p_DrawOr:
.db __DrawOrEnd-1-$
;; hl=sprite, (sp)=ret, (sp+2)=y, (sp+4)=x
;; Rearrange inputs.
push hl
pop ix
ld hl,plotSScreen
x_DrawOrEntry:
pop af
pop de
pop bc
push af
;; c=x, e=y, hl=buff, ix=sprite, (sp)=ret
;; Check if the top of the sprite is offscreen.
ld b,7
ld a,63
sub e
jr nc,__DrawOrNoClipTop
;; a=63-y, b=7, c=x, e=y, hl=buff, ix=sprite
;; If the top of the sprite is offscreen, abort if the bottom is also offscreen.
ld a,e
add a,b
ret nc
;; a=y+7, b=7, c=x, e=y, hl=buff, ix=sprite
;; The top of the sprite is offscreen (negative) but the bottom is not
;; (nonnegative), so clip y to 0 and advance the sprite pointer past the
;; clipped off data.
__DrawOrClipTop:
; xor b
; ld e,a
; add ix,de
; ld e,d
; xor b
inc ix
inc e
jr nz,__DrawOrClipTop
;; a=(y<0 ? y+7 : 63-y), b=7, c=x, e=clipped y, hl=buff, ix=sprite start
;; Calculate the clipped height.
__DrawOrNoClipTop:
cp b
jr nc,__DrawOrNoClipBot
ld b,a
__DrawOrNoClipBot:
inc b
;; a=(y<0 ? y+7 : 63-y), b=clipped height, c=x, e=clipped y, hl=buff,
;; ix=sprite start
;; Abort if the sprite is fully offscreen horizontally.
ld a,c
add a,7
cp 96+7
ret nc
;; a=x+7, b=clipped height, c=x, e=clipped y, hl=buff, ix=sprite start
;; Calculate the pointer to which to draw the top-right of the (clipped) sprite:
;; buff+((clipped y)*12)+((x+7)/8).
ld d,0
sla e
sla e
add hl,de
rra
add hl,de
rra
add hl,de
rra
ld e,a
add hl,de
;; a=(x+7)/8, b=clipped height, c=x, de=clipped y*4, hl=draw start,
;; ix=sprite start
;; Use the aligned drawing code if possible.
ld a,c
and 7
jr z,__DrawOrAligned
;; a=x&7, b=clipped height, c=x, de=clipped y*4, hl=draw start, ix=sprite start
;; Calculate masks for whether or not to draw the left and right bytes of the
;; unaligned sprite.
ld e,c
ld c,a
ld a,e
cp -7
sbc a,a
ld d,a
and e
cp 96-7
sbc a,a
ld e,a
;; b=height remaining, c=x&7, d=(x<0 ? $FF : 0), e=(x>88 ? $FF : 0),
;; hl=draw current, ix=sprite current
;; Read a sprite byte and rotate it into the correct alignment.
__DrawOrLoop:
push bc
ld b,c
ld c,(ix)
xor a
__DrawOrShift:
srl c
rra
djnz __DrawOrShift
;; b=0, ca=(sprite byte<<8)>>(x&7), d=(x<0 ? $FF : 0), e=(x>88 ? $FF : 0),
;; hl=draw current, ix=sprite current, (sp)=(height remaining<<8)+(x&7)
;; Draw the rotated sprite byte, clipping horizontally as necessary by writing
;; back unchanged data.
and e
or (hl)
ld (hl),a
dec hl
ld a,c
and d
or (hl)
ld (hl),a
;; b=0, c=sprite byte>>(x&7), d=(x<0 ? $FF : 0), e=(x>88 ? $FF : 0),
;; hl=draw current-1, ix=sprite current, (sp)=(height remaining<<8)+(x&7)
;; Advance the draw and sprite pointers.
ld c,13
add hl,bc
inc ix
;; bc=13, d=(x<0 ? $FF : 0), e=(x>88 ? $FF : 0), hl=draw next,
;; ix=sprite next, (sp)=(height remaining<<8)+(x&7)
;; Decrement the height remaining and continue drawing if it's nonzero.
pop bc
djnz __DrawOrLoop
ret
;; ALIGNED SPRITE DRAWING
;; a=0, b=clipped height, c=x, de=clipped y*4, hl=draw start, ix=sprite start
;; Prepare.
__DrawOrAligned:
ld e,12
;; a=0, b=height remaining, c=x, de=12, hl=draw current, ix=sprite current
;; Read and draw a sprite byte, advance the sprite and draw pointers, and
;; decrement the height remaining and continue drawing if it's nonzero.
__DrawOrAlignedLoop:
ld a,(ix)
or (hl)
ld (hl),a
inc ix
add hl,de
djnz __DrawOrAlignedLoop
ret
__DrawOrEnd: