gbdk-releases/gbdk-lib/libc/gb/font.ms
2015-01-10 16:25:08 +01:00

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