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_sprite8
calculates 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_draw
macro.
:subroutine
-
The calculation is set up as a subroutine, which can be reached via
draw_sprite8.calc_scr_addr
label. See alsoMacros.gfx_sprite8_calculate_screen_address
.
:external
-
The calculation routine is NOT created. In this instance the only way to call
draw_sprite8
is via theMacros.gfx_sprite8_draw
macro.
- CHECK_HEIGHT_SANITY
Controls if
draw_sprite8
should 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_address
when importingSprite8
code.
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):
-
de
should point to the remaining visible sprite columns, -
c
should contain the number of visible sprite columns, -
if x modulo 8 is between -1 and -7 then
h
should contain x modulo 8 as a twos complement negative number andl
should 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