module ZXLib::Gfx::Sprite8::Macros
ZXLib::Gfx::Sprite8
Macros
.¶ ↑
Sprite8::Macros
require:
macro_import MathInt macro_import Gfx
Public Instance Methods
Creates a routine that calculates coordinates and prepares registers for Sprite8.draw_sprite8
.
hl
-
An address of sprite data.
a
-
A height of a sprite in pixel lines: [1, 192].
a'
-
A width of a sprite in bytes ((pixel width + 7) / 8): [1, 32].
bc
-
A horizontal (x) coordinate of a sprite's top-leftmost pixel as a 16-bit twos complement signed integer: [-32768, 32767] where the screen area is between: [0, 255].
de
-
A vertical (y) coordinate of a sprite's top-leftmost pixel as a 16-bit twos complement signed integer: [-32768..32767] where the screen area is between: [0, 191].
f
-
Flags specifying a drawing method (see below).
Options:
outofscreen
-
What to do if the whole sprite is out of the screen area - if no
block
is given then provide a branchinglabel
, otherwiseret
is being executed.
block
-
Should create code to execute when the whole sprite is out of the screen area. The
eoc
label provided to theblock
points after the calculating routine. The code must not fall through!
Any other option is being passed over to the block
namespace.
Drawing methods:
mode: OR SET XOR AND+OR CF: 0 1 0 1 ZF: 0 0 1 1 assuming accumulator contains the non-zero number of sprite lines how to: ora a ora a cp a cp a scf scf
See Sprite8.draw_sprite8
for the description of output registers.
- NOTE
-
The
outofscreen
is invoked only when it would be impossible to formulate valid arguments forSprite8.draw_sprite8
, which is exactly when(x > 255) or (x + pixel width <= 0) or (y > 191) or (y < -255)
.
Uses: af
, af'
, bc
, de
, hl
, stack: max 4 bytes.
# File lib/zxlib/gfx/sprite8.rb, line 176 def gfx_sprite8_calculate_coords(outofscreen: :ret, **nsopts, &block) isolate do |eoc| ex af, af # store CF and sprite height push af # sprite width ld a, d ora a jp Z, vnext1 # 0 <= de < 256 inc a # d == 0xff jr NZ, quit1 # de < -256 # xor a # a is already 0 sub e jr Z, quit1 # de == -256 ld d, a # skip ld e, 0 # y = 0 jp hnext1 quit1 pop af if block_given? ns(:quitoos, **nsopts) do yield eoc end elsif label?(outofscreen) quitoos jp outofscreen else ret end vnext1 ld a, e # 0 <= de < 192 cp 192 jr NC, quit1 # de >= 192 hnext1 ld a, b ora a # 0<= bc < 256 jp Z, hnext2 # bc on screen inc a jr NZ, quit1 # bc < -256 xor a sub c # x = -x jr Z, quit1 # x == -256 anda 0xf8 jr Z, fskip # -8 < x < 0 rrca rrca rrca ld b, a # -x / 8 pop af # sprite width sub b # width -= -x / 8 if block_given? or label?(outofscreen) jr C, quitoos # width < -x / 8 jr Z, quitoos # width == -x / 8 else ret C # width < -x / 8 ret Z # width == -x / 8 end ex af, af # new width push af # height + CZ push de ld d, 0 ld e, a # height jr NC, mulh.muls1 jr NZ, mulh.muls1 # height*2 (andor) C=1 Z=1 mulh mul8(d, e, b, tt:de, clrhl:false, double:true) # sprite address+= height * (-x / 8) pop de pop af ex af, af # height + CZ push af # new width fskip ld a, c ora 0xf8 ld c, e ld e, a hnext2 ex de, hl # sprite -> de ld b, h # skip first ld h, l # h = y & 0xff ld l, c # l = x & 0xff pop af ld c, a # sprite width end end
Creates a routine that calculates the screen address for Sprite8.draw_sprite8
.
The h
and l
registers should contain the pixel coordinates as described in Sprite8.draw_sprite8
.
As a result of executing the routine the hl
registers will hold the calculated screen address and the c
register will hold the special bit right shift number.
If the horizontal pixel coordinate (x) is positive the bit shift will be between 0 and 7. If the x coordinate is negative and x is between -7 and -1 the bit shift will be between 8 and 14.
Options:
scraddr
-
A screen memory address which must be a multiple of 0x2000 as an integer or a label.
subroutine
-
Whether to create a subroutine.
# File lib/zxlib/gfx/sprite8.rb, line 82 def gfx_sprite8_calculate_screen_address(scraddr:SCREEN_ADDRESS, subroutine:false) isolate do |eoc| ld a, h cp 192 jp C, hvertical anda 7 # -7..-1 -> 1..7 jr Z, noadjust # sanity check add 7 # 1..7 -> 8..14 noadjust ld c, a # C: negshift (0, 8..14) ytoscr l, ah:h, al:l, t:b, scraddr:scraddr if subroutine ret else jr eoc end # HL<: yx, HL>: screen, C>: shift (0..7), B: temp hvertical xytoscr h, l, ah:h, al:l, s:c, t:b, scraddr:scraddr ret if subroutine end end
Creates a subroutine that calculates the screen address before jumping to Sprite8.draw_sprite8
.
This subroutine should be used if you want to access the calculated screen address just before executing draw_sprite8
.
draw_sprite8
-
A label addressing the
Sprite8.draw_sprite8
subroutine. block
-
A block that creates a code to execute when the screen address has been calculated. The address is available in
hl
registers. Additionally thec
register contains the special bit shift number. Seegfx_sprite8_calculate_screen_address
for details. The code must preserve the content ofc
,de
andaf'
registers.
See Sprite8.draw_sprite8
for the description of input registers and usage.
Options:
scraddr
-
A screen memory address which must be a multiple of 0x2000 as an integer or a label.
calculate
-
If this option is set to
:subroutine
then the screen address calculation routine is being called (atdraw_sprite8.calc_scr_addr
) instead of inlining it. In this instance the Sprite8::CALCULATE_SCREEN_ADDRESS constant must be set to:subroutine
before requiring thesprite8
module.
Any other option is being passed over to the block
namespace.
# File lib/zxlib/gfx/sprite8.rb, line 123 def gfx_sprite8_draw(draw_sprite8=self.draw_sprite8, scraddr:SCREEN_ADDRESS, calculate:CALCULATE_SCREEN_ADDRESS, **nsopts, &block) isolate do |eoc| push bc # save width and skip if calculate == :subroutine call draw_sprite8.calc_scr_addr else gfx_sprite8_calculate_screen_address(scraddr:scraddr) end push hl # HL: screen addr, C: negshift (0..14) if block_given? ns(**nsopts) do yield eoc end end jp draw_sprite8.addr_on_stack end end
Creates a routine that flips sprite pixel data horizontally (mirrors sprites).
hl
-
An address immediately following the source sprite data (sprite data address + sprite data size).
de
-
A target address where the mirrored sprite data should be placed. The target memory area must not overlap with the source.
c
-
A width of a sprite in bytes ((pixel width + 7) / 8) (0 is 256).
b
-
A height of a sprite in pixel lines (0 is 256).
Options:
subroutine
-
Whether to create a subroutine.
After the routine finishes its operation:
de
-
Will hold a memory address immediately following the flipped sprite data (flipped sprite data address + sprite data size).
hl
-
Will hold a memory address of the source sprite data.
b
-
Will hold a provided sprite height in pixel lines.
c
-
Will be 0.
- NOTE
-
Sprite data must be laid out column-wise as expected by
Sprite8.draw_sprite8
. If data include the sprite mask the provided height should be twice the sprite height. In this instance the maximum sprite height to be mirrored is 128 pixel lines.
Uses: af
, bc
, de
, hl
, stack: 4 bytes.
# File lib/zxlib/gfx/sprite8.rb, line 278 def gfx_sprite8_flip_horizontally(subroutine:false) isolate do column_loop push bc sub_from b, h, l push hl scf row_loop ld c, [hl] inc hl rl c bit_swap_loop rra sla c jr NZ, bit_swap_loop ld [de], a inc de djnz row_loop pop hl pop bc dec c jr NZ, column_loop ret if subroutine end end