Browse Source

Complete map scrolling algorithm

master
Forest Belton 3 years ago
parent
commit
fd5911f42e
1 changed files with 200 additions and 159 deletions
  1. +200
    -159
      src/map.s

+ 200
- 159
src/map.s View File

@ -4,13 +4,16 @@ INCLUDE "util.inc"
SECTION "Map Data", WRAM0 SECTION "Map Data", WRAM0
DEF ROW_BUFFER_SIZE EQUS "SCRN_X_B + 4"
DEF COL_BUFFER_SIZE EQUS "SCRN_Y_B + 4"
SCROLL_DIR:: DB SCROLL_DIR:: DB
PENDING_ROW_PTR:: DW ; Where to write pending row data (0 = no write) PENDING_ROW_PTR:: DW ; Where to write pending row data (0 = no write)
PENDING_ROW_DATA:: DS SCRN_VX_B ; Row to be written
PENDING_ROW_DATA:: DS ROW_BUFFER_SIZE ; Row to be written
PENDING_COL_PTR:: DW ; Where to write pending column data (0 = no write) PENDING_COL_PTR:: DW ; Where to write pending column data (0 = no write)
PENDING_COL_DATA: DS SCRN_VY_B ; Column to be written
PENDING_COL_DATA: DS COL_BUFFER_SIZE ; Column to be written
CURRENT_DATA_START:: CURRENT_DATA_START::
CURRENT_TILE_PTR:: DW ; Location of tile data CURRENT_TILE_PTR:: DW ; Location of tile data
@ -82,77 +85,6 @@ Map_Load::
ret ret
; Loads the map X-coordinate into B
MACRO LOAD_MAPX
; if SCX <= 0x7f
; ld a, [rSCX]
; cp $80
; jr nc, .wrap\@
; B = CAMERA_X - SCX/8
ld a, [rSCX]
ld b, a
ld a, [CURRENT_CAMERA_X]
srln b, 3
sub b
ld b, a
; jr .done\@
; else SCX > 0x7f
; .wrap\@:
; ; B = CAMERA_X - PAGE_X/8
; ld a, [PAGEX]
; ld b, a
; ld a, [CURRENT_CAMERA_X]
; srln b, 3
; sub b
; ld b, a
; ; HL += PAGE_X/8
; ld a, [PAGEX]
; srln a, 3
; ADD16 hl
; .done\@:
ENDM
; Loads the map Y-coordinate into C
MACRO LOAD_MAPY
; if SCY <= 0x7f
; ld a, [rSCY]
; cp $80
; jr nc, .wrap\@
; C = CAMERA_Y - SCY/8
ld a, [rSCY]
ld c, a
ld a, [CURRENT_CAMERA_Y]
srln c, 3
sub c
ld c, a
; jr .done\@
; ; else SCY > 0x7f
; .wrap\@:
; ; C = CAMERA_Y - SCY/8
; ld a, [PAGEY]
; ld c, a
; ld a, [CURRENT_CAMERA_Y]
; srln c, 3
; sub c
; ld c, a
; ; HL += 32 * PAGE_Y/8
; ld d, 0
; ld a, [PAGEY]
; ld e, a
; REPT 5
; SLA16 de
; ENDR
; add hl, de
; .done\@:
ENDM
; Update map state based on SCX/SCY ; Update map state based on SCX/SCY
Map_Scroll:: Map_Scroll::
; Check scroll up/down ; Check scroll up/down
@ -165,7 +97,10 @@ Map_Scroll::
and %111 and %111
ret nz ret nz
LOAD_MAPX
; B = CAMERA_X - 2
ld a, [CURRENT_CAMERA_X]
sub 2
ld b, a
ld a, [SCROLL_DIR] ld a, [SCROLL_DIR]
cp DIRB_UP cp DIRB_UP
@ -176,12 +111,10 @@ Map_Scroll::
sub 2 sub 2
ld c, a ld c, a
; HL = _SCRN0 + 32 * ((SCX/8 - 2) % 32)
ld a, [rSCX]
; MAP Y = SCY/8 - 2
ld a, [rSCY]
srln a, 3 srln a, 3
sub 2 sub 2
and %11111
call get_row_ptr
jr .write_row jr .write_row
@ -191,13 +124,24 @@ Map_Scroll::
add SCRN_Y_B + 1 add SCRN_Y_B + 1
ld c, a ld c, a
; HL = _SCRN0 + 32 * (SCY/8 + SCRN_Y_B + 1)
; MAP Y = SCY/8 + SCRN_Y_B + 1
ld a, [rSCY] ld a, [rSCY]
srln a, 3 srln a, 3
add SCRN_Y_B + 1 add SCRN_Y_B + 1
call get_row_ptr
.write_row: .write_row:
and %11111
call get_row_ptr
ld a, [rSCX]
sub 16
srl a
srl a
srl a
ld e, a
ld d, 0
add hl, de
call enqueue_row_write call enqueue_row_write
ret ret
@ -207,43 +151,51 @@ Map_Scroll::
and %111 and %111
ret nz ret nz
LOAD_MAPY
; C = CAMERA_Y - 2
ld a, [CURRENT_CAMERA_Y]
sub 2
ld c, a
ld a, [rSCY]
sub 16
srl a
srl a
srl a
call get_row_ptr
ld a, [SCROLL_DIR] ld a, [SCROLL_DIR]
cp DIRB_LEFT cp DIRB_LEFT
jr nz, .scroll_right jr nz, .scroll_right
; HL = VRAM + (SCX/8 - 2) % 32
ld hl, _SCRN0
ld a, [rSCX]
srln a, 3
sub 2
and %11111
ADD16 hl
; B = CAMERA_X - 2 ; B = CAMERA_X - 2
ld a, [CURRENT_CAMERA_X] ld a, [CURRENT_CAMERA_X]
sub 2 sub 2
ld b, a ld b, a
; HL = VRAM + (SCX/8 - 2)
ld a, [rSCX]
srln a, 3
sub 2
jr .write_col jr .write_col
.scroll_right: .scroll_right:
; B = CAMERA_X + 20 + 1
ld a, [CURRENT_CAMERA_X]
add SCRN_X_B + 1
ld b, a
; HL = VRAM + SCX/8 + SCRN_X_B + 1 ; HL = VRAM + SCX/8 + SCRN_X_B + 1
ld hl, _SCRN0
ld a, [rSCX] ld a, [rSCX]
srl a srl a
srl a srl a
srl a srl a
add SCRN_X_B + 1 add SCRN_X_B + 1
ADD16 hl
; B = CAMERA_X + 20 + 1
ld a, [CURRENT_CAMERA_X]
add SCRN_X_B + 1
ld b, a
.write_col: .write_col:
and %11111
ADD16 hl
call enqueue_col_write call enqueue_col_write
ret ret
@ -257,7 +209,7 @@ Map_Update::
jr z, .update_col jr z, .update_col
ld hl, PENDING_ROW_DATA ld hl, PENDING_ROW_DATA
ld d, SCRN_VX_B
ld d, ROW_BUFFER_SIZE
.copy_row: .copy_row:
ld a, [hl+] ld a, [hl+]
ld [bc], a ld [bc], a
@ -289,7 +241,7 @@ Map_Update::
or c or c
ret z ret z
ld d, SCRN_VY_B
ld d, COL_BUFFER_SIZE
ld hl, PENDING_COL_DATA ld hl, PENDING_COL_DATA
.update_col_loop: .update_col_loop:
ld a, [hl+] ld a, [hl+]
@ -367,7 +319,7 @@ enqueue_row_write:
.copy_map_row: .copy_map_row:
; C = BYTES_LEFT ; C = BYTES_LEFT
ld c, SCRN_VX_B
ld c, ROW_BUFFER_SIZE
ld de, PENDING_ROW_DATA ld de, PENDING_ROW_DATA
; If X > 0, increment map pointer by X ; If X > 0, increment map pointer by X
@ -378,15 +330,18 @@ enqueue_row_write:
ADD16 hl ADD16 hl
jr .copy_middle jr .copy_middle
; Note: Can skip checking BYTES_LEFT > 0 in this loop. If there were
; SCRN_VX_B zeros to write, then Y would be 1 greater and we would have
; jumped into .zero_row before reaching this code
.pad_left: .pad_left:
; Check X < 0 ; Check X < 0
bit 7, b bit 7, b
jr z, .copy_middle jr z, .copy_middle
; Check BYTES_LEFT > 0
ld a, c
or a
ret z
; *ROW++ = 0 ; *ROW++ = 0
xor a
ld [de], a ld [de], a
inc de inc de
@ -436,7 +391,7 @@ enqueue_row_write:
.zero_row: .zero_row:
ld hl, PENDING_ROW_DATA ld hl, PENDING_ROW_DATA
xor a xor a
ld c, SCRN_VX_B
ld c, ROW_BUFFER_SIZE
.zero_row_loop: .zero_row_loop:
ld [hl+], a ld [hl+], a
dec c dec c
@ -456,17 +411,7 @@ write_map_row:
push de push de
push hl push hl
call enqueue_row_write
ld a, [PENDING_ROW_PTR]
ld c, a
ld a, [PENDING_ROW_PTR + 1]
ld b, a
; TODO: Fix
ld hl, PENDING_ROW_DATA
ld d, SCRN_VX_B
MEMCPY bc, hl, d
call init_row_write
pop hl pop hl
pop de pop de
@ -493,43 +438,30 @@ enqueue_col_write:
; If X >= MAP_WIDTH, write 0s ; If X >= MAP_WIDTH, write 0s
ld a, [CURRENT_MAP_WIDTH] ld a, [CURRENT_MAP_WIDTH]
dec a dec a
cp c
cp b
jr c, .zero_row jr c, .zero_row
; HL = CURRENT_MAP_PTR
; HL = CURRENT_MAP_PTR + X
ld a, [CURRENT_MAP_PTR] ld a, [CURRENT_MAP_PTR]
ld l, a ld l, a
ld a, [CURRENT_MAP_PTR + 1] ld a, [CURRENT_MAP_PTR + 1]
ld h, a ld h, a
; HL = CURRENT_MAP_PTR + Y * MAP_WIDTH + X
ld d, 0
ld a, [CURRENT_MAP_WIDTH]
ld e, a
ld a, c
.get_map_col_ptr:
or a
jr z, .copy_map_column
add hl, de
dec a
jr .get_map_col_ptr
.copy_map_column:
ld a, b ld a, b
ADD16 hl ADD16 hl
; B = BYTES_LEFT ; B = BYTES_LEFT
ld b, SCRN_VY_B
ld b, COL_BUFFER_SIZE
ld de, PENDING_COL_DATA ld de, PENDING_COL_DATA
; Note: Can skip checking BYTES_LEFT > 0 in this loop. If there were
; SCRN_VY_B zeros to write, then X would be 1 greater and we would have
; jumped into .zero_row before reaching this code
.pad_left: .pad_left:
; Check Y < 0 ; Check Y < 0
bit 7, c bit 7, c
jr z, .copy_middle
jr z, .adjust_hl
; Check BYTES_LEFT > 0
ld a, b
or a
ret z
; *ROW++ = 0 ; *ROW++ = 0
xor a xor a
@ -541,6 +473,25 @@ enqueue_col_write:
dec b dec b
jr .pad_left jr .pad_left
.adjust_hl:
push de
; HL += Y * MAP_WIDTH
ld d, 0
ld a, [CURRENT_MAP_WIDTH]
ld e, a
ld a, c
.get_map_col_ptr:
or a
jr z, .done_get_col_map_ptr
add hl, de
dec a
jr .get_map_col_ptr
.done_get_col_map_ptr:
pop de
.copy_middle: .copy_middle:
; Check Y < MAP_HEIGHT ; Check Y < MAP_HEIGHT
ld a, [CURRENT_MAP_HEIGHT] ld a, [CURRENT_MAP_HEIGHT]
@ -586,43 +537,133 @@ enqueue_col_write:
.zero_row: .zero_row:
ld hl, PENDING_COL_DATA ld hl, PENDING_COL_DATA
xor a xor a
ld c, SCRN_VY_B
ld c, COL_BUFFER_SIZE
.zero_row_loop: .zero_row_loop:
ld [hl+], a ld [hl+], a
dec c dec c
jr nz, .zero_row_loop jr nz, .zero_row_loop
ret ret
; Compute the distance (modulo 32) between two values
; @param b Value 1
; @param c Value 2
mmd2:
push bc
ld a, b
sub c
; Basically enqueue_col_write but for entire row, used during map load
; TODO: Deduplicate
; @param b Map X coordinate (signed)
; @param c Map Y coordinate (signed)
; @param hl Where to write the column in map VRAM
; @destroy All registers
init_row_write:
; If Y < 0, write 0s
bit 7, c
jr nz, .zero_row
cpl
ld b, a
cpl
; If Y >= MAP_HEIGHT, write 0s
ld a, [CURRENT_MAP_HEIGHT]
dec a
cp c
jr c, .zero_row
; DE = HL
ld d, h
ld e, l
; HL = CURRENT_MAP_PTR
ld a, [CURRENT_MAP_PTR]
ld l, a
ld a, [CURRENT_MAP_PTR + 1]
ld h, a
push de
; HL = CURRENT_MAP_PTR + Y * MAP_WIDTH
ld d, 0
ld a, [CURRENT_MAP_WIDTH]
ld e, a
ld a, c
.get_map_row_ptr:
or a
jr z, .copy_map_row
add hl, de
dec a
jr .get_map_row_ptr
.copy_map_row:
pop de
; C = BYTES_LEFT
ld c, SCRN_VX_B
; If X > 0, increment map pointer by X
; TODO: Remove this branch by adding X before copy_middle
bit 7, b bit 7, b
jr z, .0
jr nz, .pad_left
ld b, a
ld a, b
ADD16 hl
jr .copy_middle
.pad_left:
; Check X < 0
bit 7, b
jr z, .copy_middle
; Check BYTES_LEFT > 0
ld a, c
or a
ret z
.0:
ld a, 32
sub b
; *ROW++ = 0
ld [de], a
inc de
; X++, BYTES_LEFT--
inc b
dec c
jr .pad_left
.copy_middle:
; Check X < MAP_WIDTH
ld a, [CURRENT_MAP_WIDTH]
dec a
cp b cp b
jr nc, .1
jr c, .pad_right
pop bc
ret
; Check BYTES_LEFT > 0
ld a, c
or a
ret z
.1:
ld a, b
; *ROW++ = *MAP++
ld a, [hl+]
ld [de], a
inc de
pop bc
ret
; X++, BYTES_LEFT--
inc b
dec c
jr .copy_middle
.pad_right:
; Check BYTES_LEFT > 0
ld a, c
or a
ret z
; *ROW++ = 0
xor a
ld [de], a
inc de
; X++, BYTES_LEFT--
inc b
dec c
jr .pad_right
.zero_row:
xor a
ld c, SCRN_VX_B
.zero_row_loop:
ld [hl+], a
dec c
jr nz, .zero_row_loop
ret

Loading…
Cancel
Save