ref: f6038a3d52a2d26271fdcba9639284301305d751
parent: 5a14234b49e8870a33b80fb768928c194756255c
author: yenatch <yenatch@gmail.com>
date: Sun May 25 15:23:12 EDT 2014
Try to clean up PrepareOAMData.
--- /dev/null
+++ b/engine/oam_dma.asm
@@ -1,0 +1,25 @@
+WriteDMACodeToHRAM:
+; Since no other memory is available during OAM DMA,
+; DMARoutine is copied to HRAM and executed there.
+ ld c, $ff80 % $100
+ ld b, DMARoutineEnd - DMARoutine
+ ld hl, DMARoutine
+.copy
+ ld a, [hli]
+ ld [$ff00+c], a
+ inc c
+ dec b
+ jr nz, .copy
+ ret
+
+DMARoutine:
+ ; initiate DMA
+ ld a, $c3
+ ld [$ff46], a
+
+ ; wait for DMA to finish
+ ld a, $28
+.wait dec a
+ jr nz, .wait
+ ret
+DMARoutineEnd:
--- /dev/null
+++ b/engine/overworld/oam.asm
@@ -1,0 +1,178 @@
+PrepareOAMData:
+; Determine OAM data for currently visible
+; sprites and write it to wOAMBuffer.
+
+ ld a, [$cfcb]
+ dec a
+ jr z, .asm_4b1e
+
+ cp 0 - 1
+ ret nz
+ ld [$cfcb], a
+ jp HideSprites
+
+.asm_4b1e
+ xor a
+ ld [$ff90], a
+.asm_4b21
+ ld [$ff8f], a
+
+ ld d, wSpriteStateData1 / $100
+ ld a, [$ff8f]
+ ld e, a
+ ld a, [de] ; c1x0
+ and a
+ jp z, .asm_4bad
+
+ inc e
+ inc e
+ ld a, [de] ; c1x2 (facing/anim)
+ ld [$d5cd], a
+ cp $ff ; off-screen (don't draw)
+ jr nz, .visible
+
+ call Func_4bd1
+ jr .asm_4bad
+
+.visible
+ cp $a0
+ jr c, .usefacing
+ and $f
+ add $10
+ jr .asm_4b48
+
+.usefacing
+ and $f
+.asm_4b48
+ ld l, a
+
+ push de
+ inc d
+ ld a, e
+ add $5
+ ld e, a
+ ld a, [de] ; c2x7
+ and $80
+ ld [$ff94], a ; temp store sprite priority
+ pop de
+
+ ld h, 0
+ ld bc, SpriteFacingAndAnimationTable
+ add hl, hl
+ add hl, hl
+ add hl, bc
+
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ call Func_4bd1
+
+ ld a, [$ff90]
+ ld e, a
+ ld d, wOAMBuffer / $100
+.tile
+ ld a, [$ff92] ; temp for sprite Y position
+ add $10 ; Y=16 is top of screen (Y=0 is invisible)
+ add [hl] ; add Y offset from table
+ ld [de], a ; write new sprite OAM Y position
+ inc hl
+ ld a, [$ff91] ; temp for sprite X position
+ add $8 ; X=8 is left of screen (X=0 is invisible)
+ add [hl] ; add X offset from table
+ inc e
+ ld [de], a ; write new sprite OAM X position
+ inc e
+ ld a, [bc] ; read pattern number offset (accomodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
+ inc bc
+ push bc
+ ld b, a
+
+ ld a, [$d5cd] ; temp copy of c1x2
+ swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
+ and $f
+
+ ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
+ ; As a result, sprite $b's tile offset is less than normal.
+ cp $b
+ jr nz, .offset
+ ld a, $a * 12 + 4
+ jr .gotoffset
+
+.offset
+ ; a *= 12
+ sla a
+ sla a
+ ld c, a
+ sla a
+ add c
+.gotoffset
+ add b ; which frame
+ pop bc
+ ld [de], a ; tile id
+ inc hl
+ inc e
+ ld a, [hl]
+ bit 1, a ; sprite priority
+ jr z, .fg
+ ld a, [$ff94] ; facing priority
+ or [hl]
+.fg
+ inc hl
+ ld [de], a
+ inc e
+ bit 0, a ; OAMFLAG_ENDOFDATA
+ jr z, .tile
+
+ ld a, e
+ ld [$ff90], a
+
+.asm_4bad
+ ld a, [$ff8f]
+ add $10
+ cp $100 % $100
+ jp nz, .asm_4b21
+
+ ; Clear unused OAM.
+ ld a, [$ff90]
+ ld l, a
+ ld h, wOAMBuffer / $100
+ ld de, $4
+ ld b, $a0
+ ld a, [$d736]
+ bit 6, a
+ ld a, $a0
+ jr z, .clear
+ ld a, $90
+.clear
+ cp l
+ ret z
+ ld [hl], b
+ add hl, de
+ jr .clear
+
+Func_4bd1: ; 4bd1 (1:4bd1)
+ inc e
+ inc e
+ ld a, [de] ; c1x4
+ ld [$ff92], a
+ inc e
+ inc e
+ ld a, [de] ; c1x6
+ ld [$ff91], a
+ ld a, $4
+ add e
+ ld e, a
+ ld a, [$ff92]
+ add $4
+ and $f0
+ ld [de], a ; c1xa (y)
+ inc e
+ ld a, [$ff91]
+ and $f0
+ ld [de], a ; c1xb (x)
+ ret
--- a/main.asm
+++ b/main.asm
@@ -139,184 +139,8 @@
db "マスター@"
db "エクセレント"
-; calculates the OAM data for all currently visible sprites and writes it to wOAMBuffer
-PrepareOAMData: ; 4b0f (1:4b0f)
- ld a, [$cfcb]
- dec a
- jr z, .asm_4b1e
- cp $ff
- ret nz
- ld [$cfcb], a
- jp HideSprites
-.asm_4b1e
- xor a
- ld [$ff90], a
-.asm_4b21
- ld [$ff8f], a
- ld d, $c1
- ld a, [$ff8f]
- ld e, a
- ld a, [de] ; c1x0
- and a
- jp z, .asm_4bad
- inc e
- inc e
- ld a, [de] ; c1x2 read combined orientation and animation info
- ld [$d5cd], a
- cp $ff
- jr nz, .spriteVisible ; $ff -> offscreen, don't draw
- call Func_4bd1
- jr .asm_4bad
-.spriteVisible
- cp $a0
- jr c, .considerOrientation ; if >= $a0, ignore the sprite orientation and animation (by using a different conversion table)
- and $f
- add $10
- jr .asm_4b48
-.considerOrientation
- and $f ; the lower nybble contains orientation and animation info
-.asm_4b48
- ld l, a
- push de
- inc d
- ld a, e
- add $5
- ld e, a
- ld a, [de] ; c2x7
- and $80
- ld [$ff94], a ; temp store bit 7 for later use in OAM flags (draws sprite behind background (used for grass))
- pop de
- ld h, $0
- ld bc, SpriteFacingAndAnimationTable
- add hl, hl
- add hl, hl
- add hl, bc ; skip to the table location determined by orientation and animation
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call Func_4bd1
- ld a, [$ff90]
- ld e, a
- ld d, $c3 ; wOAMBuffer+x is buffer for OAM data
-.spriteTilesLoop ; loops 4 times for the 4 tiles a sprite consists of
- ld a, [$ff92] ; temp for sprite Y position
- add $10 ; Y=16 is top of screen (Y=0 is invisible)
- add [hl] ; add Y offset from table
- ld [de], a ; write new sprite OAM Y position
- inc hl
- ld a, [$ff91] ; temp for sprite X position
- add $8 ; X=8 is left of screen (X=0 is invisible)
- add [hl] ; add X offset from table
- inc e
- ld [de], a ; write new sprite OAM X position
- inc e
- ld a, [bc] ; read pattern number offset (accomodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
- inc bc
- push bc
- ld b, a
- ld a, [$d5cd] ; temp copy of c1x2
- swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
- and $f
- cp $b ; sprites $a and $b have no orientation or animation and therefore only 4 tiles
- jr nz, .calcTileOffset ; (instead of 12), so tile b's offset is a special case
- ld a, $7c ; = $a * 12 + 4
- jr .doneCalcTileOffset
-.calcTileOffset
- sla a
- sla a
- ld c, a
- sla a
- add c ; a *= 12 (each sprite consists of 12 tiles)
-.doneCalcTileOffset
- add b ; add orientation and animation offset
- pop bc
- ld [de], a ; write OAM sprite pattern number
- inc hl
- inc e
- ld a, [hl]
- bit 1, a ; bit 1 is ignored for OAM, it's used here as an "always in foregroud" flag.
- jr z, .alwaysInForeground
- ld a, [$ff94] ; load bit 7 (set to $80 if sprite is in grass and should be drawn behind it)
- or [hl]
-.alwaysInForeground
- inc hl
- ld [de], a ; write OAM sprite flags
- inc e
- bit 0, a ; test for OAMFLAG_ENDOFDATA
- jr z, .spriteTilesLoop
- ld a, e
- ld [$ff90], a
-.asm_4bad
- ld a, [$ff8f]
- add $10
- cp $0
- jp nz, .asm_4b21
- ld a, [$ff90]
- ld l, a
- ld h, $c3
- ld de, $4
- ld b, $a0
- ld a, [$d736]
- bit 6, a
- ld a, $a0
- jr z, .clearUnusedOAMEntriesLoop
- ld a, $90
-.clearUnusedOAMEntriesLoop
- cp l
- ret z
- ld [hl], b
- add hl, de
- jr .clearUnusedOAMEntriesLoop
-
-Func_4bd1: ; 4bd1 (1:4bd1)
- inc e
- inc e
- ld a, [de] ; c1x4
- ld [$ff92], a
- inc e
- inc e
- ld a, [de] ; c1x6
- ld [$ff91], a
- ld a, $4
- add e
- ld e, a
- ld a, [$ff92]
- add $4
- and $f0
- ld [de], a ; c1xa (sprite Y pos (snapped to whole steps (?))
- inc e
- ld a, [$ff91]
- and $f0
- ld [de], a ; c1xb (sprite X pos (snapped to whole steps (?))
- ret
-
-; copies DMA routine to HRAM. By GB specifications, all DMA needs to be done in HRAM (no other memory section is available during DMA)
-WriteDMACodeToHRAM: ; 4bed (1:4bed)
- ld c, $80
- ld b, $a
- ld hl, DMARoutine
-.copyLoop
- ld a, [hli]
- ld [$ff00+c], a
- inc c
- dec b
- jr nz, .copyLoop
- ret
-
-; this routine is copied to HRAM and executed there on every VBlank
-DMARoutine: ; 4bfb (1:4bfb)
- ld a, $c3
- ld [$ff46], a ; start DMA
- ld a, $28
-.waitLoop ; wait for DMA to finish
- dec a
- jr nz, .waitLoop
- ret
-
+INCLUDE "engine/overworld/oam.asm"
+INCLUDE "engine/oam_dma.asm"
PrintWaitingText:
FuncCoord 3, 10