705 lines
11 KiB
Plaintext
705 lines
11 KiB
Plaintext
; font.ms
|
|
;
|
|
; Michael Hope, 1999
|
|
; michaelh@earthling.net
|
|
; Distrubuted under the Artistic License - see www.opensource.org
|
|
;
|
|
.include "global.s"
|
|
INCLUDE "wait_hbl.mh"
|
|
|
|
.globl .cr_curs
|
|
.globl .adv_curs
|
|
.globl .cury, .curx
|
|
.globl .display_off
|
|
|
|
; Structure offsets
|
|
sfont_handle_sizeof = 3
|
|
sfont_handle_font = 1
|
|
sfont_handle_first_tile = 0
|
|
|
|
; Encoding types - lower 2 bits of font
|
|
FONT_256ENCODING = 0
|
|
FONT_128ENCODING = 1
|
|
FONT_NOENCODING = 2
|
|
|
|
; Other bits
|
|
FONT_BCOMPRESSED = 2
|
|
|
|
.CR = 0x0A ; Unix
|
|
.SPACE = 0x00
|
|
|
|
; Maximum number of fonts
|
|
.MAX_FONTS = 6
|
|
|
|
.area _HEADER (ABS)
|
|
|
|
.org .MODE_TABLE+4*.T_MODE
|
|
JP .tmode
|
|
|
|
.module font.ms
|
|
|
|
; Globals from drawing.s
|
|
; FIXME: Hmmm... check the linkage of these
|
|
.globl .fg_colour
|
|
.globl .bg_colour
|
|
|
|
.area _BSS
|
|
; The current font
|
|
font_current::
|
|
.ds sfont_handle_sizeof
|
|
; Cached copy of the first free tile
|
|
font_first_free_tile::
|
|
.ds 1
|
|
; Table containing descriptors for all of the fonts
|
|
font_table::
|
|
.ds sfont_handle_sizeof*.MAX_FONTS
|
|
|
|
.area _BASE
|
|
; Copy uncompressed 16 byte tiles from (BC) to (HL), length = DE*2
|
|
; Note: HL must be aligned on a UWORD boundry
|
|
font_copy_uncompressed::
|
|
ld a,d
|
|
or e
|
|
ret z
|
|
|
|
ld a,h
|
|
cp #0x98
|
|
jr c,4$
|
|
sub #0x98-0x88
|
|
ld h,a
|
|
4$:
|
|
xor a
|
|
cp e ; Special for when e=0 you will get another loop
|
|
jr nz,1$
|
|
dec d
|
|
1$:
|
|
WAIT_HBL
|
|
ld a,(bc)
|
|
ld (hl+),a
|
|
inc bc
|
|
|
|
WAIT_HBL
|
|
ld a,(bc)
|
|
ld (hl),a
|
|
inc bc
|
|
|
|
inc l
|
|
jr nz,2$
|
|
inc h
|
|
ld a,h ; Special wrap-around
|
|
cp #0x98
|
|
jr nz,2$
|
|
ld h,#0x88
|
|
2$:
|
|
dec e
|
|
jr nz,1$
|
|
dec d
|
|
bit 7,d ; -1?
|
|
jr z,1$
|
|
ret
|
|
|
|
; Copy a set of compressed (8 bytes/cell) tiles to VRAM
|
|
; Sets the foreground and background colours based on the current
|
|
; font colours
|
|
; Entry:
|
|
; From (BC) to (HL), length (DE) where DE = #cells * 8
|
|
; Uses the current fg_colour and bg_colour fields
|
|
font_copy_compressed::
|
|
ld a,d
|
|
or e
|
|
ret z ; Do nothing
|
|
|
|
ld a,h
|
|
cp #0x98 ; Take care of the 97FF -> 8800 wrap around
|
|
jr c,font_copy_compressed_loop
|
|
sub #0x98-0x88
|
|
ld h,a
|
|
font_copy_compressed_loop:
|
|
push de
|
|
ld a,(bc)
|
|
ld e,a
|
|
inc bc
|
|
push bc
|
|
|
|
ld bc,#0
|
|
; Do the background colour first
|
|
ld a,(.bg_colour)
|
|
bit 0,a
|
|
jr z,font_copy_compressed_bg_grey1
|
|
ld b,#0xFF
|
|
font_copy_compressed_bg_grey1:
|
|
bit 1,a
|
|
jr z,font_copy_compressed_bg_grey2
|
|
ld c,#0xFF
|
|
font_copy_compressed_bg_grey2:
|
|
; BC contains the background colour
|
|
; Compute what xoring we need to do to get the correct fg colour
|
|
ld d,a
|
|
ld a,(.fg_colour)
|
|
xor d
|
|
ld d,a
|
|
|
|
bit 0,d
|
|
jr z,font_copy_compressed_grey1
|
|
ld a,e
|
|
xor b
|
|
ld b,a
|
|
font_copy_compressed_grey1:
|
|
bit 1,d
|
|
jr z,font_copy_compressed_grey2
|
|
ld a,e
|
|
xor c
|
|
ld c,a
|
|
font_copy_compressed_grey2:
|
|
WAIT_HBL
|
|
ld (hl),b
|
|
inc hl
|
|
WAIT_HBL
|
|
ld (hl),c
|
|
inc hl
|
|
ld a,h ; Take care of the 97FFF -> 8800 wrap around
|
|
cp #0x98
|
|
jr nz,1$
|
|
ld h,#0x88
|
|
1$:
|
|
pop bc
|
|
pop de
|
|
dec de
|
|
ld a,d
|
|
or e
|
|
jr nz,font_copy_compressed_loop
|
|
ret
|
|
|
|
; Load the font HL
|
|
font_load::
|
|
call .display_off
|
|
push hl
|
|
|
|
; Find the first free font entry
|
|
ld hl,#font_table+sfont_handle_font
|
|
ld b,#.MAX_FONTS
|
|
font_load_find_slot:
|
|
ld a,(hl) ; Check to see if this entry is free
|
|
inc hl ; Free is 0000 for the font pointer
|
|
or (hl)
|
|
cp #0
|
|
jr z,font_load_found
|
|
|
|
inc hl
|
|
inc hl
|
|
dec b
|
|
jr nz,font_load_find_slot
|
|
pop hl
|
|
ld hl,#0
|
|
jr font_load_exit ; Couldn't find a free space
|
|
font_load_found:
|
|
; HL points to the end of the free font table entry
|
|
pop de
|
|
ld (hl),d ; Copy across the font struct pointer
|
|
dec hl
|
|
ld (hl),e
|
|
|
|
ld a,(font_first_free_tile)
|
|
dec hl
|
|
ld (hl),a
|
|
|
|
push hl
|
|
call font_set ; Set this new font to be the default
|
|
|
|
; Only copy the tiles in if were in text mode
|
|
ld a,(.mode)
|
|
and #.T_MODE
|
|
|
|
call nz,font_copy_current
|
|
|
|
; Increase the 'first free tile' counter
|
|
ld hl,#font_current+sfont_handle_font
|
|
ld a,(hl+)
|
|
ld h,(hl)
|
|
ld l,a
|
|
|
|
inc hl ; Number of tiles used
|
|
ld a,(font_first_free_tile)
|
|
add a,(hl)
|
|
ld (font_first_free_tile),a
|
|
|
|
pop hl ; Return font setup in HL
|
|
font_load_exit:
|
|
;; Turn the screen on
|
|
LDH A,(.LCDC)
|
|
OR #0b10000001 ; LCD = On
|
|
; BG = On
|
|
AND #0b11100111 ; BG Chr = 0x8800
|
|
; BG Bank = 0x9800
|
|
LDH (.LCDC),A
|
|
|
|
RET
|
|
|
|
; Copy the tiles from the current font into VRAM
|
|
font_copy_current::
|
|
; Find the current font data
|
|
ld hl,#font_current+sfont_handle_font
|
|
ld a,(hl+)
|
|
ld h,(hl)
|
|
ld l,a
|
|
|
|
inc hl ; Points to the 'tiles required' entry
|
|
ld e,(hl)
|
|
ld d,#0
|
|
rl e ; Multiple DE by 8
|
|
rl d
|
|
rl e
|
|
rl d
|
|
rl e
|
|
rl d ; DE has the length of the tile data
|
|
dec hl
|
|
|
|
ld a,(hl) ; Get the flags
|
|
push af
|
|
and #3 ; Only lower 2 bits set encoding table size
|
|
|
|
ld bc,#128
|
|
cp #FONT_128ENCODING ; 0 for 256 char encoding table, 1 for 128 char
|
|
jr z,font_copy_current_copy
|
|
|
|
ld bc,#0
|
|
cp #FONT_NOENCODING
|
|
jr z,font_copy_current_copy
|
|
|
|
ld bc,#256 ; Must be 256 element encoding
|
|
font_copy_current_copy:
|
|
inc hl
|
|
inc hl ; Points to the start of the encoding table
|
|
add hl,bc
|
|
ld c,l
|
|
ld b,h ; BC points to the start of the tile data
|
|
|
|
; Find the offset in VRAM for this font
|
|
ld a,(font_current+sfont_handle_first_tile) ; First tile used for this font
|
|
ld l,a
|
|
ld h,#0
|
|
add hl,hl
|
|
add hl,hl
|
|
add hl,hl
|
|
add hl,hl
|
|
|
|
ld a,#0x90 ; Tile 0 is at 9000h
|
|
add a,h
|
|
ld h,a
|
|
; Is this font compressed?
|
|
pop af ; Recover flags
|
|
bit FONT_BCOMPRESSED,a
|
|
; Do the jump in a mildly different way
|
|
jp z,font_copy_uncompressed
|
|
jp font_copy_compressed
|
|
|
|
; Set the current font to HL
|
|
font_set::
|
|
ld a,(hl+)
|
|
ld (font_current),a
|
|
ld a,(hl+)
|
|
ld (font_current+1),a
|
|
ld a,(hl+)
|
|
ld (font_current+2),a
|
|
ret
|
|
|
|
;; Print a character with interpretation
|
|
.put_char::
|
|
; See if it's a special char
|
|
cp #.CR
|
|
jr nz,1$
|
|
|
|
; Now see if were checking special chars
|
|
push af
|
|
ld a,(.mode)
|
|
and #.M_NO_INTERP
|
|
jr nz,2$
|
|
call .cr_curs
|
|
pop af
|
|
ret
|
|
2$:
|
|
pop af
|
|
1$:
|
|
CALL .set_char
|
|
CALL .adv_curs
|
|
RET
|
|
|
|
;; Print a character without interpretation
|
|
.out_char::
|
|
CALL .set_char
|
|
CALL .adv_curs
|
|
RET
|
|
|
|
;; Delete a character
|
|
.del_char::
|
|
CALL .rew_curs
|
|
LD A,#.SPACE
|
|
CALL .set_char
|
|
RET
|
|
|
|
;; Print the character in A
|
|
.set_char:
|
|
push af
|
|
ld a,(font_current+2)
|
|
; Must be non-zero if the font system is setup (cant have a font in page zero)
|
|
or a
|
|
jr nz,3$
|
|
|
|
; Font system is not yet setup - init it and copy in the ibm font
|
|
; Kind of a compatibility mode
|
|
call _font_init
|
|
|
|
; Need all of the tiles
|
|
xor a
|
|
ld (font_first_free_tile),a
|
|
|
|
.globl _font_load_ibm_fixed
|
|
call banked_call
|
|
.dw _font_load_ibm_fixed
|
|
.if __RGBDS__
|
|
.dw BANK(_font_load_ibm_fixed);
|
|
.else
|
|
.dw 0
|
|
.endif
|
|
3$:
|
|
pop af
|
|
push bc
|
|
push de
|
|
push hl
|
|
; Compute which tile maps to this character
|
|
ld e,a
|
|
ld hl,#font_current+sfont_handle_font
|
|
ld a,(hl+)
|
|
ld h,(hl)
|
|
ld l,a
|
|
ld a,(hl+)
|
|
and #3
|
|
cp #FONT_NOENCODING
|
|
jr z,set_char_no_encoding
|
|
inc hl
|
|
; Now at the base of the encoding table
|
|
; E is set above
|
|
ld d,#0
|
|
add hl,de
|
|
ld e,(hl) ; That's the tile!
|
|
set_char_no_encoding:
|
|
ld a,(font_current+0)
|
|
add a,e
|
|
ld e,a
|
|
|
|
LD A,(.cury) ; Y coordinate
|
|
LD L,A
|
|
LD H,#0x00
|
|
ADD HL,HL
|
|
ADD HL,HL
|
|
ADD HL,HL
|
|
ADD HL,HL
|
|
ADD HL,HL
|
|
LD A,(.curx) ; X coordinate
|
|
LD C,A
|
|
LD B,#0x00
|
|
ADD HL,BC
|
|
LD BC,#0x9800
|
|
ADD HL,BC
|
|
|
|
WAIT_HBL
|
|
LD (HL),E
|
|
POP HL
|
|
POP DE
|
|
POP BC
|
|
RET
|
|
|
|
.area _CODE
|
|
_putchar:: ; Banked
|
|
PUSH BC
|
|
LDA HL,.BANKOV+2(SP); Skip return address
|
|
LD A,(HL) ; A = c
|
|
CALL .put_char
|
|
POP BC
|
|
RET
|
|
|
|
_setchar:: ; Banked
|
|
PUSH BC
|
|
LDA HL,.BANKOV+2(SP); Skip return address
|
|
LD A,(HL) ; A = c
|
|
CALL .set_char
|
|
POP BC
|
|
RET
|
|
|
|
.area _BASE
|
|
_font_load::
|
|
push bc
|
|
LDA HL,4(SP) ; Skip return address and bc
|
|
LD A,(HL) ; A = c
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
call font_load
|
|
push hl
|
|
pop de ; Return in DE
|
|
pop bc
|
|
RET
|
|
|
|
_font_set::
|
|
push bc
|
|
LDA HL,4(SP) ; Skip return address
|
|
LD A,(HL) ; A = c
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a
|
|
call font_set
|
|
pop bc
|
|
ld de,#0 ; Always good...
|
|
RET
|
|
|
|
_font_init::
|
|
push bc
|
|
.globl .tmode
|
|
|
|
call .tmode
|
|
|
|
ld a,#1 ; We use the first tile as a space _always_
|
|
ld (font_first_free_tile),a
|
|
|
|
; Clear the font table
|
|
xor a
|
|
ld hl,#font_table
|
|
ld b,#sfont_handle_sizeof*.MAX_FONTS
|
|
1$:
|
|
ld (hl+),a
|
|
dec b
|
|
jr nz,1$
|
|
ld a,#3
|
|
ld (.fg_colour),a
|
|
ld a,#0
|
|
ld (.bg_colour),a
|
|
|
|
call .cls
|
|
pop bc
|
|
ret
|
|
|
|
_cls::
|
|
.cls::
|
|
PUSH DE
|
|
PUSH HL
|
|
LD HL,#0x9800
|
|
LD E,#0x20 ; E = height
|
|
1$:
|
|
LD D,#0x20 ; D = width
|
|
2$:
|
|
WAIT_HBL
|
|
|
|
LD (HL),#.SPACE ; Always clear
|
|
INC HL
|
|
DEC D
|
|
JR NZ,2$
|
|
DEC E
|
|
JR NZ,1$
|
|
POP HL
|
|
POP DE
|
|
RET
|
|
|
|
.area _CODE
|
|
; Support routines
|
|
_gotoxy:: ; Banked
|
|
lda hl,.BANKOV(sp)
|
|
ld a,(hl+)
|
|
ld (.curx),a
|
|
ld a,(hl)
|
|
ld (.cury),a
|
|
ret
|
|
|
|
_posx::
|
|
LD A,(.mode) ; Banked
|
|
AND #.T_MODE
|
|
JR NZ,1$
|
|
PUSH BC
|
|
CALL .tmode
|
|
POP BC
|
|
1$:
|
|
LD A,(.curx)
|
|
LD E,A
|
|
RET
|
|
|
|
_posy:: ; Banked
|
|
LD A,(.mode)
|
|
AND #.T_MODE
|
|
JR NZ,1$
|
|
PUSH BC
|
|
CALL .tmode
|
|
POP BC
|
|
1$:
|
|
LD A,(.cury)
|
|
LD E,A
|
|
RET
|
|
|
|
.area _BASE
|
|
;; Rewind the cursor
|
|
.rew_curs:
|
|
PUSH HL
|
|
LD HL,#.curx ; X coordinate
|
|
XOR A
|
|
CP (HL)
|
|
JR Z,1$
|
|
DEC (HL)
|
|
JR 99$
|
|
1$:
|
|
LD (HL),#.MAXCURSPOSX
|
|
LD HL,#.cury ; Y coordinate
|
|
XOR A
|
|
CP (HL)
|
|
JR Z,99$
|
|
DEC (HL)
|
|
99$:
|
|
POP HL
|
|
RET
|
|
|
|
.cr_curs::
|
|
PUSH HL
|
|
XOR A
|
|
LD (.curx),A
|
|
LD HL,#.cury ; Y coordinate
|
|
LD A,#.MAXCURSPOSY
|
|
CP (HL)
|
|
JR Z,2$
|
|
INC (HL)
|
|
JR 99$
|
|
2$:
|
|
CALL .scroll
|
|
99$:
|
|
POP HL
|
|
RET
|
|
|
|
.adv_curs::
|
|
PUSH HL
|
|
LD HL,#.curx ; X coordinate
|
|
LD A,#.MAXCURSPOSX
|
|
CP (HL)
|
|
JR Z,1$
|
|
INC (HL)
|
|
JR 99$
|
|
1$:
|
|
LD (HL),#0x00
|
|
LD HL,#.cury ; Y coordinate
|
|
LD A,#.MAXCURSPOSY
|
|
CP (HL)
|
|
JR Z,2$
|
|
INC (HL)
|
|
JR 99$
|
|
2$:
|
|
;; See if scrolling is disabled
|
|
LD A,(.mode)
|
|
AND #.M_NO_SCROLL
|
|
JR Z,3$
|
|
;; Nope - reset the cursor to (0,0)
|
|
XOR A
|
|
LD (.cury),A
|
|
LD (.curx),A
|
|
JR 99$
|
|
3$:
|
|
CALL .scroll
|
|
99$:
|
|
POP HL
|
|
RET
|
|
|
|
;; Scroll the whole screen
|
|
.scroll:
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD HL,#0x9800
|
|
LD BC,#0x9800+0x20 ; BC = next line
|
|
LD E,#0x20-0x01 ; E = height - 1
|
|
1$:
|
|
LD D,#0x20 ; D = width
|
|
2$:
|
|
LDH A,(.STAT)
|
|
AND #0x02
|
|
JR NZ,2$
|
|
|
|
LD A,(BC)
|
|
LD (HL+),A
|
|
INC BC
|
|
DEC D
|
|
JR NZ,2$
|
|
DEC E
|
|
JR NZ,1$
|
|
|
|
LD D,#0x20
|
|
3$:
|
|
LDH A,(.STAT)
|
|
AND #0x02
|
|
JR NZ,3$
|
|
|
|
LD A,#.SPACE
|
|
LD (HL+),A
|
|
DEC D
|
|
JR NZ,3$
|
|
POP HL
|
|
POP DE
|
|
POP BC
|
|
RET
|
|
|
|
.area _BSS
|
|
.curx:: ; Cursor position
|
|
.ds 0x01
|
|
.cury::
|
|
.ds 0x01
|
|
|
|
.area _BASE
|
|
|
|
.globl .vbl
|
|
.globl .lcd
|
|
.globl .int_0x40
|
|
.globl .int_0x48
|
|
.globl .remove_int
|
|
|
|
;; Enter text mode
|
|
.tmode::
|
|
DI ; Disable interrupts
|
|
|
|
;; Turn the screen off
|
|
LDH A,(.LCDC)
|
|
BIT 7,A
|
|
JR Z,1$
|
|
|
|
;; Turn the screen off
|
|
CALL .display_off
|
|
|
|
;; Remove any interrupts setup by the drawing routine
|
|
LD BC,#.vbl
|
|
LD HL,#.int_0x40
|
|
CALL .remove_int
|
|
LD BC,#.lcd
|
|
LD HL,#.int_0x48
|
|
CALL .remove_int
|
|
1$:
|
|
|
|
CALL .tmode_out
|
|
|
|
;; Turn the screen on
|
|
LDH A,(.LCDC)
|
|
OR #0b10000001 ; LCD = On
|
|
; BG = On
|
|
AND #0b11100111 ; BG Chr = 0x8800
|
|
; BG Bank = 0x9800
|
|
LDH (.LCDC),A
|
|
|
|
EI ; Enable interrupts
|
|
|
|
RET
|
|
|
|
;; Text mode (out only)
|
|
.tmode_out::
|
|
XOR A
|
|
LD (.curx),A
|
|
LD (.cury),A
|
|
|
|
;; Clear screen
|
|
CALL .cls
|
|
|
|
LD A,#.T_MODE
|
|
LD (.mode),A
|
|
|
|
RET
|