The new system redraws the UI with a request system.
The entire UI tilemap is mirrored in wram where it can be updated
outside of blanks.
#define WINDOW_Y 112
#define WINDOW_X 1
+#define UI_TILE_WIDTH 20
+#define UI_TILE_HEIGHT 4
+
; defines end of scroll location
#define CURSOR_MIN_X 0
#define CURSOR_MAX_X 0xF8
.de act_dialog_opts, 2
.de act_size, 0
- ; max bge queue size
-#define BGE_MAX 4
-
- ; max bg updates per frame
-#define BG_UPDATE_MAX 8
-
- ; bg update flags
-.se 1
- ; sets a tile
-.de BGEF_TILE, 1
- ; sets BGE address
-.de BGEF_ADDR, 2
-
- ; bg update entry
-.se 0
- ; if flags is 00 the entry is skipped
-.de bge_flags, 1
-.de bge_new_tile, 1
-.de bge_addr, 2
-.de bge_size, 0
#define MAP_BG_TILE_OFFSET 0
#define MAP_BG_FLAGS_OFFSET 1
ret
- ; draws map title to UI (SCRN1)
+ ; draws map title to UI
; inputs:
; hl: map_ptr
map_draw_area_title:
add hl, de ; hl = map_name ptr
ld b, MAP_NAME_LEN
- ld de, SCRN1+1
+ ld de, shadow_ui+1
@loop:
ld a, [hl+]
add a, FONT_OFFSET
dec b
jr nz, @loop REL
+ call ui_request_redraw
+
ret
; gets the tile at a y/x position
@done:
ret
- ; prints a 0-terminated string to the update buffer
- ; can be called outside of blank
- ; inputs:
- ; hl: the string
- ; de: tile location
-bputs:
- ; the first char is special
- ld a, [hl+]
- cp a, 0
- jr z, @done REL ; if its 0 already skip
-
- ; if its not 0 write the address to the
- ; bg update queue
- add a, FONT_OFFSET
- ld b, a ; b = tile data for text
- ld a, BGEF_TILE | BGEF_ADDR
- ; de = tile address already
- push hl
- call bg_update_queue_push
- pop hl
-
-@loop:
-
- ; now we just push tiles
- ; with BGEF_TILE
- ld a, [hl+]
- cp a, 0 ; terminator?
- jr z, @done REL
-
- push hl
- add a, FONT_OFFSET
- ld b, a ; b = tile
- ld a, BGEF_TILE ; tile only mode
- ; no need to set location
- call bg_update_queue_push
- pop hl
-
- jr @loop REL
-@done:
- ret
-
; inits UI
ui_init:
+ ; fill shadow UI with default tile
+ ld hl, shadow_ui
+ ld bc, UI_TILE_WIDTH * UI_TILE_HEIGHT
+ ld d, UI_WINDOW_BACKGROUND
+ call memset
+
call ui_redraw_hp
+
+ call ui_request_redraw
ret
; updates HP UI
ui_redraw_hp:
ld hl, STR_TEST
- ld de, SCRN1 + 34
- call bputs
+ ld de, shadow_ui + 34
+ call puts
+
+ ret
+
+ ; requests a redraw
+ ; this will set up redraw_bg
+ ; redraw_shadow and redraw_steps
+ui_request_redraw:
+ ld hl, SCRN1
+ ld a, h
+ ld [ui_redraw_bg], a
+ ld a, l
+ ld [ui_redraw_bg+1], a
+
+ ld de, shadow_ui
+ ld a, d
+ ld [ui_redraw_shadow], a
+ ld a, e
+ ld [ui_redraw_shadow+1], a
+
+ ; steps of 5 * 16
+ ld a, 16
+ ld [ui_redraw_steps], a
+ ret
+
+#macro ui_redraw_vblank_write
+ ld a, [de]
+ inc de
+ ld [hl+], a
+#endmacro
+
+ ; redraws a UI step in vblank
+ui_redraw_vblank:
+ ld a, [ui_redraw_steps]
+ ; no more steps we bail
+ cp a, 0
+ ret z
+
+ ; steps--
+ dec a
+ ld [ui_redraw_steps], a
+
+ ; load bg ptr
+ ld a, [ui_redraw_bg]
+ ld h, a
+ ld a, [ui_redraw_bg+1]
+ ld l, a
+
+ ; load source address
+ ld a, [ui_redraw_shadow]
+ ld d, a
+ ld a, [ui_redraw_shadow+1]
+ ld e, a
+
+ ; write data
+ ; in an unrolled loop
+ ui_redraw_vblank_write
+ ui_redraw_vblank_write
+ ui_redraw_vblank_write
+ ui_redraw_vblank_write
+ ui_redraw_vblank_write
+
+ ; lastly store current ptr state again
+
+
+ ld a, d
+ ld [ui_redraw_shadow], a
+ ld a, e
+ ld [ui_redraw_shadow+1], a
+
+ ; skip 12 tiles ahead in BG
+ ; every other step
+ ld a, [ui_redraw_steps]
+ and a, 3
+ jr nz, @no_jump REL
+ ld de, 12
+ add hl, de
+@no_jump:
+ ld a, h
+ ld [ui_redraw_bg], a
+ ld a, l
+ ld [ui_redraw_bg+1], a
ret
+#undefine ui_redraw_vblank_write
; loads default map
new_game_init:
call video_fade_out
-
+
call shadow_oam_clear
+ call ui_init
+
call unit_load_default_player
; init initial map
ld a, WINDOW_X
ld [RWX], a
- call ui_init
-
; set up palettes for
; gameplay
ld a, BGP
ld a, [RLCD]
or a, LCDCF_OBJON
ld [RLCD], a
+
+ ; check ui update
+ call ui_redraw_vblank
; dma previous frame's oam
call OAMDMAFN
- call bg_update_queue_process
-
call scroll_write
; get inputs
jp memcpy
-
- ; bg update queue
- ; loads update_start tile address
- ; and updates tiles until the STOP flag is read
- ; of the loop countr is BGE_MAX
-bg_update_queue_process:
- ld de, bg_update_queue ; load initial entry
-
- ld b, BGE_MAX ; b == loop counter
- ; hl = target address
-
-@loop:
- ld a, [de] ; load flags
- ; thest big 1 (STOP)
- cp a, 0
- jr z, @skip REL ; skip this entry
-
- ; first test address set mode
- bit 1, a
- jr z, @no_addr_set REL
-
- push de
- push af
-
- ; load addr from entry
- inc de
- inc de
- ; get to addr
- ld a, [de]
- ld l, a
- inc de
- ld a, [de]
- ld h, a
- ; hl = new target address
-
- pop af
- pop de
-@no_addr_set:
- ; test tile set bit
- bit 0, a
- jr z, @no_tile_wirte REL
-
- inc de
-
- ; write new tile and inc hl
- ld a, [de]
- ld [hl+], a
-
- dec de
-
-@no_tile_wirte:
-@skip:
- ; advance to next entry
- inc de
- inc de
- inc de
- inc de
- dec b ; b--
- jr nz, @loop REL
-
-
- ; advance to queue clear
-
- ; clears the bg update queue
- ; sets update index to 0
-bg_update_queue_clear:
- xor a, a
- ld [bg_update_index], a
-
- ; clear all entries
- ld hl, bg_update_queue
- ld bc, bge_size * BGE_MAX
- ld d, a ; d = 0
- jp memset
-
- ; pushes a new bg update to the queue
- ; inputs:
- ; b: tile data
- ; a: entry flags
- ; de: address (unused unless in BGEF_ADDR mode)
- ; returns:
- ; a == 1: if update was queued
- ; a == 0: if queue is full
-bg_update_queue_push:
- push af
- push bc
-
- ; first calculate address in queue
- ld a, [bg_update_index]
- cp a, BGE_MAX
- jp z, @full
-
- add a, a
- add a, a
- ; a * 4
- ld b, 0
- ld c, a ; de = index offset
-
- ld hl, bg_update_queue
- add hl, bc
-
- pop bc
- pop af
-
- ; write flags
- ld [hl+], a
- ld a, b
- ; write tile data
- ld [hl+], a
-
- ; write address
- ld a, e
- ld [hl+], a
- ld a, d
- ld [hl], a
-
- ; index++
- ld a, [bg_update_index]
- inc a
- ld [bg_update_index], a
-
- ld a, 1
- ret
-@full:
- xor a, a ; queue was full
- ret
; menu cursor can be used by any in-game menu
menu_cursor_index: .adv 1
- ; offset into bg_update_queue
-bg_update_index: .adv 1 ; current entry
-bg_update_queue: .adv bge_size * BGE_MAX
-
draw_flags: .adv 1
gameplay_flags: .adv 1
+
+ ; shadow UI is a buffer for drawing the UI
+ ; this UI is then re-drawn on request in vblank
+shadow_ui: .adv UI_TILE_WIDTH * UI_TILE_HEIGHT
+
+; UI redraw BG address
+ui_redraw_bg: .adv 2
+; UI redraw shadow address
+ui_redraw_shadow: .adv 2
+; remaining UI redraw steps
+ui_redraw_steps: .adv 1
; dummy oam
; same memory as empty_unit