class ZXLib::Gfx::Sprite8
Sprite drawing routines.
See also ZXLib::Gfx::Sprite8::Macros.
By default all drawing method routines are produced. To select only required routines define a ZXLib::Gfx::Sprite8::DRAW_METHODS constant before requiring this file.
module ZXLib module Gfx class Sprite8 DRAW_METHODS = [:xor] end end end require 'zxlib/gfx/sprite8'
Constants
- CALCULATE_SCREEN_ADDRESS
Configures the method in which
draw_sprite8calculates the screen address from pixel coordinates.The routine is 60 bytes in size and can be set up in one of the following ways:
:inline-
The calculation is inline which is faster and backwards compatible but the calculation routine can't be re-used by
Macros.gfx_sprite8_drawmacro.
:subroutine-
The calculation is set up as a subroutine, which can be reached via
draw_sprite8.calc_scr_addrlabel. See alsoMacros.gfx_sprite8_calculate_screen_address.
:external-
The calculation routine is NOT created. In this instance the only way to call
draw_sprite8is via theMacros.gfx_sprite8_drawmacro.
- CHECK_HEIGHT_SANITY
Controls if
draw_sprite8should check if the sprite pixel height is larger than “top lines to skip” parameter.- DRAW_METHODS
Array of supported drawing methods:
:xor,:or,:set,:mask_or- DRAW_METHOD_MASK_OR
- DRAW_METHOD_OR
- DRAW_METHOD_SET
- DRAW_METHOD_XOR
- SCREEN_ADDRESS
A default screen address used by the routines. You may change this value by overriding label
sprite8_screen_addresswhen importingSprite8code.
Public Instance Methods
Draws a sprite using one of the selected drawing methods with an arbitrary pixel height and width.
Pixel data for sprites must be laid column-wise:
1st 8-pixel column bytes 2nd 8-pixel column bytes ...
Example:
A sprite 16x2 pixels:
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
░░░░████████░░░░██░░░░░░░░░░░░██ 0
░░██░░░░░░░░██░░████████████████ 1
db 0b00111100, # 1st column
0b01000010,
0b10000001, # 2nd column
0b11111111
In an AND+OR (a.k.a. MASK_OR) mode bytes representing shape of a sprite must be intertwined with sprite's mask bytes:
1st bitmap byte 1st mask byte 2nd bitmap byte 2nd mask byte ...
This routine is optimised for vertical sprites with pixel height > width and square ones with width <= 24 pixels.
de-
An address of sprite data to be drawn.
h-
A screen vertical (y) coordinate of a sprite's top-leftmost pixel: [0, 191].
l-
A screen horizontal (x) coordinate of a sprite's top-leftmost pixel: [0, 255].
b-
How many pixel lines to skip from the sprite's top.
c-
A width of a sprite in bytes (columns) ((pixel width + 7) / 8): [1, 32].
a'-
A height of a sprite in pixel lines: [1, 192].
f'-
Flags specifying a drawing method (see below).
To specify a negative vertical coordinate (y < 0) set h (or l see below) to 0 and b to an absolute value of y.
To specify a negative horizontal coordinate (x < 0):
-
deshould point to the remaining visible sprite columns, -
cshould contain the number of visible sprite columns, -
if x modulo 8 is between -1 and -7 then
hshould contain x modulo 8 as a twos complement negative number andlshould contain a vertical coordinate (y) instead.
Drawing methods:
mode: OR SET XOR AND+OR
CF: 0 1 0 1
ZF: 0 0 1 1
how to: ora 1 scf cp a cp a
sbc a scf
- Uses
-
af,af',bc,de,hl,bc',de',hl',ix, stack: max 6 bytes, in AND+OR mode alsoiy.
# File lib/zxlib/gfx/sprite8.rb, line 364 ns :draw_sprite8 do unless CALCULATE_SCREEN_ADDRESS == :external push bc # save width and skip case CALCULATE_SCREEN_ADDRESS when :subroutine call calc_scr_addr else gfx_sprite8_calculate_screen_address(scraddr:sprite8_screen_address) end skip_addr push hl # HL: screen addr # C: shift 0..14 end addr_on_stack ld hl, maskshift select((maskshift + 14) & 0xFF){|m| m < 14 }.then do |_| ld b, 0 add hl, bc # HL: -> (maskshift + shift) end.else do ld a, c add l ld l, a # HL: -> (maskshift + shift) end ld a, [hl] # A: rotate mask exx ld e, a # E: rotate mask pop hl # HL: screen addr exx # E': rotate mask, H'L': screen addr ex af, af # A: height + CZ ld b, a # B: height ld a, c # A: shift 0..14 unless DRAW_METHOD_XOR or DRAW_METHOD_OR or DRAW_METHOD_SET or DRAW_METHOD_MASK_OR raise Syntax, "there must be at least one draw method selected" end if DRAW_METHOD_XOR or DRAW_METHOD_OR if DRAW_METHOD_SET or DRAW_METHOD_MASK_OR jr C, aocskip end if DRAW_METHOD_XOR and DRAW_METHOD_OR jr NZ, orskip end if DRAW_METHOD_XOR add a jr Z, fastxor ld hl, sprxor.start push hl # jump addr ld hl, jumpxor - 2 jp skipall fastxor ld hl, sprxor.fstcopy jp skpfast end if DRAW_METHOD_OR orskip add a jr Z, fastor ld hl, spror.start push hl # jump addr ld hl, jumpor - 2 jp skipall fastor ld hl, spror.fstcopy jp skpfast end end if DRAW_METHOD_SET and DRAW_METHOD_MASK_OR aocskip jr Z, andskip elsif DRAW_METHOD_SET or DRAW_METHOD_MASK_OR aocskip label end if DRAW_METHOD_SET add a jr Z, fastclr ld hl, spclror.start push hl # jump addr ld hl, jumpclror - 2 jp skipall fastclr ld hl, spclror.fstcopy jp skpfast end if DRAW_METHOD_MASK_OR andskip ld hl, spandor.start add a jr Z, fastaor push hl # jump addr ld hl, jumpandor - 4 add a adda_to h, l ld a, [hl] ld iyl, a inc hl ld a, [hl] ld iyh, a inc hl jp skipal2 fastaor ld hl, spandor.fstcopy jp skpfast end if DRAW_METHOD_XOR or DRAW_METHOD_OR or DRAW_METHOD_SET skipall adda_to h, l end skipal2 ld a, [hl] ld ixl, a inc hl ld a, [hl] ld ixh, a pop hl # jump addr skpfast ld a, b # height pop bc # skip + width sub b # height - skip top lines if CHECK_HEIGHT_SANITY ret C # return if skip top > height ret Z # return if skip top == height end jp (hl) if CALCULATE_SCREEN_ADDRESS == :subroutine calc_scr_addr gfx_sprite8_calculate_screen_address(scraddr:sprite8_screen_address, subroutine:true) end end