Almost fully implemented text enginer

master
Jonatan Nilsson 2019-06-21 12:04:17 +00:00
parent d98ff62872
commit d95b9460d3
11 changed files with 304 additions and 77 deletions

Binary file not shown.

View File

@ -1 +1,66 @@
controller.asm
SECTION "ram_controller", WRAM0
controller_curkeys: ds 1
controller_newkeys: ds 1
SECTION "Controller", ROM0
InitController:
ld a, 0
ld [controller_curkeys], a
ld [controller_newkeys], a
ret
; Controller reading ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This controller reading routine is optimized for size.
; It stores currently pressed keys in controller_curkeys (1=pressed) and
; keys newly pressed since last read in controller_newkeys, with the same
; nibble ordering as the Game Boy Advance.
; 76543210
; |||||||+- A
; ||||||+-- B
; |||||+--- Select
; ||||+---- Start
; |||+----- Right
; ||+------ Left
; |+------- Up
; +-------- Down
; R
; L (just kidding)
UpdateController:
; Poll half the controller
ld a,P1F_4
call .onenibble
ld b,a ; B7-4 = 1; B3-0 = unpressed buttons
; Poll the other half
ld a,P1F_5
call .onenibble
swap a ; A3-0 = unpressed directions; A7-4 = 1
xor b ; A = pressed buttons + directions
ld b,a ; B = pressed buttons + directions
; And release the controller
ld a,P1F_N
ld [rP1],a
; Combine with previous controller_curkeys to make controller_newkeys
ld a, [controller_curkeys]
xor b ; A = keys that changed state
and b ; A = keys that changed to pressed
ld [controller_newkeys], a
ld a,b
ld [controller_curkeys], a
ret
.onenibble:
ldh [rP1],a ; switch the key matrix
ldh a,[rP1] ; ignore value while waiting for the key matrix to settle
ldh a,[rP1]
ldh a,[rP1]
ldh a,[rP1]
ldh a,[rP1]
ldh a,[rP1] ; the actual read
or $F0 ; A7-4 = 1; A3-0 = unpressed keys
ret

View File

@ -1,4 +1,5 @@
INCLUDE "game/text.asm"
INCLUDE "game/controller.asm"
SECTION "Game Loop", ROM0
@ -7,6 +8,7 @@ GameLoop:
call StartText
.mainloop
; Start our game loop
call UpdateController
call DrawActiveText
call WaitVBlank
jr .mainloop
@ -16,4 +18,6 @@ Section "Hello wrold string", ROM0
HelloWorldStr:
; [ ]
db "...wake up...\n"
db "please wake up...", 0
db "please wake up...#"
db "...we don't have\n"
db "time, wake up...", 0

View File

@ -1,19 +1,21 @@
SECTION "ram_textwriter", WRAM0
textwriter_curtext: ds 2
textwriter_curletter: ds 1
textwriter_posx: ds 1
textwriter_posy: ds 1
textwriter_curdelay: ds 1
textwriter_active: ds 1
textwriter_starting: ds 1
textwriter_ending: ds 1
textwriter_pausing: ds 1
SECTION "rom_textmap", ROM0,ALIGN[8]
textwriter_map:
; 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
db $50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50 ; 0
db $44,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50 ; 0
; 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
db $50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50,$50 ; 16
; 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
db $50,$41,$50,$50,$50,$50,$50,$43,$50,$50,$50,$50,$42,$50,$3F,$50 ; 32
db $50,$41,$50,$45,$50,$50,$50,$43,$50,$50,$50,$50,$42,$50,$3F,$50 ; 32
; 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
db $35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$50,$50,$50,$50,$50,$40 ; 48
; 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
@ -29,16 +31,15 @@ SECTION "TextWriter", ROM0
InitWindow:
; Fill first line in window with straight line
ld hl, _SCRN1
ld b, $20
ld hl, (_SCRN1 + 1)
ld b, 19
ld a, $52
call Memfill
; Fill rest of the area with dark bg
ld b, $40
ld a, $50
call Memfill
call ClearWindow
; Fill last line in window with straight line
ld b, $20
ld hl, (_SCRN1 + $61)
ld b, 19
ld a, $57
call Memfill
; Top left corner
@ -63,16 +64,26 @@ InitWindow:
ld [hl], $55
ld hl, _SCRN1 + $40 + 19
ld [hl], $55
; Some other common memory addresses that should be filled
ld a, 0
ld [textwriter_posx], a
ld [textwriter_posy], a
ld [textwriter_ending], a
ld [textwriter_pausing], a
ld [textwriter_active], a
ld [textwriter_curdelay], a
ld [textwriter_starting], a
ret ; Return
ClearWindow:
ld hl, (_SCRN1 + $21)
ld a, $50
ld b, $1E
ld b, 18
call Memfill
ld hl, (_SCRN1 + $41)
ld b, $1E
ld b, 18
call Memfill
ret
; Start to print a string on screen
; @param de - Address source string
@ -85,9 +96,10 @@ StartText:
ld a, 10
ld [textwriter_curdelay], a
ld a, 0
ld [textwriter_curletter], a
ld [textwriter_posx], a
ld [textwriter_posy], a
ld [textwriter_ending], a
ld [textwriter_pausing], a
ld a, 1
ld [textwriter_active], a
ld hl, textwriter_curtext
@ -96,6 +108,9 @@ StartText:
ld a, e
ld [hl], a
dec hl
ld a, 16
ld [textwriter_starting], a
call ClearWindow ; Clear it just in case
ret
; Draw text if one is currently active
@ -103,14 +118,83 @@ StartText:
DrawActiveText:
ld a, [textwriter_active] ; Check if text is currently active
and a
ret z
ret z ; If no text is active, just exit immediately
; Delay writing a letter by 10 frames
ld a, [textwriter_starting] ; Check if we're booting up the window
and a
jr z, .afterLoading ; Jump to after loading if we're not loading
; We are loading the window
ld a, [rWY] ; Get current window position
dec a ; Decrement twice (moves it slowly up)
dec a
ld [rWY], a ; Set the position back into window
ld a, [textwriter_starting]
dec a
ld [textwriter_starting], a
jr z, .afterLoading
ret
.afterLoading
ld a, [textwriter_ending] ; Check if we are ending
and a
jr z, .checkPausing ; If we are not ending, jump to check pause
; We are ending, animate the window back down
ld a, [rWY] ; Get current window position
inc a ; Increment twice
inc a
ld [rWY], a ; Set the position back into window
ld a, [textwriter_ending] ; Grab the ending guy
dec a ; Decrement it
ld [textwriter_ending], a ; Set it back
jr z, .closingAll ; If we reach zero, we can disable text renderer
ret
.closingAll
ld [textwriter_active], a
ret
.checkPausing
ld a, [textwriter_pausing] ; Check if we're in a paused state
and a
jr z, .checkDelay ; Jump to Delayer if we're not in paused state
ld b, a ; We are in pause state so store pause state in register b
ld a, [controller_newkeys] ; Check our controller
and a, PAD_A|PAD_B ; Check if we pressed either A or B
ret z ; Exit if he didn't
dec b ; Decrement B, our paused state
jr z, .continuingNextLine ; If paused state was 1 then we continue
;to render next line
; If we reach here, paused state was 2 which means we should
; end text reader
ld a, 16 ; Set a to 1
ld [textwriter_ending], a ; Mark it as we are ending
ret
.continuingNextLine
call ClearWindow
ld a, 0
ld [textwriter_pausing], a
ld [textwriter_posx], a
ld [textwriter_posy], a
jr .delayFinished
.checkDelay
; Delay writing a letter by 10 frames if no button is down
ld a, [textwriter_curdelay]
dec a
ld [textwriter_curdelay], a
ret nz
jr z, .delayFinished
ld a, [controller_curkeys] ; Check our controller
and a, PAD_B
ret z ; If B button is being held, we skip any delay
.delayFinished
; Reset the curdelay
ld a, 10
ld [textwriter_curdelay], a
@ -148,19 +232,28 @@ DrawActiveText:
ld a, [bc] ; Get the tile byte for the ASCII from the map
ld [hl], a ; Print the byte to the map
.checkIsEnding
ld a, [de]
and a ; Check if we reached the end
jr nz, .checkNewline
jr nz, .checkContinuing
; We have reached the end of the string, disable textwriter
ld b, 0 ; Disable repeater
ld a, 0
ld [textwriter_active], a
; We have reached the end of the string, mark it
ld a, 2
ld [textwriter_pausing], a
jr .continue ; Jump straight to continue. No need to check anything
.checkContinuing
ld a, [de] ; Regrab the ascii byte we printed
cp a, $23 ; Check if it's '#'
jr nz, .checkNewline ; Jump to next check if it wasn't
ld a, 1
ld [textwriter_pausing], a
jr .continue
.checkNewline
ld a, [de] ; Regrab the ascii byte we printed
cp a, $0A ; Check if it was a new line
cp a, $0A ; Check if it was a new line '\n'
jr nz, .checkRepeatOnce ; Jump to checkRepeatOnce if it wasn't a new line
; The byte we printed was a new line so we increment Y position
@ -171,15 +264,10 @@ DrawActiveText:
ld a, 1
ld [textwriter_posy], a ; Set our Y position to 1
ld [textwriter_curdelay], a ; Also set curdelay to 1 as well
; We already know we printed empty character so we can skip checking
; if we need to repeat once again and just set the b flag
ld b, 1
jr .continue
.checkRepeatOnce
ld a, [bc] ; Regrab the tile we printer
ld b, 0 ; Use b as our marker if we should repeat once
; Check if we printed an empty letter
cp a, $50
@ -200,10 +288,6 @@ DrawActiveText:
ld a, [textwriter_posx]
inc a
ld [textwriter_posx], a
; Update the current letter being drawn in ram
ld a, [textwriter_curletter]
inc a
ld [textwriter_curletter], a
.exit
ld a, [textwriter_active]

View File

@ -89,6 +89,7 @@ OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC)
; --
rP1 EQU $FF00
P1F_N EQU %00110000 ; P14-15 out port
P1F_5 EQU %00100000 ; P15 out port
P1F_4 EQU %00010000 ; P14 out port
P1F_3 EQU %00001000 ; P13 in port
@ -800,6 +801,15 @@ PADF_SELECT EQU $04
PADF_B EQU $02
PADF_A EQU $01
PAD_DOWN EQU $80
PAD_UP EQU $40
PAD_LEFT EQU $20
PAD_RIGHT EQU $10
PAD_START EQU $08
PAD_SELECT EQU $04
PAD_B EQU $02
PAD_A EQU $01
PADB_DOWN EQU $7
PADB_UP EQU $6
PADB_LEFT EQU $5

View File

@ -61,7 +61,7 @@ Start:
ld a, 7
ld [rWX], a
ld a, (SCRN_Y - 32)
ld a, SCRN_Y
ld [rWY], a
; Reset OAM memory with zeros
@ -70,7 +70,18 @@ Start:
ld b, $FEA0 - _OAMRAM ; Get the full size of the fill
call Memfill
; Reset WRAM memory with zeros
ld hl, _RAM ; Set position of OAM Ram to hl
ld a, $01 ; Fill that memory space with zero
ld bc, $E000 - _RAM ; Get the full size of the fill
call Memfill16
ld hl, _RAM ; Set position of OAM Ram to hl
ld a, $00 ; Fill that memory space with zero
ld bc, $E000 - _RAM ; Get the full size of the fill
call Memfill16
; Initialize other stuff
call InitController
call InitWindow
; Turn the screen on, display background

BIN
main.o

Binary file not shown.

BIN
test.gb

Binary file not shown.

View File

@ -1,46 +1,65 @@
ROM Bank #0 (HOME):
SECTION: $0200-$027F ($0080 bytes) ["rom_textmap"]
$0200 = textwriter_map
SECTION: $1280-$136C ($00ED bytes) ["TextWriter"]
$131D = DrawActiveText.drawletter
$1331 = DrawActiveText.checkNewline
$1353 = DrawActiveText.continue
$1347 = DrawActiveText.checkRepeatOnce
$12D3 = StartText
$12F1 = DrawActiveText
SECTION: $1280-$13EA ($016B bytes) ["TextWriter"]
$12D7 = ClearWindow
$132E = DrawActiveText.afterLoading
$1348 = DrawActiveText.checkPausing
$1344 = DrawActiveText.closingAll
$136E = DrawActiveText.checkDelay
$135E = DrawActiveText.continuingNextLine
$137D = DrawActiveText.delayFinished
$139C = DrawActiveText.drawletter
$13AE = DrawActiveText.checkContinuing
$13D8 = DrawActiveText.continue
$13BA = DrawActiveText.checkNewline
$13CE = DrawActiveText.checkRepeatOnce
$12EA = StartText
$1313 = DrawActiveText
$1280 = InitWindow
SECTION: $0031-$003E ($000E bytes) ["Game Loop"]
$0037 = GameLoop.mainloop
$0031 = GameLoop
SECTION: $0000-$001F ($0020 bytes) ["Hello wrold string"]
$0000 = HelloWorldStr
SECTION: $0020-$0030 ($0011 bytes) ["Tools"]
$0029 = Memfill
$002E = WaitVBlank
$0020 = Memcpy
$0029 = Memfill.repeatFill
SECTION: $0000-$0039 ($003A bytes) ["Controller"]
$0029 = UpdateController.onenibble
$0009 = UpdateController
$0000 = InitController
SECTION: $0166-$0176 ($0011 bytes) ["Game Loop"]
$016C = GameLoop.mainloop
$0166 = GameLoop
SECTION: $00BB-$00FC ($0042 bytes) ["Hello wrold string"]
$00BB = HelloWorldStr
SECTION: $0150-$0165 ($0016 bytes) ["Tools"]
$0159 = Memfill
$0163 = WaitVBlank
$0150 = Memcpy
$0159 = Memfill.repeatFill
$015E = Memfill16.repeatFill
$015E = Memfill16
SECTION: $0040-$0040 ($0001 bytes) ["InterruptVblank"]
SECTION: $0048-$0048 ($0001 bytes) ["InterruptLCDC"]
SECTION: $0050-$0050 ($0001 bytes) ["InterruptTimer_Overflow"]
SECTION: $0058-$0058 ($0001 bytes) ["InterruptSerial"]
SECTION: $0060-$0060 ($0001 bytes) ["Interruptp1thru4"]
SECTION: $0100-$014F ($0050 bytes) ["Header"]
SECTION: $0061-$00A1 ($0041 bytes) ["Intro code"]
SECTION: $0061-$00BA ($005A bytes) ["Intro code"]
$0061 = Start
SECTION: $0280-$127F ($1000 bytes) ["Font"]
$0280 = Page1
$1280 = Page1End
SLACK: $2DBE bytes
SLACK: $2CC3 bytes
WRAM Bank #0:
SECTION: $C000-$C006 ($0007 bytes) ["ram_textwriter"]
$C005 = textwriter_curdelay
$C002 = textwriter_curletter
$C003 = textwriter_posx
$C004 = textwriter_posy
$C006 = textwriter_active
SECTION: $C000-$C008 ($0009 bytes) ["ram_textwriter"]
$C002 = textwriter_posx
$C003 = textwriter_posy
$C007 = textwriter_ending
$C008 = textwriter_pausing
$C005 = textwriter_active
$C004 = textwriter_curdelay
$C006 = textwriter_starting
$C000 = textwriter_curtext
SLACK: $0FF9 bytes
SECTION: $C009-$C00A ($0002 bytes) ["ram_controller"]
$C00A = controller_newkeys
$C009 = controller_curkeys
SLACK: $0FF5 bytes
WRAM Bank #1:
EMPTY

View File

@ -1,26 +1,43 @@
; File generated by rgblink
00:0200 textwriter_map
00:131D DrawActiveText.drawletter
00:1331 DrawActiveText.checkNewline
00:1353 DrawActiveText.continue
00:1347 DrawActiveText.checkRepeatOnce
00:12D3 StartText
00:12F1 DrawActiveText
00:12D7 ClearWindow
00:132E DrawActiveText.afterLoading
00:1348 DrawActiveText.checkPausing
00:1344 DrawActiveText.closingAll
00:136E DrawActiveText.checkDelay
00:135E DrawActiveText.continuingNextLine
00:137D DrawActiveText.delayFinished
00:139C DrawActiveText.drawletter
00:13AE DrawActiveText.checkContinuing
00:13D8 DrawActiveText.continue
00:13BA DrawActiveText.checkNewline
00:13CE DrawActiveText.checkRepeatOnce
00:12EA StartText
00:1313 DrawActiveText
00:1280 InitWindow
00:0037 GameLoop.mainloop
00:0031 GameLoop
00:0000 HelloWorldStr
00:0029 Memfill
00:002E WaitVBlank
00:0020 Memcpy
00:0029 Memfill.repeatFill
00:0029 UpdateController.onenibble
00:0009 UpdateController
00:0000 InitController
00:016C GameLoop.mainloop
00:0166 GameLoop
00:00BB HelloWorldStr
00:0159 Memfill
00:0163 WaitVBlank
00:0150 Memcpy
00:0159 Memfill.repeatFill
00:015E Memfill16.repeatFill
00:015E Memfill16
00:0061 Start
00:0280 Page1
00:1280 Page1End
00:C005 textwriter_curdelay
00:C002 textwriter_curletter
00:C003 textwriter_posx
00:C004 textwriter_posy
00:C006 textwriter_active
00:C002 textwriter_posx
00:C003 textwriter_posy
00:C007 textwriter_ending
00:C008 textwriter_pausing
00:C005 textwriter_active
00:C004 textwriter_curdelay
00:C006 textwriter_starting
00:C000 textwriter_curtext
00:C00A controller_newkeys
00:C009 controller_curkeys

View File

@ -35,6 +35,23 @@ Memfill:
jr nz, .repeatFill
ret
Memfill16:
; Fill an area in memory at position hl with value a for bc amount of times
;
; @param hl - Starting address in memory to fill
; @param a - The value to fill said address space with
; @param b - How many bytes we should fill starting from said address space
; @return a - garbage
; @return b - PosX on where to draw text
; @return c - PosY on where to draw text
; @return hl - Workram position for text pointer
; @return de - Memory address to source string
.repeatFill
ld [hli], a
dec bc
jr nz, .repeatFill
ret
;;
; Waits for the vblank ISR to increment the count of vertical blanks.
; Will lock up if DI, vblank IRQ off, or LCD off.