Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
6295 lines (6081 sloc) 128 KB
;-------------------------------------------------------------------------------
include '../include/library.inc'
;-------------------------------------------------------------------------------
library 'GRAPHX', 10
;-------------------------------------------------------------------------------
; no dependencies
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; v1 functions
;-------------------------------------------------------------------------------
export gfx_Begin
export gfx_End
export gfx_SetColor
export gfx_SetDefaultPalette
export gfx_SetPalette
export gfx_FillScreen
export gfx_SetPixel
export gfx_GetPixel
export gfx_GetDraw
export gfx_SetDraw
export gfx_SwapDraw
export gfx_Blit
export gfx_BlitLines
export gfx_BlitRectangle
export gfx_PrintChar
export gfx_PrintInt
export gfx_PrintUInt
export gfx_PrintString
export gfx_PrintStringXY
export gfx_SetTextXY
export gfx_SetTextBGColor
export gfx_SetTextFGColor
export gfx_SetTextTransparentColor
export gfx_SetFontData
export gfx_SetFontSpacing
export gfx_SetMonospaceFont
export gfx_GetStringWidth
export gfx_GetCharWidth
export gfx_GetTextX
export gfx_GetTextY
export gfx_Line
export gfx_HorizLine
export gfx_VertLine
export gfx_Circle
export gfx_FillCircle
export gfx_Rectangle
export gfx_FillRectangle
export gfx_Line_NoClip
export gfx_HorizLine_NoClip
export gfx_VertLine_NoClip
export gfx_FillCircle_NoClip
export gfx_Rectangle_NoClip
export gfx_FillRectangle_NoClip
export gfx_SetClipRegion
export gfx_GetClipRegion
export gfx_ShiftDown
export gfx_ShiftUp
export gfx_ShiftLeft
export gfx_ShiftRight
export gfx_Tilemap
export gfx_Tilemap_NoClip
export gfx_TransparentTilemap
export gfx_TransparentTilemap_NoClip
export gfx_TilePtr
export gfx_TilePtrMapped
export gfx_Reserved
export gfx_AllocSprite
export gfx_Sprite
export gfx_TransparentSprite
export gfx_Sprite_NoClip
export gfx_TransparentSprite_NoClip
export gfx_GetSprite
export gfx_ScaledSprite_NoClip
export gfx_ScaledTransparentSprite_NoClip
export gfx_FlipSpriteY
export gfx_FlipSpriteX
export gfx_RotateSpriteC
export gfx_RotateSpriteCC
export gfx_RotateSpriteHalf
export gfx_Polygon
export gfx_Polygon_NoClip
export gfx_FillTriangle
export gfx_FillTriangle_NoClip
;-------------------------------------------------------------------------------
; v2 functions
;-------------------------------------------------------------------------------
export gfx_Deprecated
export gfx_SetTextScale
;-------------------------------------------------------------------------------
; v3 functions
;-------------------------------------------------------------------------------
export gfx_SetTransparentColor
export gfx_ZeroScreen
export gfx_SetTextConfig
export gfx_GetSpriteChar
;-------------------------------------------------------------------------------
; v4 functions
;-------------------------------------------------------------------------------
export gfx_Lighten
export gfx_Darken
;-------------------------------------------------------------------------------
; v5 functions
;-------------------------------------------------------------------------------
export gfx_SetFontHeight
export gfx_ScaleSprite
export gfx_FloodFill
;-------------------------------------------------------------------------------
; v6 functions
;-------------------------------------------------------------------------------
export gfx_RLETSprite
export gfx_RLETSprite_NoClip
export gfx_ConvertFromRLETSprite
export gfx_ConvertToRLETSprite
export gfx_ConvertToNewRLETSprite
;-------------------------------------------------------------------------------
; v7 functions
;-------------------------------------------------------------------------------
export gfx_RotateScaleSprite
export gfx_RotatedScaledTransparentSprite_NoClip
export gfx_RotatedScaledSprite_NoClip
;-------------------------------------------------------------------------------
; v8 functions
;-------------------------------------------------------------------------------
export gfx_SetCharData
;-------------------------------------------------------------------------------
; v9 functions
;-------------------------------------------------------------------------------
export gfx_Wait
;-------------------------------------------------------------------------------
LcdSize := LcdWidth*LcdHeight
; minimum stack size to provide for interrupts if moving the stack
InterruptStackSize := 4000
CurrentBuffer := mpLcdLpbase
TRASPARENT_COLOR := 0
TEXT_FG_COLOR := 0
TEXT_BG_COLOR := 255
TEXT_TP_COLOR := 255
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
macro mIsHLLessThanDE?
or a,a
sbc hl,de
add hl,hl
jp po,$+5
ccf
end macro
macro mIsHLLessThanBC?
or a,a
sbc hl,bc
add hl,hl
jp po,$+5
ccf
end macro
macro s8 op, imm
local i
i = imm
assert i >= -128 & i < 128
op, i
end macro
;-------------------------------------------------------------------------------
wait_quick.usages_counter = 0
macro wait_quick?
call _WaitQuick
wait_quick.usages_counter = wait_quick.usages_counter + 1
end macro
postpone
wait_quick.usages := wait_quick.usages_counter
end postpone
;-------------------------------------------------------------------------------
macro setSmcBytes name*
local addr, data
postpone
virtual at addr
irpv each, name
if % = 1
db %%
end if
assert each >= addr + 1 + 2*%%
dw each - $ - 2
end irpv
load data: $-$$ from $$
end virtual
end postpone
call _SetSmcBytes
addr db data
end macro
macro setSmcBytesFast name*
local temp, list
postpone
temp equ each
irpv each, name
temp equ temp, each
end irpv
list equ temp
end postpone
pop de ; de = return vetor
ex (sp),hl ; l = byte
ld a,l ; a = byte
match expand, list
iterate expand
if % = 1
ld hl,each
ld c,(hl)
ld (hl),a
else
ld (each),a
end if
end iterate
end match
ld a,c ; a = old byte
ex de,hl ; hl = return vector
jp (hl)
end macro
macro smcByte name*, addr: $-1
local link
link := addr
name equ link
end macro
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
gfx_Begin:
; Sets up the graphics canvas
; Arguments:
; arg0: bpp mode to start in
; Returns:
; None
call _boot_ClearVRAM ; clear the screen
lcdGraphxMode := lcdWatermark+lcdIntFront+lcdPwr+lcdBgr+lcdBpp8
ld de,lcdGraphxMode
ld hl,CurrentBuffer
SetGfx:
ld bc,VRAM
ld (hl),bc ; set the current draw to the screen
assert CurrentBuffer and -$100 = mpLcdRange
ld l,lcdCtrl
ld (hl),de ; set lots of control parameters
ld l,lcdTiming0+1
ld de,_LcdTiming
assert VRAM and $FF = 0
ld b,8+1 ; +1 because c = 0, so first ldi will
; decrement b
.ExchangeTimingLoop: ; exchange stored and active timing
ld a,(de)
ldi
dec hl
ld (hl),a
inc hl
djnz .ExchangeTimingLoop
; jp gfx_SetDefaultPalette ; setup the default palette
assert $ = gfx_SetDefaultPalette
;-------------------------------------------------------------------------------
gfx_SetDefaultPalette:
; Sets up the default palette where H=L
; Arguments:
; None
; Returns:
; None
ld de,mpLcdPalette ; address of mmio palette
ld b,e ; b = 0
.loop:
ld a,b
rrca
xor a,b
and a,224
xor a,b
ld (de),a
inc de
ld a,b
rla
rla
rla
ld a,b
rra
ld (de),a
inc de
inc b
jr nz,.loop ; loop for 256 times to fill palette
ret
;-------------------------------------------------------------------------------
gfx_End:
; Closes the graphics library and sets up for the TI-OS
; Arguments:
; None
; Returns:
; None
call _boot_ClearVRAM ; clear the screen
ld de,lcdNormalMode
ld hl,mpLcdBase
jr SetGfx ; restore the screen mode
;-------------------------------------------------------------------------------
gfx_AllocSprite:
; Allocates space for a new sprite
; Arguments:
; arg0 : width
; arg1 : height
; arg2 : pointer to malloc routine
; Returns:
; Pointer to allocated sprite, first byte width, second height
ld bc,3
push bc
pop hl
add hl,sp
ld e,(hl) ; e = width
add hl,bc
ld d,(hl) ; d = height
add hl,bc
ld hl,(hl) ; hl = malloc
push de
mlt de ; de = width * height
inc de ; +2 to store width and height
inc de ; de = width * height + 2
push de
call _indcallHL ; hl = malloc(width * height + 2)
pop de ; de = width * height + 2
add hl,de ; this should never carry
sbc hl,de ; check if malloc failed (hl == 0)
pop de ; e = width, d = height
ret z ; abort if malloc failed
ld (hl),de ; store width and height
ret
;-------------------------------------------------------------------------------
gfx_SetClipRegion:
; Sets the clipping region for clipped routines
; Arguments:
; arg0 : Xmin
; arg1 : Ymin
; arg2 : Xmax
; arg3 : Ymax
; Returns:
; None
ld hl,_ClipRegion_Full ; clip against the actual LCD screen
call .copy
ld iy,0
add iy,sp
call _ClipRegion ; iy points to the start of the arguments
ret c
lea hl,iy+3
.copy:
ld de,_XMin
ld bc,4*3
ldir
ret
;-------------------------------------------------------------------------------
gfx_Lighten:
; Lightens a 16 bit 1555 color (0 = white, 255 = same color)
; Arguments:
; arg0 : 16 bit color
; arg1 : 8 bit change amount
; Returns:
; 16 bit color value
pop de ; de = return vector
pop bc ; bc = color
ex (sp),hl ; l = amt
push bc
push de
; Strategy: lighten(color, amt) = ~darken(~color, amt)
; Darken the inverted color
ld a,c
cpl
ld c,a
ld a,b
cpl
ld b,a ; bc = ~color
call _Darken ; hl = darken(~color, amt)
ld a,l ; Invert the darken result for the lighten result
cpl
ld l,a
ld a,h
cpl
ld h,a ; hl = ~darken(~color, amt) = lighten(color, amt)
ret
;-------------------------------------------------------------------------------
gfx_Darken:
; Darkens a 16 bit 1555 color (0 = black, 255 = same color)
; Arguments:
; arg0 : 16 bit color
; arg1 : 8 bit change amount
; Returns:
; 16 bit color value
pop de ; de = return vector
pop bc ; bc = color
ex (sp),hl ; l = amt
push bc
push de ; Comments assume 1555 RGB color
_Darken:
push bc ; Calculate the output blue value
ld a,c ; a = color & $FF
ld c,l ; c = amt
and a,31
ld h,a ; h = blue
mlt hl ; hl = blue * amt
ld de,128 ; de = 128
add hl,de ; hl = blue * amt + 128
ld l,h
ld h,d ; hl = (blue * amt + 128) / 256 = blue_out
ex (sp),hl ; hl = color, tmp1 = blue_out
; Isolate the input red value
ld a,h ; a = color >> 8
rra ; a = color >> 9
and a,62
ld b,a ; b = red << 1
; Calculate the output green value
add.s hl,hl
rla ; a & 1 = green & 1
add hl,hl
add hl,hl ; hl = color << 3
rra
ld a,h
rla
and a,63
ld h,a ; h = green
ld l,c ; l = amt
mlt hl ; hl = green * amt
add hl,de ; hl = green * amt + 128
ld l,h ; l = (green * amt + 128) / 256 = green_out
; Calculate the output red value
mlt bc ; bc = red * amt << 1
inc b ; b = (red * amt + 128 << 1) / 256
srl b ; b = (red * amt + 128) / 256 = red_out
; Position the output red and green bits
add hl,hl
add hl,hl ; l = green_out << 2
ld h,b ; h = red_out
add hl,hl
add hl,hl ; hl = (red_out << 10) | (green_out << 4)
bit 4,l
jr z,.out
set 7,h
res 4,l ; hl = (green_out & 1 << 15) | (red_out << 10) | (green_out >> 1 << 5)
.out:
; Add the output blue value (no positioning necessary) for the final output color
pop bc ; bc = blue_out
add hl,bc ; hl = color_out
ret
;-------------------------------------------------------------------------------
gfx_SetColor:
; Sets the global color index for all routines
; Arguments:
; arg0 : Global color index
; Returns:
; Previous global color index
setSmcBytesFast _Color
;-------------------------------------------------------------------------------
gfx_SetTransparentColor:
; Sets the global transparent color index for all routines
; Arguments:
; arg0 : Transparent color index
; Returns:
; Previous transparent color index
setSmcBytes _TransparentColor
;-------------------------------------------------------------------------------
gfx_FillScreen:
; Fills the screen with the specified color index
; Arguments:
; arg0 : Color index
; Returns:
; None
FillScreen_PushesPerIter := 115 ; see fillscreen.xlsx for derivation
FillScreen_NumIters := (LcdSize-InterruptStackSize)/(FillScreen_PushesPerIter*3)
FillScreen_BytesToPush := FillScreen_PushesPerIter*3*FillScreen_NumIters
FillScreen_BytesToLddr := LcdSize-FillScreen_BytesToPush
ld iy,0
add iy,sp ; iy = original sp
ld hl,FillScreen_FastCode_SrcEnd-1
ld de,FillScreen_FastCode_DestEnd-1
ld bc,FillScreen_FastCode_SrcSize
lddr ; copy fast code after push run
; de = pointer second to last push
; bc = 0
push de
pop hl
inc hl ; hl = pointer to last push (already copied)
ld c,FillScreen_PushesPerIter-1
lddr ; fill push run
ld a,$E1
ld (de),a ; write initial pop hl
ld hl,(CurrentBuffer)
ld de,LcdSize
add hl,de ; hl = end (exclusive) of buffer
ld de,(iy+1) ; deu = color
ld d,(iy+3) ; d = color
ld e,d ; e = color
ld b,FillScreen_NumIters ; b = number of fast code iterations
call gfx_Wait
ld sp,hl ; sp = end (exclusive) of buffer
call _FillScreen_FastCode_Dest ; do fast fill
sbc hl,hl
add hl,sp ; hl = pointer to last byte fast-filled
ld sp,iy ; sp = original sp
push hl
pop de
dec de ; de = pointer to first byte to slow-fill
ld bc,FillScreen_BytesToLddr
lddr ; finish with slow fill
ret
_FillScreen_FastCode_Src:
org mpLcdCrsrImage
_FillScreen_FastCode_Dest:
org $ + 1
.loop:
push de
org $ + FillScreen_PushesPerIter - 1
djnz .loop
jp (hl)
FillScreen_FastCode_DestEnd := $
FillScreen_FastCode_DestSize := FillScreen_FastCode_DestEnd-_FillScreen_FastCode_Dest
FillScreen_FastCode_SrcSize := FillScreen_FastCode_DestSize-(FillScreen_PushesPerIter-1+1)
org _FillScreen_FastCode_Src+FillScreen_FastCode_SrcSize
FillScreen_FastCode_SrcEnd := $
;-------------------------------------------------------------------------------
gfx_ZeroScreen:
; Fills the screen with color index 0
; Arguments:
; None
; Returns:
; None
ld l,0
push hl
call gfx_FillScreen
pop hl
ret
;-------------------------------------------------------------------------------
gfx_SetPalette:
; Sets the palette colors
; Arguments:
; arg0 : Pointer to palette
; arg1 : Size of palette in bytes
; arg2 : Offset at which to start inserting the palette
; Returns:
; None
pop iy ; iy = return vector
pop de ; de = src
pop bc ; bc = size
ex (sp),hl ; l = offset
push bc
push de
ld a,l
assert mpLcdPalette and 1 = 0
ld hl,mpLcdPalette shr 1
ld l,a ; hl = (palette >> 1) + offset
add hl,hl ; hl = &palette[offset] = dest
ex de,hl ; de = dest, hl = src
ldir
jp (iy)
;-------------------------------------------------------------------------------
gfx_GetPixel:
; Gets the color index of a pixel
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; Returns:
; Color index of X,Y coordinate
ld hl,3
add hl,sp ; hl = &x
inc.s bc
ld c,(hl)
inc hl
ld b,(hl) ; bc = (uint16_t)x
inc hl
inc hl ; hl = &y
ld e,(hl) ; e = y
_GetPixel:
ld d,LcdWidth/2
mlt de ; de = y * (lcdWidth / 2)
ld hl,(CurrentBuffer) ; hl = buffer
add hl,bc
add hl,de
add hl,de ; hl = buffer + y * (lcdWidth / 2)*2 + (uint16_t)x
; = buffer + y * lcdWidth + (uint16_t)x
; = &buffer[y][x]
; No clipping is necessary, because if the pixel is offscreen, the result is
; undefined. All that is necessary is to ensure that there are no side effects
; of reading outside of the buffer. In this case, the largest possible offset
; into the buffer is 255 * lcdWidth + 65535 = 147135 bytes. Even in the case
; that the current buffer is the second half of VRAM, the largest that this
; pointer can be is $D52C00 + 147135 = $D76ABF. This goes beyond the end of
; mapped RAM, but only into unmapped memory with no read side effects.
ld a,(hl) ; a = buffer[y][x]
ret
;-------------------------------------------------------------------------------
gfx_SetPixel:
; Sets the color pixel to the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; Returns:
; None
ld hl,3
add hl,sp
ld bc,(hl) ; bc = x coordinate
ld de,3
add hl,de ; move to next argument
ld e,(hl) ; e = y coordinate
_SetPixel:
wait_quick
_SetPixel_NoWait:
ld hl,-LcdWidth
add hl,bc
ret c ; return if out of bounds
ld hl,-LcdHeight
add hl,de
ret c ; return if out of bounds
ld hl,(CurrentBuffer)
add hl,bc
ld d,LcdWidth/2
mlt de
add hl,de
add hl,de
ld (hl),0 ; get the actual pixel
smcByte _Color
ret
;-------------------------------------------------------------------------------
gfx_FillRectangle:
; Draws a clipped rectangle with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Width
; arg3 : Height
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(iy+9) ; hl = width
ld de,(iy+3) ; de = x coordinate
add hl,de
ld (iy+9),hl
ld hl,(iy+12) ; hl = height
ld de,(iy+6) ; de = y coordinate
add hl,de
ld (iy+12),hl
call _ClipRegion
ret c ; return if offscreen or degenerate
ld de,(iy+3)
ld hl,(iy+9)
sbc hl,de
push hl
ld de,(iy+6)
ld hl,(iy+12)
sbc hl,de
pop bc ; bc = new width
ld a,l ; a = new height
ld hl,(iy+3) ; hl = new x, de = new y
jr _FillRectangle_NoClip
;-------------------------------------------------------------------------------
gfx_FillRectangle_NoClip:
; Draws an unclipped rectangle with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Width
; arg3 : Height
; Returns:
; None
ld iy,0
add iy,sp
ld a,(iy+12) ; a = height
or a,a
ret z ; make sure height is not 0
ld bc,(iy+9) ; bc = width
sbc hl,hl
adc hl,bc
ret z ; make sure width is not 0
ld hl,(iy+3) ; hl = x coordinate
ld e,(iy+6) ; e = y coordinate
_FillRectangle_NoClip:
ld d,LcdWidth / 2
mlt de
add hl,de
add hl,de
ld de,(CurrentBuffer)
add hl,de
ex de,hl ; de -> place to begin drawing
push de
ld (.width1),bc
ld (.width2),bc
ld hl,_Color
wait_quick
ldi ; check if we only need to draw 1 pixel
pop hl
jp po,.skip
ldir
.skip:
dec a
ret z
inc b
ld c,$40 ; = slightly faster "ld bc,LcdWidth"
.loop:
add hl,bc
dec de
ex de,hl
.width1 = $ + 1
ld bc,0
lddr
dec a
ret z
ld bc,(2 * LcdWidth) + 1
add hl,bc
inc de
ex de,hl
.width2 = $ + 1
ld bc,0
ldir
ld bc,(2 * LcdWidth) - 1
dec a
jr nz,.loop
ret
;-------------------------------------------------------------------------------
gfx_Rectangle:
; Draws an clipped rectangle outline with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Width
; arg3 : Height
; Returns:
; None
push ix ; need to use ix because lines use iy
ld ix,0
add ix,sp
ld hl,(ix+6)
ld de,(ix+9)
ld bc,(ix+12)
push bc
push de
push hl
call gfx_HorizLine ; top horizontal line
ld hl,(ix+6)
ld de,(ix+9)
ld bc,(ix+15)
push bc
push de
push hl
call gfx_VertLine ; left vertical line
ld hl,(ix+6)
ld de,(ix+9)
ld bc,(ix+12)
add hl,bc ; add x and width
dec hl
ld bc,(ix+15)
push bc
push de
push hl
call gfx_VertLine ; right vertical line
ld de,(ix+6)
ld hl,(ix+9)
ld bc,(ix+15)
add hl,bc
dec hl ; add y and height
ld bc,(ix+12)
push bc
push hl
push de
call gfx_HorizLine ; bottom horizontal line
ld sp,ix
pop ix
ret
;-------------------------------------------------------------------------------
gfx_Rectangle_NoClip:
; Draws an unclipped rectangle outline with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Width
; arg3 : Height
; Returns:
; None
ld iy,0
add iy,sp
ld a,(iy+12) ; a = height
or a,a
ret z ; abort if height == 0
ld bc,(iy+9) ; bc = width
sbc hl,hl
adc hl,bc
ret z ; abort if width == 0
push bc
call _HorizLine_NoClip_NotDegen_StackXY ; draw top horizontal line
; hl = &buf[y][x+width-1]
ld b,a ; b = height
call _VertLine_NoClip_Draw ; draw right vertical line
ld b,(iy+12) ; b = height
ld e,(iy+6) ; e = y
call _VertLine_NoClip_NotDegen_StackX ; draw left vertical line
; hl = &buf[y+height][x]
; de = LcdWidth
sbc hl,de ; hl = &buf[y+height-1][x]
pop bc ; bc = width
jp _HorizLine_NoClip_Draw ; draw bottom horizontal line
;-------------------------------------------------------------------------------
gfx_HorizLine:
; Draws an clipped horizontal line with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Length
; Returns:
; None
ld iy,0
add iy,sp
ld de,(_YMin)
ld hl,(iy+6)
mIsHLLessThanDE ; compare y coordinate <-> ymin
ret c
ld hl,(_YMax)
dec hl ; inclusive
ld de,(iy+6)
mIsHLLessThanDE ; compare y coordinate <-> ymax
ret c
ld hl,(iy+9)
ld de,(iy+3)
add hl,de
ld (iy+9),hl
ld hl,(_XMin)
call _Maximum
ld (iy+3),hl ; save maximum x value
ld hl,(_XMax)
ld de,(iy+9)
call _Minimum
ld (iy+9),hl ; save minimum x value
ld de,(iy+3)
mIsHLLessThanDE
ret c
ld hl,(iy+9)
sbc hl,de
push hl
pop bc ; bc = length
jr _HorizLine_NoClip_StackXY
;-------------------------------------------------------------------------------
gfx_HorizLine_NoClip:
; Draws an unclipped horizontal line with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Length
; Returns:
; None
ld iy,0
add iy,sp
ld bc,(iy+9) ; bc = length
_HorizLine_NoClip_StackXY:
sbc hl,hl
adc hl,bc
ret z ; abort if length == 0
_HorizLine_NoClip_NotDegen_StackXY:
ld e,(iy+6) ; e = y
ld hl,(iy+3) ; hl = x
_HorizLine_NoClip_NotDegen:
wait_quick
_HorizLine_NoClip_NotDegen_NoWait:
ld d,LcdWidth/2
mlt de
add hl,de
add hl,de
ld de,(CurrentBuffer)
add hl,de ; hl -> place to draw
_HorizLine_NoClip_Draw:
ld (hl),0
smcByte _Color
cpi
ret po
ex de,hl
ld hl,-1
add hl,de
ldir
ret
;-------------------------------------------------------------------------------
gfx_VertLine:
; Draws an clipped vertical line with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Length
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(_XMax)
dec hl ; inclusive
ld de,(iy+3)
mIsHLLessThanDE
ret c ; return if x > xmax
ld hl,(_XMin)
ex de,hl
mIsHLLessThanDE
ret c ; return if x < xmin
ld hl,(iy+9)
ld de,(iy+6)
add hl,de
ld (iy+9),hl
ld hl,(_YMin)
call _Maximum ; get minimum y
ld (iy+6),hl
ld hl,(_YMax)
ld de,(iy+9)
call _Minimum ; get maximum y
ld (iy+9),hl
ld de,(iy+6)
mIsHLLessThanDE
ret c ; return if not within y bounds
ld hl,(iy+9)
sbc hl,de
ld b,l
jr _VertLine_NoClip_StackX ; jump to unclipped version
;-------------------------------------------------------------------------------
gfx_VertLine_NoClip:
; Draws an unclipped vertical line with the global color index
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Length
; Returns:
; None
ld iy,0
add iy,sp
ld e,(iy+6) ; e = y
ld b,(iy+9) ; b = length
_VertLine_NoClip_StackX:
xor a,a
or a,b
ret z ; abort if length == 0
_VertLine_NoClip_NotDegen_StackX:
ld hl,(iy+3) ; hl = x
ld d,LcdWidth/2
mlt de
add hl,de
add hl,de
ld de,(CurrentBuffer)
add hl,de ; hl -> drawing location
_VertLine_NoClip_Draw:
ld de,LcdWidth
ld a,0
smcByte _Color
wait_quick
.loop:
ld (hl),a ; loop for height
add hl,de
djnz .loop
ret
;-------------------------------------------------------------------------------
gfx_SetDraw:
; Forces drawing routines to operate on the offscreen buffer
; or to operate on the visible screen
; Arguments:
; arg0: buffer or screen
; Returns:
; None
pop de
ex (sp),hl
ld a,l
or a,a
ld hl,(mpLcdBase) ; get current base
ld bc,vram
jr z,.match
sbc hl,bc
jr nz,.swap ; if not the same, swap
.set:
ld bc,vram+LcdSize
.swap:
ld (CurrentBuffer),bc
ex de,hl
jp (hl)
.match:
sbc hl,bc
jr z,.swap ; if the same, swap
jr .set
;-------------------------------------------------------------------------------
gfx_GetDraw:
; Gets the current drawing state
; Arguments:
; None
; Returns:
; Returns true if drawing on the buffer
ld a,(mpLcdBase+2) ; comparing upper byte only is sufficient
ld hl,CurrentBuffer+2
xor a,(hl) ; always 0 or 1
ret
;-------------------------------------------------------------------------------
_WaitQuick:
ex (sp),hl ; hl saved, hl = return vector
push de ; de saved
ld de,gfx_Wait
dec hl
dec hl
dec hl
ld (hl),de ; call _WaitQuick -> call _Wait
dec hl ; hl = callee
ex de,hl ; de = callee
ld hl,_WriteWaitQuickSMC
.WriteWaitsTail = $-3
ld (hl),$22 ; ld (callee),hl
inc hl
ld (hl),de
inc hl
inc hl
inc hl
ld (.WriteWaitsTail),hl
ex de,hl ; hl = callee
pop de ; de restored
ex (sp),hl ; return vector = callee, hl restored
; Fall through to gfx_Wait, but don't let it return immediately. Even if it ends
; up not waiting, it will re-write the quick wait SMC, including for the callee.
push hl
; jr gfx_Wait+1 ; emulated by dummifying next instruction:
db $2E ; ret || push hl -> ld l,*
;-------------------------------------------------------------------------------
gfx_Wait:
; Waits for the screen buffer to finish being displayed after gfx_SwapDraw
; Arguments:
; None
; Returns:
; None
ret ; will be SMC'd into push hl
push af
ld a,(mpLcdRis)
bit bLcdIntVcomp,a
jr nz,.WaitDone
push de
.WaitLoop:
.ReadLcdCurr:
ld a,(mpLcdCurr+2) ; a = *mpLcdCurr>>16
ld hl,(mpLcdCurr+1) ; hl = *mpLcdCurr>>8
sub a,h
jr nz,.ReadLcdCurr ; nz ==> lcdCurr may have updated
; mid-read; retry read
ld de,(CurrentBuffer+1)
sbc hl,de
ld de,-LcdSize shr 8
add hl,de
jr nc,.WaitLoop
pop de
.WaitDone:
ld a,$C9 ; ret
ld (gfx_Wait),a ; disable wait logic
pop af
ld hl,$0218 ; jr $+4
_WriteWaitQuickSMC:
repeat wait_quick.usages
; Each call _WaitQuick will replace the next unmodified 4-byte entry with
; ld (_WaitQuick_callee_x),hl.
pop hl
ret
nop
nop
end repeat
pop hl
ret
;-------------------------------------------------------------------------------
gfx_SwapDraw:
; Swaps the roles of the screen and drawing buffers
; Arguments:
; None
; Returns:
; None
ld iy,mpLcdRange
.WaitLoop:
bit bLcdIntLNBU,(iy+lcdRis)
jr z,.WaitLoop
assert vRam and $FF = 0
assert LcdSize and $FF = 0
ld bc,(iy-mpLcdRange+CurrentBuffer+1) ; bc = old_draw>>8
.LcdSizeH := (LcdSize shr 8) and $FF
assert .LcdSizeH and lcdIntVcomp
assert .LcdSizeH and lcdIntLNBU
ld a,.LcdSizeH ; a = LcdSize>>8
ld (iy+lcdBase+1),bc ; screen = old_draw
ld (iy+lcdIcr),a ; clear interrupt statuses to wait for
xor a,c ; a = (old_draw>>8)^(LcdSize>>8)
ld c,a ; c = (old_draw>>8)^(LcdSize>>8)
inc b
res 1,b ; b = (old_draw>>16)+1&-2
; assuming !((old_draw>>16)&2):
; = (old_draw>>16)^1
; = (old_draw>>16)^(LcdSize>>16)
; bc = (old_draw>>8)^(LcdSize>>8)
; = new_draw>>8
ld (iy-mpLcdRange+CurrentBuffer+1),bc
ld hl,gfx_Wait
ld (hl),$E5 ; push hl; enable wait logic
push hl
dec sp
pop hl
ld l,$CD ; call *
; hl = first 3 bytes of call _Wait
dec sp
dec sp ; sp -= 3 to match pop hl later
jr _WriteWaitQuickSMC
;-------------------------------------------------------------------------------
gfx_Circle:
; Draws a clipped circle outline
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Radius
; Returns:
; None
ld iy,0
add iy,sp
lea hl,iy-9
ld sp,hl
ld bc,(iy+9)
ld (iy-6),bc
sbc hl,hl
ld (iy-3),hl
adc hl,bc
jp z,.exit
ld hl,1
or a,a
sbc hl,bc
call gfx_Wait
jp .next
.sectors:
ld bc,(iy+3)
ld hl,(iy-6)
add hl,bc
push hl
push hl
pop bc
ld de,(iy+6)
ld hl,(iy-3)
add hl,de
ex de,hl
push de
call _SetPixel_NoWait
ld bc,(iy+6)
ld hl,(iy-6)
add hl,bc
ex de,hl
push de
ld bc,(iy+3)
ld hl,(iy-3)
add hl,bc
push hl
push hl
pop bc
call _SetPixel_NoWait
ld bc,(iy-6)
ld hl,(iy+6)
or a,a
sbc hl,bc
ex de,hl
pop bc
push de
call _SetPixel_NoWait
pop de
ld bc,(iy-3)
ld hl,(iy+3)
or a,a
sbc hl,bc
push hl
push hl
pop bc
call _SetPixel_NoWait
pop bc
pop de
call _SetPixel_NoWait
pop de
ld bc,(iy-6)
ld hl,(iy+3)
or a,a
sbc hl,bc
push hl
push hl
pop bc
call _SetPixel_NoWait
ld bc,(iy-3)
ld hl,(iy+6)
or a,a
sbc hl,bc
ex de,hl
pop bc
push de
call _SetPixel_NoWait
pop de
pop bc
call _SetPixel_NoWait
ld bc,(iy-3)
inc bc
ld (iy-3),bc
ld bc,(iy-9)
or a,a
sbc hl,hl
sbc hl,bc
jp m,.cmp0
jp pe,.cmp1
jr .cmp2
.cmp0:
jp po,.cmp1
.cmp2:
ld hl,(iy-3)
add hl,hl
inc hl
add hl,bc
jr .next
.cmp1:
ld bc,(iy-6)
dec bc
ld (iy-6),bc
ld hl,(iy-3)
or a,a
sbc hl,bc
add hl,hl
inc hl
ld de,(iy-9)
add hl,de
.next:
ld (iy-9),hl
ld bc,(iy-3)
ld hl,(iy-6)
or a,a
sbc hl,bc
jp p,.check
jp pe,.sectors
jr .exit
.check:
jp po,.sectors
.exit:
ld sp,iy
ret
;-------------------------------------------------------------------------------
gfx_FillCircle:
; Draws an clipped circle
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Radius
; Returns:
; None
push ix
ld ix,0
add ix,sp
lea hl,ix-9
ld sp,hl
ld bc,(ix+12)
ld (ix-6),bc
sbc hl,hl
ld (ix-3),hl
adc hl,bc
jp z,_ResetStack
ld hl,1
or a,a
sbc hl,bc
jp .cmp3
.fillsectors:
ld hl,(ix-3)
add hl,hl
inc hl
ld (.circle0),hl
push hl
ld bc,(ix-6)
ld hl,(ix+9)
add hl,bc
push hl
ld bc,(ix-3)
ld hl,(ix+6)
or a,a
sbc hl,bc
ld (.circle1),hl
push hl
call gfx_HorizLine
ld hl,0
.circle0 := $-3
push hl
ld bc,(ix-6)
ld hl,(ix+9)
or a,a
sbc hl,bc
push hl
ld hl,0
.circle1 := $-3
push hl
call gfx_HorizLine
ld hl,(ix-6)
add hl,hl
inc hl
ld (.circle2),hl
push hl
ld bc,(ix-3)
ld hl,(ix+9)
add hl,bc
push hl
ld bc,(ix-6)
ld hl,(ix+6)
or a,a
sbc hl,bc
ld (.circle3),hl
push hl
call gfx_HorizLine
ld hl,0
.circle2 := $-3
push hl
ld bc,(ix-3)
ld hl,(ix+9)
or a,a
sbc hl,bc
push hl
ld hl,0
.circle3 := $-3
push hl
call gfx_HorizLine
lea hl,ix-9
ld sp,hl
ld bc,(ix-3)
inc bc
ld (ix-3),bc
ld bc,(ix-9)
or a,a
sbc hl,hl
sbc hl,bc
jp m,.cmp0
jp pe,.cmp2
jr .cmp1
.cmp0:
jp po,.cmp2
.cmp1:
ld hl,(ix-3)
add hl,hl
inc hl
add hl,bc
jr .cmp3
.cmp2:
ld bc,(ix-6)
dec bc
ld (ix-6),bc
ld hl,(ix-3)
ld de,(ix-9)
or a,a
sbc hl,bc
add hl,hl
inc hl
add hl,de
.cmp3:
ld (ix-9),hl
ld bc,(ix-3)
ld hl,(ix-6)
or a,a
sbc hl,bc
jp p,.check
jp pe,.fillsectors
ld sp,ix
pop ix
ret
.check:
jp po,.fillsectors
ld sp,ix
pop ix
ret
;-------------------------------------------------------------------------------
gfx_FillCircle_NoClip:
; Draws an unclipped circle
; Arguments:
; arg0 : X coordinate
; arg1 : Y coordinate
; arg2 : Radius
; Returns:
; None
push ix
ld ix,0
add ix,sp
lea hl,ix-9
ld sp,hl
ld bc,(ix+12)
ld (ix-6),bc
sbc hl,hl
ld (ix-3),hl
adc hl,bc
jp z,_ResetStack
ld hl,1
or a,a
sbc hl,bc
call gfx_Wait
jp .loop
.fillsectors:
ld hl,(ix-3)
add hl,hl
inc hl
ld (.circle0),hl
push hl
ld bc,(ix-6)
ld hl,(ix+9)
add hl,bc
ld e,l
ld bc,(ix-3)
ld hl,(ix+6)
or a,a
sbc hl,bc
ld (.circle1),hl
pop bc
call _HorizLine_NoClip_NotDegen_NoWait
ld bc,0
.circle0 := $-3
ld de,(ix-6)
ld hl,(ix+9)
or a,a
sbc hl,de
ld e,l
ld hl,0
.circle1 := $-3
call _HorizLine_NoClip_NotDegen_NoWait
ld hl,(ix-6)
add hl,hl
inc hl
ld (.circle2),hl
push hl
ld bc,(ix-3)
ld hl,(ix+9)
add hl,bc
ld e,l
ld bc,(ix-6)
ld hl,(ix+6)
or a,a
sbc hl,bc
ld (.circle3),hl
pop bc
call _HorizLine_NoClip_NotDegen_NoWait
ld bc,0
.circle2 := $-3
ld de,(ix-3)
ld hl,(ix+9)
or a,a
sbc hl,de
ld e,l
ld hl,0
.circle3 := $-3
call _HorizLine_NoClip_NotDegen_NoWait
ld bc,(ix-3)
inc bc
ld (ix-3),bc
ld bc,(ix-9)
or a,a
sbc hl,hl
sbc hl,bc
jp m,.cmp0
jp pe,.cmp2
jr .cmp1
.cmp0:
jp po,.cmp2
.cmp1:
ld hl,(ix-3)
add hl,hl
inc hl
add hl,bc
jr .loop
.cmp2:
ld bc,(ix-6)
dec bc
ld (ix-6),bc
ld hl,(ix-3)
or a,a
sbc hl,bc
add hl,hl
inc hl
ld de,(ix-9)
add hl,de
.loop:
ld (ix-9),hl
ld bc,(ix-3)
ld hl,(ix-6)
or a,a
sbc hl,bc
jp nc,.fillsectors
_ResetStack:
ld sp,ix
pop ix
ret
;-------------------------------------------------------------------------------
gfx_Line:
; Draws an arbitrarily clipped line
; Arguments:
; arg0: x0
; arg0: y0
; arg0: x1
; arg0: y1
; Returns:
; true if drawn, false if offscreen
ld iy,0
add iy,sp
push hl ; temp storage
ld hl,(iy+3) ; x0
ld de,(iy+6) ; y0
call _ComputeOutcode
ld (iy-1),a
ld hl,(iy+9) ; x1
ld de,(iy+12) ; y1
call _ComputeOutcode
ld (iy-2),a
CohenSutherlandLoop:
ld b,(iy-1) ; b = outcode0
ld a,(iy-2) ; a = outcode1
tst a,b
jp nz,TrivialReject ; if(outcode0|outcode1)
or a,a
jr nz,GetOutOutcode
or a,b
jp z,TrivialAccept
GetOutOutcode: ; select correct outcode
push af ; a = outoutcode
rra
jr nc,.notop ; if (outcodeOut & TOP)
ld hl,(_YMax)
dec hl ; inclusive
jr ComputeNewX
.notop:
rra
jr nc,NotBottom ; if (outcodeOut & BOTTOM)
ld hl,(_YMin)
ComputeNewX:
push hl
ld bc,(iy+6)
or a,a
sbc hl,bc ; ymax_YMin - y0
ex de,hl
ld hl,(iy+9)
ld bc,(iy+3)
or a,a
sbc hl,bc ; x0 - x1
call _MultiplyHLDE
ex de,hl ; (x0 - x1)*(ymax_YMin - y0)
ld hl,(iy+12)
ld bc,(iy+6)
or a,a
sbc hl,bc ; y1 - y0
push hl
pop bc
ex de,hl
call _DivideHLBC ; ((x0 - x1)*(ymax_YMin - y0))/(y1 - y0)
ld bc,(iy+3)
add hl,bc ; (x) hl = x0 + ((x0 - x1)*(ymax_YMin - y0))/(y1 - y0)
pop de ; (y) de = ymax_YMin
jr FinishComputations
NotBottom:
rra
jr nc,NotRight ; if (outcodeOut & RIGHT)
ld hl,(_XMax)
dec hl ; inclusive
jr ComputeNewY
NotRight:
rra
jr nc,FinishComputations ; if (outcodeOut & LEFT)
ld hl,(_XMin)
ComputeNewY:
push hl
ld bc,(iy+3)
or a,a
sbc hl,bc ; xmax_XMin - x0
ex de,hl
ld hl,(iy+12)
ld bc,(iy+6)
sbc hl,bc ; x1 - x0
call _MultiplyHLDE
ex de,hl ; (x1 - x0)*(xmax_XMin - x0)
ld hl,(iy+9)
ld bc,(iy+3)
or a,a
sbc hl,bc ; y1 - y0
push hl
pop bc
ex de,hl
call _DivideHLBC ; ((x1 - x0)*(xmax_XMin - x0))/(y1 - y0)
ld bc,(iy+6)
add hl,bc
ex de,hl ; (y) de = y0 + ((x1 - x0)*(xmax_XMin - x0))/(y1 - y0)
pop hl ; (x) hl = ymax_YMin
FinishComputations:
pop af
cp a,(iy-1)
jr nz,OutcodeOutOutcode1
ld (iy+3),hl
ld (iy+6),de
call _ComputeOutcode
ld (iy-1),a ; b = outcode0
jp CohenSutherlandLoop
OutcodeOutOutcode1:
ld (iy+9),hl
ld (iy+12),de
call _ComputeOutcode
ld (iy-2),a ; c = outcode1
jp CohenSutherlandLoop
TrivialReject:
inc sp
inc sp
inc sp
ret
TrivialAccept:
inc sp
inc sp
inc sp
; jr _Line_NoClip ; line routine handler
;-------------------------------------------------------------------------------
gfx_Line_NoClip:
; Draws an unclipped arbitrary line
; Arguments:
; arg0 : X1 coordinate (hl)
; arg1 : Y1 coordinate (b)
; arg2 : X2 coordinate (de)
; arg3 : Y2 coordinate (c)
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(iy+3)
ld de,(iy+9)
ld b,(iy+6)
ld c,(iy+12) ; line from hl,b to de,c
or a,a
sbc hl,de
add hl,de
jr c,+_ ; draw left to right
ex de,hl
ld a,b
ld b,c
ld c,a
_: push bc
pop iy
push hl
ld hl,(CurrentBuffer)
ld c,160
mlt bc
add hl,bc
add hl,bc ; y0 * screenwidth
pop bc
add hl,bc ; y0 * screenwidth + x0
push hl ; save buffer
ex de,hl
or a,a
sbc hl,bc ; xe - xs
push hl
pop bc ; bc = dx
ld a,iyh
or a,a
sbc hl,hl
ld l,a ; y1
ex de,hl
ld a,iyl
sbc hl,hl
ld l,a ; y0
sbc hl,de
jr nc,$+9
ex de,hl
sbc hl,hl
ccf
sbc hl,de
inc hl ; abs(dy)
ld a,iyl
sub a,iyh
ld iy,-320
jr c,$+7
ld iy,320
or a,a
sbc hl,bc
add hl,bc ; hl = dy
jr nc,dl_vertical
dl_horizontal:
ld a,l
or a,h
ld a,$38
jr nz,$+4
xor a,$20
ld (_smc_dl_jr_0 + 0),a ; write smc
ld (_smc_dl_width_1 + 1),iy ; write smc
ex de,hl
sbc hl,hl
ccf
sbc hl,de
inc hl
ex de,hl ; de = -dy
pop hl ; restore buffer
ld (_smc_dl_dx_1 + 1),bc ; write smc
ld (_smc_dl_dy_1 + 1),de ; write smc
push bc
srl b
rr c
push bc
pop iy ; iy = dx / 2
pop bc
inc bc
ld a,0
smcByte _Color
wait_quick
dl_hloop:
ld (hl),a ; write pixel
cpi
ret po
add iy,de ; dy
_smc_dl_jr_0:
jr c,dl_hloop
_smc_dl_width_1:
ld de,0
add hl,de ; y inc
_smc_dl_dx_1:
ld de,0 ; dx
add iy,de
_smc_dl_dy_1:
ld de,0 ; dy
jr dl_hloop
dl_vertical:
lea de,iy
ld b,c
ld a,l
ld iyl,a
ld c,a
srl a ; a = dy / 2
inc c
pop hl
wait_quick
dl_vloop:
ld (hl),0 ; write pixel
smcByte _Color
dec c
ret z
add hl,de ; y inc
sub a,b ; dx
jr nc,dl_vloop
inc hl
add a,iyl ; dy
jr dl_vloop
;-------------------------------------------------------------------------------
gfx_Blit:
; Copies the buffer image to the screen and vice versa
; Arguments:
; arg0 : Buffer to copy from (screen = 0, buffer = 1)
; Returns:
; None
pop iy ; iy = return vector
ex (sp),hl
ld a,l ; a = buffer to blit from
call _CheckBlit ; determine blit buffers
ld bc,LcdSize
_Blit_Ldir:
call gfx_Wait
ldir ; just do it
jp (iy)
;-------------------------------------------------------------------------------
gfx_BlitLines:
; Copies the buffer image to the screen and vice versa line wise
; Arguments:
; arg0 : Buffer to copy from (screen = 0, buffer = 1)
; arg1 : Y coordinate
; arg2 : Number of lines to copy
; Returns:
; None
pop iy ; iy = return vector
pop bc
ld a,c ; a = buffer to blit from
pop de ; e = number of lines to copy
ex (sp),hl ; l = y coordinate
push de
push bc
ld h,LcdWidth/2
ld d,h
mlt hl
add hl,hl ; hl -> number of bytes to copy
push hl
ex de,hl
mlt hl
add hl,hl ; hl -> offset to start at
push hl
call _CheckBlit ; determine blit buffers
pop bc
add hl,bc
ex de,hl
add hl,bc
ex de,hl
pop bc ; number of bytes to copy
jr _Blit_Ldir
;-------------------------------------------------------------------------------
gfx_BlitRectangle:
; Copies the buffer image to the screen and vice versa rectangularly
; Arguments:
; arg0 : Buffer to copy from (screen = 0, buffer = 1)
; arg1 : X coordinate
; arg2 : Y coordinate
; arg3 : Width
; arg4 : Height
; Returns:
; None
ld iy,0
add iy,sp
ld de,(iy+6) ; de = x coordinate
ld l,(iy+9) ; l = y coordinate
ld h,LcdWidth/2
mlt hl
add hl,hl
add hl,de ; hl = amount to increment
push hl ; save amount to increment
ld a,(iy+3) ; a = buffer to blit from
call _CheckBlit ; determine blit buffers
pop bc
add hl,bc
ex de,hl
add hl,bc
ex de,hl
ld bc,(iy+12) ; the width of things
ld (.width),bc
push hl
ld hl,LcdWidth
or a,a
sbc hl,bc ; change in width for rectangle
ld (.delta),hl
pop hl
ld a,(iy+15)
ld iy,0
add iy,de
call gfx_Wait
.loop:
ld bc,0 ; smc for speedz
.width := $-3
ldir
inc b
ld c,$40 ; increment to next line
add iy,bc
lea de,iy
ld bc,0 ; increment to next line
.delta := $-3
add hl,bc
dec a
jr nz,.loop
ret
;-------------------------------------------------------------------------------
gfx_ShiftLeft:
; Shifts whatever is in the clip left by some pixels
; Arguments:
; arg0 : Amount to shift by
; Returns:
; None
db $F6 ; magic byte
;-------------------------------------------------------------------------------
gfx_ShiftUp:
; Shifts whatever is in the clip up by some pixels
; Arguments:
; arg0 : Amount to shift by
; Returns:
; None
scf
ld a,$B0
call _ShiftCalculate
ld (ShiftAmountOffset),hl
jr z,.next
sbc hl,hl
.next:
ex de,hl
ld hl,(_XMax)
ld bc,(_XMin)
sbc hl,bc
sbc hl,de
ld (ShiftCopyAmount),hl
ex de,hl
ld hl,LcdWidth
sbc hl,de
ld (ShiftLineOff),hl
ld hl,_YMax
sub a,(hl)
ld hl,_YMin
ld e,(hl)
add a,e
jr _Shift
;-------------------------------------------------------------------------------
gfx_ShiftRight:
; Shifts whatever is in the clip right by some pixels
; Arguments:
; arg0 : Amount to shift by
; Returns:
; None
db $F6 ; magic byte
;-------------------------------------------------------------------------------
gfx_ShiftDown:
; Shifts whatever is in the clip down by some pixels
; Arguments:
; arg0 : Amount to shift by
; Returns:
; None
scf
ld a,$B8
call _ShiftCalculate
ex de,hl
sbc hl,hl
sbc hl,de
ld (ShiftAmountOffset),hl
or a,a
jr z,.next
sbc hl,hl
.next:
ld bc,(_XMax)
add hl,bc
dec bc
ld e,a
ld a,(_YMin)
add a,e
ld de,(_XMin)
sbc hl,de
ld (ShiftCopyAmount),hl
ld de,0 - LcdWidth
add hl,de
ld (ShiftLineOff),hl
ld hl,_YMax
ld e,(hl)
sub a,e
dec e
_Shift:
ld d,LcdWidth/2
mlt de
ld hl,(CurrentBuffer)
add hl,de
add hl,de
add hl,bc
call gfx_Wait
ShiftCopyAmount :=$+1
.loop:
ld bc,0
ex de,hl
ShiftAmountOffset :=$+1
ld hl,0
add hl,de
ShiftCopyDirection :=$+1
ldir
ShiftLineOff :=$+1
ld hl,0
add hl,de
inc a
jr nz,.loop
ret
;-------------------------------------------------------------------------------
gfx_GetClipRegion:
; Arguments:
; Pointer to struct
; Returns:
; False if offscreen
ld hl,3
add hl,sp
ld iy,(hl)
call _ClipRegion ; get the clipping region
sbc a,a ; return false if offscreen (0)
inc a
ret
;-------------------------------------------------------------------------------
gfx_ScaledSprite_NoClip:
; Draws a scaled sprite to the screen
; Arguments:
; arg0 : Pointer to sprite
; arg1 : X coordinate
; arg2 : Y coordinate
; arg5 : Width Scale (integer)
; arg6 : Height Scale (integer)
; Returns:
; None
ld iy,0
add iy,sp
push ix
ld h,LcdWidth/2
ld l,(iy+15) ; height of scale
ld a,l
ld (NcSprHscl+1),a
mlt hl
add hl,hl
ld (NcSprHscl320+1),hl
ld de,(iy+6) ; x coordinate
ld c,(iy+9) ; y coordinate
ld a,(iy+12) ; width of scale
ld h,a
ld ixl,a
ld iy,(iy+3) ; start of sprite structure
ld l,(iy+0)
ld a,l
ld (NcSprWidth+1),a
mlt hl
ld (SprWxSclW1+1),hl
ld (SprWxSclW2+1),hl
ld a,(iy+1)
ld ixh,a ; height of sprite
ld hl,(CurrentBuffer)
add hl,de
inc hl
ld b,LcdWidth/2
mlt bc
add hl,bc
call gfx_Wait
NcSprBigLoop:
add hl,bc
ex de,hl
sbc hl,hl
ld b,l
add hl,de
dec hl
push de
NcSprWidth:
ld a,0 ; width of sprite
jr NcSprLpEntry
NcSprWlp:
ldir
NcSprLpEntry:
ld c,(iy+2)
inc iy
ld (hl),c
ld c,ixl ; width of scale
dec a
jr nz,NcSprWlp
dec c
jr z,NcSprHscl
ldir
NcSprHscl:
ld a,0 ; height of scale
dec a
jr z,NcSprW_end
inc b
ld c,$40 ; bc = LcdWidth
NcSprLineCopy:
add hl,bc
dec de
ex de,hl
SprWxSclW1:
ld bc,0 ; widthSprite x widthScale
lddr
dec a
jr z,NcSprW_end
ld bc,641
add hl,bc
inc de
ex de,hl
SprWxSclW2:
ld bc,0 ; widthSprite x widthScale
ldir
ld bc,639
dec a
jr nz,NcSprLineCopy
NcSprW_end:
pop hl
NcSprHscl320:
ld bc,0 ; LcdWidth x heightScale
dec ixh
jr nz,NcSprBigLoop
pop ix ; restore ix sp
ret
;-------------------------------------------------------------------------------
gfx_ScaledTransparentSprite_NoClip:
; Draws a scaled sprite to the screen with transparency
; Arguments:
; arg0 : Pointer to sprite structure
; arg1 : X coordinate
; arg2 : Y coordinate
; arg5 : Width Scale (integer)
; arg6 : Height Scale (integer)
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(iy+6) ; hl = x coordinate
ld c,(iy+9) ; c = y coordniate
ld de,(CurrentBuffer)
add hl,de
ld b,LcdWidth/2
mlt bc
add hl,bc
add hl,bc
ex de,hl ; de -> start draw location
ld hl,LcdWidth
ld a,(iy+15)
ld (.heightscale),a
ld a,(iy+12)
ld (.widthscale),a ; smc faster inner loop
ld iy,(iy+3) ; iy -> start of sprite struct
ld c,(iy+0) ; c = width
ld b,a
ld a,c
mlt bc
sbc hl,bc ; find x offset next
ld (.amount),hl
ld (.width),a
ld a,(iy+1)
lea hl,iy+2 ; hl -> sprite data
push ix ; save ix sp
ld ixh,a ; ixh = height
call gfx_Wait
.loop:
ld ixl,0 ; ixl = height scale
.heightscale := $-1
.loopheight:
push hl
ld c,0
.width := $-1
.loopwidth:
ld b,0
.widthscale := $-1
ld a,(hl) ; get sprite pixel
cp a,TRASPARENT_COLOR
smcByte _TransparentColor
jr nz,.next ; is transparent?
.skip:
inc de
djnz .skip
jr .locate ; loop for next pixel
.next:
ld (de),a
inc de
djnz .next ; set and loop for next pixel
.locate:
inc hl
dec c
jr nz,.loopwidth ; loop for width
ex de,hl
ld iy,0
add iy,de ; save hl
ld bc,0
.amount := $-3
add hl,bc ; get next draw location
ex de,hl
pop hl
dec ixl ; loop height scale
jr nz,.loopheight
lea hl,iy ; restore hl
dec ixh ; loop height
jr nz,.loop
pop ix ; restore ix sp
ret
;-------------------------------------------------------------------------------
gfx_TransparentSprite:
; Draws a transparent sprite with clipping
; Arguments:
; arg0 : Pointer to sprite
; arg1 : X coordinate
; arg2 : Y coordinate
; Returns:
; None
push ix ; save ix sp
call _ClipCoordinates
pop ix ; restore ix sp
ret nc
ld (.amount),a
ld a,(iy+0) ; _TmpWidth
ld (.next),a
ld a,(iy+3) ; tmpHeight
ld h,LcdWidth/2
mlt hl
ld bc,0 ; zero ubc
add hl,hl
add hl,de
ld de,(CurrentBuffer)
add hl,de
push hl
ld hl,(iy+6) ; hl -> sprite data
pop iy
push ix
ld ixh,a
ld a,TRASPARENT_COLOR
smcByte _TransparentColor
wait_quick
.loop:
ld c,0
.next := $-1
lea de,iy
call _TransparentPlot ; call the transparent routine
ld c,0
.amount := $-1
add hl,bc
ld de,LcdWidth ; move to next row
add iy,de
dec ixh
jr nz,.loop
pop ix
ret
_TransparentPlot_Opaque: ; routine to handle transparent plotting
ldi
ret po
cp a,(hl)
jr z,_TransparentPlot_Transparent
ldi
ret po
cp a,(hl)
jr z,_TransparentPlot_Transparent
ldi
ret po
cp a,(hl)
jr z,_TransparentPlot_Transparent
ldi
ret po
cp a,(hl)
jr nz,_TransparentPlot_Opaque
_TransparentPlot_Transparent:
inc de
inc hl
dec c
ret z
_TransparentPlot:
cp a,(hl)
jr nz,_TransparentPlot_Opaque
inc de
inc hl
dec c
ret z
cp a,(hl)
jr nz,_TransparentPlot_Opaque
inc de
inc hl
dec c
ret z
cp a,(hl)
jr nz,_TransparentPlot_Opaque
inc de
inc hl
dec c
ret z
cp a,(hl)
jr z,_TransparentPlot_Transparent
jr _TransparentPlot_Opaque
;-------------------------------------------------------------------------------
gfx_Sprite:
; Places an sprite on the screen as fast as possible with clipping
; Arguments:
; arg0 : Pointer to sprite
; arg1 : X coordinate
; arg2 : Y coordinate
; arg3 : Width -- 8bits
; arg4 : Height -- 8bits
; Returns:
; None
push ix ; save ix sp
call _ClipCoordinates
pop ix ; restore ix sp
ret nc
ld (.amount),a
ld a,(iy+0) ; a = _TmpWidth
ld (.next),a
ld a,(iy+3) ; a = tmpHeight
ld h,LcdWidth/2
mlt hl
add hl,hl
add hl,de
ld de,(CurrentBuffer)
add hl,de
push hl
ld hl,(iy+6) ; hl -> sprite data
pop iy
ld bc,0
wait_quick
.loop:
ld c,0
.next := $-1
lea de,iy
ldir
ld de,LcdWidth
add iy,de
ld c,0
.amount := $-1
add hl,bc ; move to next line
dec a
jr nz,.loop
ret
;-------------------------------------------------------------------------------
gfx_Sprite_NoClip:
; Places an sprite on the screen as fast as possible
; Arguments:
; arg0 : Pointer to sprite
; arg1 : X coordinate
; arg2 : Y coordinate
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(CurrentBuffer)
ld bc,(iy+6) ; x coordinate
add hl,bc
ld d,LcdWidth/2
ld e,(iy+9) ; y coordinate
mlt de
add hl,de
add hl,de
ex de,hl ; de = start draw location
ld hl,(iy+3) ; hl = sprite structure
ld c,(hl) ; spriteWidth
inc hl
ld iyh,c
xor a,a
ld b,a
srl c
sbc a,.step - .evenw
ld (.step - 1),a
ld a,LcdWidth/2
sub a,c
ld iyl,a ; (LcdWidth/2)-(spriteWidth/2)
ld a,(hl) ; spriteHeight
inc hl
wait_quick
jr .start
.loop:
dec de ; needed if sprite width is odd
.evenw:
ld c,iyl ; (LcdWidth/2)-(spriteWidth/2)
ex de,hl
add hl,bc
add hl,bc
ex de,hl
.start:
ld c,iyh ; spriteWidth
ldir
dec a
jr nz,.loop
.step:
ret
;-------------------------------------------------------------------------------
gfx_GetSprite:
; Grabs the data from the current draw buffer and stores it in another buffer
; Arguments:
; arg0 : Pointer to storage buffer
; arg1 : X coordinate
; arg2 : Y coordinate
; Returns:
; Pointer to resultant sprite
ld iy,0
add iy,sp
ld bc,(iy+9) ; bc = y coordinate
bit 0,b ; check if negative y
ld b,LcdWidth/2
mlt bc
ld hl,(CurrentBuffer)
add hl,bc
add hl,bc ; hl -> place to begin drawing
jr z,.next
ld de,(-LcdWidth)*256
add hl,de ; fix if negative
.next:
ld de,(iy+6)
add hl,de
ld de,(iy+3)
push de
ld a,(de)
inc de
ld (.amount),a ; amount to copy per line
ld c,a
ld a,LcdWidth and $ff
sub a,c
ld c,a
sbc a,a
inc a
ld b,a ; the amount to add to get to the next line
ld (.offset),bc
ld a,(de)
inc de
.loop:
ld bc,0
.amount := $-3
ldir ; copy the data into the struct data
ld bc,0
.offset := $-3
add hl,bc
dec a
jr nz,.loop
pop hl
ret
;-------------------------------------------------------------------------------
gfx_TransparentSprite_NoClip:
; Draws a transparent sprite to the current buffer
; Arguments:
; arg0 : Pointer to sprite
; arg1 : X coordinate
; arg2 : Y coordinate
; Returns:
; None
ld iy,0
add iy,sp
ld hl,(iy+6) ; hl = x coordinate
ld c,(iy+9) ; c = y coordinate
ld iy,(iy+3) ; iy -> sprite struct
ld de,(CurrentBuffer)
add hl,de
ld b,LcdWidth/2
mlt bc
add hl,bc
add hl,bc ; hl -> place to draw
push hl
ld a,(iy+0)
ld (.next),a
ld a,(iy+1)
lea hl,iy+2
pop iy
push ix
ld ixh,a ; ixh = height of sprite
ld b,0 ; zero mid byte
ld a,TRASPARENT_COLOR
smcByte _TransparentColor
wait_quick
.loop:
ld c,0
.next := $-1
lea de,iy
call _TransparentPlot ; call the plotter
ld de,LcdWidth
add iy,de
dec ixh ; loop for height
jr nz,.loop
pop ix ; restore stack pointer
ret
;-------------------------------------------------------------------------------
_ClipCoordinates:
; Clipping stuff
; Arguments:
; arg0 : Pointer to sprite structure
; arg1 : X coordinate
; arg2 : Y coordinate
; Returns:
; A : How much to add to the sprite per iteration
; L : New Y coordinate
; DE : New X coordinate
; NC : If offscreen
ld ix,6 ; get pointer to arguments
lea iy,ix-6
add ix,sp
ld hl,(ix+3)
ld a,(hl)
ld de,_TmpWidth
ld (de),a ; save _TmpWidth
ld (.width),a ; save tmpSpriteWidth
add iy,de
inc hl
ld a,(hl)
ld (iy+3),a ; save tmpHeight
inc hl
ld (iy+6),hl ; save a ptr to the sprite data to change offsets
ld bc,(ix+9)
ld hl,(_YMin)
mIsHLLessThanBC
jr c,.notop
ld hl,(iy+3)
add hl,bc
ex de,hl
ld hl,(_YMin)
mIsHLLessThanDE
ret nc ; bc = y location
ld hl,(_YMin) ; ymin
or a,a
sbc hl,bc
ld a,(iy+3)
sub a,l
ld (iy+3),a
ld h,(iy+0) ; h = _TmpWidth
mlt hl ; hl = amount of lines clipped off
ld de,(iy+6) ; de -> sprite data
add hl,de
ld (iy+6),hl ; store new ptr
ld bc,(_YMin) ; new y location ymin
.notop:
push bc
pop hl ; hl = y coordinate
ld de,(_YMax)
mIsHLLessThanDE
ret nc ; return if offscreen on bottom
; bc = y coordinate
ld hl,(iy+3) ; hl = tmpHeight
add hl,bc
ld de,(_YMax)
mIsHLLessThanDE
jr c,.notbottom ; is partially clipped bottom?
ex de,hl ; hl = ymax
; bc = y coordinate
sbc hl,bc
ld (iy+3),hl ; store new tmpHeight
.notbottom:
ld hl,(ix+6) ; hl = x coordinate
ld de,(_XMin)
mIsHLLessThanDE
ld hl,(ix+6) ; hl = x coordinate
jr nc,.noleft ; is partially clipped left?
ld de,(iy+0) ; de = _TmpWidth
add hl,de
ld de,(_XMin)
ex de,hl
mIsHLLessThanDE
ret nc ; return if offscreen
ld de,(ix+6) ; de = x coordinate
ld hl,(_XMin)
or a,a
sbc hl,de
ex de,hl ; calculate new offset
ld hl,(iy+6) ; hl -> sprite data
add hl,de
ld (iy+6),hl ; save new ptr
ld hl,(iy+0) ; hl = _TmpWidth
or a,a
sbc hl,de
ld (iy+0),hl ; save new width
ld hl,(_XMin)
ld (ix+6),hl ; save min x coordinate
.noleft:
ld de,(_XMax) ; de = xmax
mIsHLLessThanDE
ret nc ; return if offscreen
ld hl,(ix+6) ; hl = x coordinate
ld de,(iy+0) ; de = _TmpWidth
add hl,de
ld de,(_XMax)
ex de,hl
mIsHLLessThanDE
jr nc,.noright ; is partially clipped right?
ld hl,(_XMax) ; clip on the right
ld de,(ix+6)
ccf
sbc hl,de
ld (iy+0),hl ; save new _TmpWidth
.noright:
ld a,(iy+3)
or a,a
ret z ; quit if new tmpHeight is 0 (edge case)
ld a,0
.width := $-1
ld de,(ix+6) ; de = x coordinate
ld l,c ; l = y coordinate
sub a,(iy+0) ; compute new x width
scf ; set carry for success
ret
;-------------------------------------------------------------------------------
gfx_TransparentTilemap_NoClip:
; Tilemapping subsection
ld hl,gfx_TransparentSprite_NoClip
; jr _Tilemap ; emulated by dummifying next instruction:
db $FD ; ld hl,* -> ld iy,*
;-------------------------------------------------------------------------------
gfx_Tilemap_NoClip:
; Tilemapping subsection
ld hl,gfx_Sprite_NoClip
; jr _Tilemap ; emulated by dummifying next instruction:
db $FD ; ld hl,* -> ld iy,*
;-------------------------------------------------------------------------------
gfx_TransparentTilemap:
; Tilemapping subsection
ld hl,gfx_TransparentSprite
; jr _Tilemap ; emulated by dummifying next instruction:
db $FD ; ld hl,* -> ld iy,*
;-------------------------------------------------------------------------------
gfx_Tilemap:
; Draws a tilemap given a tile map structure and some offsets
; Arguments:
; arg0 : Tilemap Struct
; arg1 : X Pixel Offset (Unsigned)
; arg2 : Y Pixel Offset (Unsigned)
; Returns:
; None
; C Function:
; void DrawBGTilemap(gfx_tilemap_t *tilemap, unsigned x_offset, unsigned y_offset) {
; int x_draw, y_draw;
; uint8_t x, x_tile, y_tile, y_next;
; uint8_t x_res = x_offset/tilemap->tile_width;
; uint8_t y = y_offset/tilemap->tile_height;
;
; x_offset = x_offset%tilemap->tile_width;
; y_offset = y_offset%tilemap->tile_height;
;
; y_draw = tilemap->y_loc-y_offset;
; for(y_tile = 0; y_tile <= tilemap->draw_height; y_tile++) {
; x = x_res;
; y_next = y*tilemap->width;
; x_draw = tilemap->x_loc-x_offset;
; for(x_tile = 0; x_tile <= tilemap->draw_width; x_tile++) {
; gfx_Sprite(tilemap->tiles[tilemap->map[x+y_next]], x_draw, y_draw, tilemap->tile_width, tilemap->tile_height);
; x_draw += tilemap->tile_width;
; x++;
; }
; y_draw += tilemap->tile_height;
; y++;
; }
; }
;
t_data := 0
t_type_width := 10
t_type_height := 11
t_height := 12
t_width := 13
t_tile_height := 6
t_tile_width := 7
t_draw_height := 8
t_draw_width := 9
t_x_loc := 15
x_offset := 9
y_offset := 12
ld hl,gfx_Sprite
_Tilemap:
ld (.tilemethod),hl
push ix
ld ix,0
lea bc,ix
add ix,sp
lea hl,ix-12
ld sp,hl
ld iy,(ix+6) ; iy -> tilemap structure
ld hl,(ix+y_offset)
ld c,(iy+t_tile_height)
ld a,(iy+t_type_height)
or a,a
jr nz,.heightpow2
call __idvrmu
ex de,hl
push de
pop bc
jr .heightnotpow2
.heightpow2: ; compute as power of 2 height using shifts
ld b,a
dec c
ld a,l
and a,c
ld c,a
.div0:
srl h
rr l
djnz .div0
.heightnotpow2:
ld (ix-4),l ; y = y_offset / tilemap->tile_height
ld (ix+y_offset),bc ; y_offset = y_offset % tilemap->tile_height;
ld c,(iy+t_tile_width)
ld hl,(ix+x_offset) ; x offset
ld a,(iy+t_type_width)
or a,a
jr nz,.widthpow2
call __idvrmu
ex de,hl
push de
pop bc
jr .widthnotpow2
.widthpow2:
ld b,a
dec c
ld a,l
and a,c
ld c,a
.div1:
srl h
rr l
djnz .div1
.widthnotpow2:
ld a,l
ld (.xres),a
ld hl,(iy+t_x_loc)
or a,a
sbc hl,bc
ld (.xoffset),hl ; tilemap->x_loc - x_offset;
or a,a
sbc hl,hl
ld l,(iy+14)
ld bc,(ix+y_offset)
ld (ix-3),h
sbc hl,bc
ld (ix-12),hl
jp .yloop
.xres := $+3
.loop:
ld (ix-1),0
ld hl,0
.xoffset := $-3
ld (ix-7),hl
ld l,(iy+t_width)
ld h,(ix-4)
mlt hl
ld (.ynext),hl
xor a,a
jr .xloop
.xloopinner:
or a,a
sbc hl,hl
ld l,(ix-1)
ld bc,(iy+t_data) ; iy -> tilemap data
add hl,bc
ld bc,0
.ynext := $-3
add hl,bc
ld a,(hl)
ld l,a
inc a
jr z,.blanktile
ld h,3
mlt hl
ld de,(iy+3)
add hl,de
ld bc,(ix-12)
push bc
ld bc,(ix-7)
push bc
ld bc,(hl)
push bc
call 0 ; call sprite drawing routine
.tilemethod := $-3
lea hl,ix-12
ld sp,hl
.blanktile:
or a,a
sbc hl,hl
ld iy,(ix+6)
ld l,(iy+7)
ld bc,(ix-7)
add hl,bc
ld (ix-7),hl
inc (ix-1)
ld a,(ix-2)
inc a
.xloop:
ld (ix-2),a
cp a,(iy+t_draw_width)
jr nz,.xloopinner
ld h,0
ld l,(iy+6)
ld bc,(ix-12)
add hl,bc
ld (ix-12),hl
inc (ix-4)
inc (ix-3)
.yloop:
ld a,(iy+t_draw_height)
cp a,(ix-3)
jp nz,.loop
ld sp,ix
pop ix
ret
;-------------------------------------------------------------------------------
gfx_TilePtr:
; Returns a pointer to a tile given the pixel offsets
; Arguments:
; arg0 : Tilemap Struct
; arg1 : X Pixel Offset (Unsigned)
; arg2 : Y Pixel Offset (Unsigned)
; Returns:
; A pointer to an indexed tile in the tilemap (so it can be looked at or changed)
; C Function:
; uint8_t *gfx_TilePtr(gfx_tilemap_t *tilemap, unsigned x_offset, unsigned y_offset) {
; return &tilemap->map[(x_offset/tilemap->tile_width)+((y_offset/tilemap->tile_height)*tilemap->width)];
; }
push ix
ld ix,0
add ix,sp
ld iy,(ix+6)
ld hl,(ix+x_offset)
ld a,(iy+t_type_width)
or a,a
jr nz,.fastdiv0
ld bc,0
ld c,(iy+t_tile_width)
call __idvrmu
ex de,hl
jr .widthnotpow2
.fastdiv0:
ld b,a
.div0:
srl h
rr l
djnz .div0
.widthnotpow2:
ex de,hl
ld hl,(ix+y_offset)
ld a,(iy+t_type_height)
or a,a
jr nz,.fastdiv1
ld bc,0
ld c,(iy+t_tile_height)
push de
call __idvrmu
ex de,hl
pop de
jr .heightnotpow2
.fastdiv1:
ld b,a
.div1: srl h
rr l
djnz .div1
.heightnotpow2:
ld h,(iy+t_width)
mlt hl
add hl,de
ld de,(iy+t_data)
add hl,de
pop ix
ret
;-------------------------------------------------------------------------------
gfx_TilePtrMapped:
; Returns a direct pointer to the input tile
; Arguments:
; arg0 : Tilemap Struct
; arg1 : X Map Offset
; arg2 : Y Map Offset
; Returns:
; A pointer to the indexed tile in the tilemap (so it can be looked at or changed)
pop de ; return vector
pop iy ; tilemap struct
pop bc ; x offset
ex (sp),hl ; y offset
push bc
push bc
ld h,(iy+13) ; tilemap width
mlt hl
ld b,0
add.s hl,bc
ld bc,(iy+0) ; tilemap data
add hl,bc
ex de,hl
jp (hl)
;-------------------------------------------------------------------------------
gfx_GetTextX:
; Gets the X position of the text cursor
; Arguments:
; None
; Returns:
; X Text cursor posistion
ld hl,(_TextXPos) ; return x pos
ret
;-------------------------------------------------------------------------------
gfx_GetTextY:
; Gets the Y position of the text cursor
; Arguments:
; None
; Returns:
; Y Text cursor posistion
ld hl,(_TextYPos) ; return y pos
ret
;-------------------------------------------------------------------------------
gfx_SetTextXY:
; Sets the text X and Y positions
; Arguments:
; arg0 : Text X Pos
; arg1 : Text Y Pos
; Returns:
; None
pop de ; de=return address, sp=&xpos
pop hl ; hl=xpos, sp=&ypos
ld (_TextXPos),hl
ex (sp),hl ; hl=ypos, ypos=don't care
ld (_TextYPos),hl
push hl ; xpos=don't care, sp=&xpos
ex de,hl ; hl=return address
;-------------------------------------------------------------------------------
_indcallHL:
; Calls HL
; Inputs:
; HL : Address to call
jp (hl)
;-------------------------------------------------------------------------------
gfx_SetTextBGColor:
; Sets the background text color for text routines
; Arguments:
; arg0 : Color index to set BG to
; Returns:
; Previous text color palette index
setSmcBytes _TextBGColor
;-------------------------------------------------------------------------------
gfx_SetTextFGColor:
; Sets the foreground text color for text routines
; Arguments:
; arg0 : Color index to set FG to
; Returns:
; Previous text color palette index
setSmcBytes _TextFGColor
;-------------------------------------------------------------------------------
gfx_SetTextTransparentColor:
; Sets the transparency text color for text routines
; Arguments:
; arg0 : Color index to set transparent text to
; Returns:
; Previous text color palette index
setSmcBytes _TextTPColor
;-------------------------------------------------------------------------------
gfx_SetFontHeight:
; Sets the height of the font in pixels
; Arguments:
; arg0 : New font height
; Returns:
; Previous font height
setSmcBytes _TextHeight
;-------------------------------------------------------------------------------
gfx_PrintStringXY:
; Places a string at the given coordinates
; Arguments:
; arg0 : Pointer to string
; arg1 : Text X Pos
; arg2 : Text Y Pos
; Returns:
; None
pop iy ; iy = return vector
pop bc ; bc = str
call gfx_SetTextXY
push bc
ex (sp),hl ; hl = str
push iy
; jr _DrawCharacters ; emulated by dummifying next instructions:
db $01 ; pop de \ ex (sp),hl \ push de -> ld bc,*
;-------------------------------------------------------------------------------
gfx_PrintString:
; Places a string at the current cursor position
; Arguments:
; arg0 : Pointer to string
; Returns:
; None
pop de
ex (sp),hl
push de
_DrawCharacters:
ld a,(hl) ; get the current character
or a,a
ret z
call _PrintChar
PrintChar_2 = $-3
inc hl ; move to the next one
jr _DrawCharacters
;-------------------------------------------------------------------------------
gfx_SetTextScale:
; Changes the amount of text scaling (note that height and width are independent)
; Arguments:
; arg0 : Width scale (1 is default)
; arg1 : Height scale (1 is default)
; Returns:
; None
pop de
pop hl
pop bc
push bc
push hl
push de
ld a,l
ld de,_TextWidthScale
ld hl,_TextScaleJump
cp a,c
jr z,.match
jr .nomatch
.match:
dec a
jr z,.bothone ; if they are both one; just use normal drawing
inc a
.nomatch:
or a,a
ret z ; null check
ld (de),a
ld a,c
or a,a
ret z ; null check
ld (_TextHeightScale),a
ld (hl),_PrintLargeFont - _PrintNormalFont
ret
.bothone:
ld (hl),a ; store a 0, which means no (literal) jump
inc a
ld (de),a
ret
;-------------------------------------------------------------------------------
gfx_SetTextConfig:
; Configures text depending on the arguments
; Arguments:
; arg0 : Configuration numbers
; Returns:
; None
pop de
ex (sp),hl ; hl = config
push de
dec l ; l = config - 1
ld hl,_PrintChar_Clip
jr z,.writesmc ; z ==> config == gfx_text_clip
; config == gfx_text_noclip
ld hl,_PrintChar
.writesmc: ; hl = PrintChar routine
ld (PrintChar_0),hl
ld (PrintChar_1),hl
ld (PrintChar_2),hl
ret
;-------------------------------------------------------------------------------
gfx_PrintChar:
; Places a character at the current cursor position
; Arguments:
; arg0 : Character to draw
; Returns:
; None
pop hl
pop de
push de
push hl
ld a,e ; a = char
jp _PrintChar ; this is SMC'd to use as a grappling hook into the clipped version
PrintChar_0 := $-3
_PrintChar:
push ix ; save stack pointer
push hl ; save hl pointer if string
ld e,a ; e = char
ld a,0
_TextFixedWidth = $-1
or a,a
jr nz,.fixed
sbc hl,hl
ld l,e ; hl = character
ld bc,(_CharSpacing)
add hl,bc
ld a,(hl) ; a = char width
.fixed:
ld bc,0
_TextXPos := $-3
sbc hl,hl
ld l,a
ld ixh,a ; ixh = char width
ld a,(_TextWidthScale)
ld h,a
mlt hl
add hl,bc
ld (_TextXPos),hl
ld hl,0
_TextYPos := $-3
ld h,LcdWidth/2
mlt hl
add hl,hl
add hl,bc
ld bc,(CurrentBuffer)
add hl,bc
ex de,hl ; de = draw location
ld a,l ; l = character
sbc hl,hl
ld l,a ; hl = character
add hl,hl
add hl,hl
add hl,hl
ld bc,(_TextData) ; get text data array
add hl,bc
ld iy,0
ld ixl,8
smcByte _TextHeight
wait_quick
jr _PrintLargeFont ; SMC the jump
_TextScaleJump := $ - 1
_PrintNormalFont:
.loop:
ld c,(hl) ; c = 8 pixels
add iy,de ; get draw location
lea de,iy
ld b,ixh
.nextpixel:
ld a,TEXT_BG_COLOR
smcByte _TextBGColor
rlc c
jr nc,.bgcolor
ld a,TEXT_FG_COLOR
smcByte _TextFGColor
.bgcolor:
cp a,TEXT_TP_COLOR ; check if transparent
smcByte _TextTPColor
jr z,.transparent
ld (de),a
.transparent:
inc de ; move to next pixel
djnz .nextpixel
ld de,LcdWidth
inc hl
dec ixl
jr nz,.loop
pop hl ; restore hl and stack pointer
pop ix
ret
;-------------------------------------------------------------------------------
_PrintLargeFont:
; Prints in scaled font for prosperity
; This is so that way unscaled font can still be reasonably fast
; Returns:
; None
.loop:
ld b,1
_TextHeightScale := $-1
push hl
ld c,(hl) ; c = 8 pixels
.hscale:
push bc
add iy,de ; get draw location
lea de,iy
ld b,ixh
.inner:
ld a,TEXT_BG_COLOR
smcByte _TextBGColor
ld l,1
_TextWidthScale := $-1
rlc c
jr nc,.bgcolor
ld a,TEXT_FG_COLOR
smcByte _TextFGColor
.bgcolor:
cp a,TEXT_TP_COLOR ; check if transparent
smcByte _TextTPColor
jr z,.fgcolor
.wscale0:
ld (de),a
inc de
dec l
jr nz,.wscale0
djnz .inner
jr .done
.fgcolor:
.wscale1:
inc de
dec l
jr nz,.wscale1 ; move to next pixel
djnz .inner
.done:
ld de,LcdWidth
pop bc
djnz .hscale
pop hl
inc hl
dec ixl
jr nz,.loop
pop hl ; restore hl and stack pointer
pop ix
ret
;-------------------------------------------------------------------------------
_PrintChar_Clip:
; Clipped text for characters printing routine
; Arguments:
; arg0 : Character to draw
; Returns:
; None
push hl ; save hl pointer if string
ld e,a ; e = char
ld a,(_TextFixedWidth)
or a,a
jr nz,.fixedwidth
sbc hl,hl
ld l,e ; hl = character
ld bc,(_CharSpacing)
add hl,bc
ld a,(hl) ; a = char width
.fixedwidth:
or a,a
sbc hl,hl
ld l,e ; hl = character
add hl,hl
add hl,hl
add hl,hl
ld bc,(_TextData) ; get text data array
add hl,bc ; de = draw location
ld de,_TmpCharData ; store pixel data into temporary sprite
ld iyl,8
smcByte _TextHeight
ld iyh,a ; ixh = char width
ld (_TmpCharSprite),a ; store width of character we are drawing
call _GetChar ; store the character data
ld bc,(_TextYPos)
push bc
ld bc,(_TextXPos) ; compute the new locations
push bc
or a,a
sbc hl,hl
ld a,iyh
ld l,a
add hl,bc
ld (_TextXPos),hl ; move the text x posisition by the character width
ld bc,_TmpCharSprite
push bc
call gfx_TransparentSprite ; use the actual routine
pop bc
pop bc
pop bc
pop hl ; restore hl and stack pointer
ret
;-------------------------------------------------------------------------------
gfx_PrintInt:
; Places an int at the current cursor position
; Arguments:
; arg0 : Number to print
; arg1 : Number of characters to print
; Returns:
; None
pop de
pop hl
push hl
push de
add hl,hl
db $3E ; xor a,a -> ld a,*
;-------------------------------------------------------------------------------
gfx_PrintUInt:
; Places an unsigned int at the current cursor position
; Arguments:
; arg0 : Number to print
; arg1 : Minimum number of characters to print
; Returns:
; None
xor a,a
pop de
pop hl ; hl = uint
pop bc ; c = min num chars
push bc
push hl
push de
jr nc,.begin ; c ==> actually a negative int
ex de,hl
or a,a
sbc hl,hl
sbc hl,de ; hl = -int
ld a,'-'
call .printchar
dec c
jr nz,.begin
inc c
.begin:
ld de,-10000000
call .num1
ld de,-1000000
call .num1
ld de,-100000
call .num1
ld de,-10000
call .num1
ld de,-1000
call .num1
ld de,-100
call .num1
ld de,-10
call .num1
ld de,-1
.num1:
xor a,a
.num2:
inc a
add hl,de
jr c,.num2
sbc hl,de
dec a ; a = next digit
jr nz,.printdigit ; z ==> digit is zero, maybe don't print
ld a,c
inc c
cp a,8
ret c ; nc ==> a digit has already been
; printed, or must start printing
; to satisfy min num chars
xor a,a
.printdigit:
add a,'0'
ld c,a ; mark that a digit has been printed
.printchar:
push bc
call _PrintChar
PrintChar_1 := $-3
pop bc
ret
;-------------------------------------------------------------------------------
gfx_GetStringWidth:
; Gets the width of a string
; Arguments:
; arg0 : Pointer to string
; Returns:
; Width of string in pixels
pop de
pop hl
push hl ; hl -> string
push de
ld de,0
.loop:
ld a,(hl)
or a,a
jr z,.done ; loop until null byte
push hl
call _GetCharWidth
ex de,hl
pop hl
inc hl
jr .loop
.done:
ex de,hl ; return width of string
ret
;-------------------------------------------------------------------------------
gfx_GetCharWidth:
; Gets the width of a character
; Arguments:
; arg0 : Character
; Returns:
; Width of character in pixels
ld iy,0
lea de,iy
add iy,sp
ld a,(iy+3) ; a = character
_GetCharWidth:
sbc hl,hl
ld l,a
ld a,(_TextFixedWidth) ; is fixed width
or a,a
jr nz,.fixed
ld bc,(_CharSpacing) ; lookup spacing
add hl,bc
ld a,(hl)
.fixed:
ld l,a
ld a,(_TextWidthScale) ; add scaling factor
ld h,a
mlt hl
add hl,de
ret
;-------------------------------------------------------------------------------
gfx_GetSpriteChar:
; Sets the data in char_sprite (must have previously allocated an 8x8 width sprite)
; the pixel map of the character c
; Arguments:
; arg0 : Pointer to allocated sprite
; arg1 : Character
; Returns:
; Pointer to sprite
pop hl
pop de
push de
push hl
ld a,(_TextFixedWidth)
or a,a
jr nz,.fixed
sbc hl,hl
ld l,e ; hl = character
ld bc,(_CharSpacing)
add hl,bc
ld a,(hl) ; a = char width
.fixed:
or a,a
sbc hl,hl
ld l,e ; hl = character
add hl,hl
add hl,hl
add hl,hl
ld bc,(_TextData) ; get text data array
add hl,bc ; de = draw location
ld de,_TmpCharSprite
ex de,hl
push hl ; save pointer to sprite
ld a,8
smcByte _TextHeight
ld iyh,a ; ixh = char width
ld (hl),a ; store width of character we are drawing
inc hl
ld iyl,a ; height of char
inc hl
ex de,hl
call _GetChar ; read the character into the array
pop hl
ret
;-------------------------------------------------------------------------------
_GetChar:
; Places a character data into a nice buffer
; Inputs:
; HL : Points to character pixmap
; DE : Points to output buffer
; Outputs:
; Stored pixmap image
; Uses IY
.loop:
ld c,(hl) ; c = 8 pixels (or width based)
ld b,iyh
.nextpixel:
ld a,TEXT_BG_COLOR
smcByte _TextBGColor
rlc c
jr nc,.bgcolor
ld a,TEXT_FG_COLOR
smcByte _TextFGColor
.bgcolor:
cp a,TEXT_TP_COLOR ; check if transparent
smcByte _TextTPColor
jr z,.transparent
ld (de),a
inc de
djnz .nextpixel
inc hl
dec iyl
jr nz,.loop
ret
.transparent:
ld a,0
smcByte _TransparentColor
ld (de),a
inc de ; move to next pixel
djnz .nextpixel
inc hl
dec iyl
jr nz,.loop ; okay we stored the character sprite now draw it
ret
;-------------------------------------------------------------------------------
gfx_SetFontData:
; Sets the font to be custom
; Arguments:
; arg0 : Pointer to font data
; Set Pointer to NULL to use default font
; Returns:
; Pointer to previous font data
pop de
pop hl
push hl ; hl -> custom font data
push de
add hl,de
or a,a
sbc hl,de
ld de,(_TextData)
jr nz,.nonnull ; if null make default font
ld hl,_DefaultTextData
.nonnull:
ld (_TextData),hl ; save pointer to custom font
ex de,hl
ret
;-------------------------------------------------------------------------------
gfx_SetCharData:
; Sets a custom font for a specific character
; Arguments:
; arg1 : Character index to change (0-127 or 0-255)
; arg0 : Pointer to character data; if null returns current data
; Returns:
; Pointer to character data if null, otherwise pointer to next character
ld iy,0
add iy,sp
ld hl,(iy+6) ; de -> custom character data
add hl,de
or a,a
sbc hl,de ; sets z flag if null
ex de,hl
or a,a
sbc hl,hl
ld l,(iy+3) ; hl = index
add hl,hl
add hl,hl
add hl,hl
ld bc,(_TextData)
add hl,bc
ret z
ld bc,8
ldir
ret
;-------------------------------------------------------------------------------
gfx_SetFontSpacing:
; Sets the font to be custom spacing
; Arguments:
; arg0 : Pointer to font spacing
; Set Pointer to NULL to use default font spacing
; Returns:
; None
pop de
pop hl
push hl ; hl -> custom font width
push de
add hl,de
or a,a
sbc hl,de
jr nz,.notnull ; if null make default font width
ld hl,_DefaultCharSpacing
.notnull:
ld (_CharSpacing),hl ; save pointer to custom widths
ret
;-------------------------------------------------------------------------------
gfx_SetMonospaceFont:
; Sets the font to be monospace
; Arguments:
; arg0 : Monospace spacing amount
; Returns:
; None
pop hl
pop de
push de
push hl
ld a,e ; a = width
ld (_TextFixedWidth),a ; store the value of the monospace width
ret
;-------------------------------------------------------------------------------
gfx_FillTriangle_NoClip:
; Draws a filled triangle without clipping
; Arguments:
; arg0-5 : x0,y0,x1,y1,x2,y2
; Returns:
; None
ld hl,gfx_HorizLine_NoClip
; jr _FillTriangle ; emulated by dummifying next instruction:
db $FD ; ld hl,* -> ld iy,*
;-------------------------------------------------------------------------------
gfx_FillTriangle:
; Draws a filled triangle with clipping
; Arguments:
; arg0-5 : x0,y0,x1,y1,x2,y2
; Returns:
; None
ld hl,gfx_HorizLine
_FillTriangle:
ld (.line0),hl
ld (.line1),hl
ld (.line2),hl