203 lines
5.0 KiB
NASM
203 lines
5.0 KiB
NASM
; Sprite Objects Library - by Eievui
|
|
;
|
|
; This is a small, lightweight library meant to facilitate the rendering of
|
|
; sprite objects, including Shadow OAM and OAM DMA, single-entry "simple" sprite
|
|
; objects, and Q12.4 fixed-point position metasprite rendering.
|
|
;
|
|
; The library is only 127 bytes of ROM0, 160 bytes of WRAM0 for Shadow OAM, and a
|
|
; single HRAM byte for tracking the current position in OAM.
|
|
;
|
|
; The library is relatively simple to use, with 4 steps to rendering:
|
|
; 1. Call InitSprObjLib during initilizations - This copies the OAMDMA function to
|
|
; HRAM.
|
|
; 2. Call ResetShadowOAM at the beginning of each frame - This hides all sprites
|
|
; and resets hOAMIndex, allowing you to render a new frame of sprites.
|
|
; 3. Call rendering functions - Push simple sprites or metasprites to Shadow OAM.
|
|
; 4. Wait for VBlank and call hOAMDMA - Copies wShadowOAM to the Game Boy's OAM in
|
|
; just 160 M-cycles. Make sure to pass HIGH(wShadowOAM) in the a register.
|
|
;
|
|
; Copyright 2021, Eievui
|
|
;
|
|
; This software is provided 'as-is', without any express or implied
|
|
; warranty. In no event will the authors be held liable for any damages
|
|
; arising from the use of this software.
|
|
;
|
|
; Permission is granted to anyone to use this software for any purpose,
|
|
; including commercial applications, and to alter it and redistribute it
|
|
; freely, subject to the following restrictions:
|
|
;
|
|
; 1. The origin of this software must not be misrepresented; you must not
|
|
; claim that you wrote the original software. If you use this software
|
|
; in a product, an acknowledgment in the product documentation would be
|
|
; appreciated but is not required.
|
|
; 2. Altered source versions must be plainly marked as such, and must not be
|
|
; misrepresented as being the original software.
|
|
; 3. This notice may not be removed or altered from any source distribution.
|
|
;
|
|
|
|
INCLUDE "hardware.inc"
|
|
|
|
SECTION "OAM DMA Code", ROM0
|
|
OAMDMACode::
|
|
LOAD "OAM DMA", HRAM
|
|
; Begin an OAM DMA, waiting 160 cycles for the DMA to finish.
|
|
; This quickly copies Shadow OAM to the Game Boy's OAM, allowing the PPU to draw
|
|
; the objects. hOAMDMA should be called once per frame near the end of your
|
|
; VBlank interrupt. While an OAM DMA is running no sprites objects can be drawn
|
|
; by the PPU, which makes it preferrable to run within the VBlank interrupt, but
|
|
; it can be run at any point if more than 40 sprite objects are needed.
|
|
; @param a: High byte of active Shadow OAM. Shadow OAM must be aligned to start
|
|
; at the beginning of a page (low byte == $00).
|
|
hOAMDMA::
|
|
ldh [rDMA], a
|
|
ld a, 40
|
|
.wait
|
|
dec a
|
|
jr nz, .wait
|
|
ret
|
|
ENDL
|
|
OAMDMACodeEnd::
|
|
|
|
SECTION "Initialize Sprite Object Library", ROM0
|
|
; Initializes the sprite object library, copying things such as the hOAMDMA
|
|
; function and reseting hOAMIndex
|
|
; @clobbers: a, bc, hl
|
|
InitSprObjLib::
|
|
; Copy OAM DMA.
|
|
ld b, OAMDMACodeEnd - OAMDMACode
|
|
ld c, LOW(hOAMDMA)
|
|
ld hl, OAMDMACode
|
|
.memcpy
|
|
ld a, [hli]
|
|
ldh [c], a
|
|
inc c
|
|
dec b
|
|
jr nz, .memcpy
|
|
xor a, a
|
|
ldh [hOAMIndex], a ; hOAMIndex must be reset before running ResetShadowOAM.
|
|
ret
|
|
|
|
SECTION "Reset Shadow OAM", ROM0
|
|
; Reset the Y positions of every sprite object that was used in the last frame,
|
|
; effectily hiding them, and reset hOAMIndex. Run this function each frame
|
|
; before rendering sprite objects.
|
|
; @clobbers: a, c, hl
|
|
ResetShadowOAM::
|
|
xor a, a ; clear carry
|
|
ldh a, [hOAMIndex]
|
|
rra
|
|
rra ; a / 4
|
|
and a, a
|
|
jr z, .skip
|
|
ld c, a
|
|
ld hl, wShadowOAM
|
|
xor a, a
|
|
.clearOAM
|
|
ld [hli], a
|
|
inc l
|
|
inc l
|
|
inc l
|
|
dec c
|
|
jr nz, .clearOAM
|
|
ldh [hOAMIndex], a
|
|
.skip
|
|
ret
|
|
|
|
SECTION "Render Simple Sprite", ROM0
|
|
; Render a single object, or sprite, to OAM.
|
|
; @param b: Y position
|
|
; @param c: X position
|
|
; @param d: Tile ID
|
|
; @param e: Tile Attribute
|
|
; @clobbers: hl
|
|
RenderSimpleSprite::
|
|
ld h, HIGH(wShadowOAM)
|
|
ldh a, [hOAMIndex]
|
|
ld l, a
|
|
ld a, b
|
|
add a, 16
|
|
ld [hli], a
|
|
ld a, c
|
|
add a, 8
|
|
ld [hli], a
|
|
ld a, d
|
|
ld [hli], a
|
|
ld a, e
|
|
ld [hli], a
|
|
ld a, l
|
|
ldh [hOAMIndex], a
|
|
ret
|
|
|
|
SECTION "Render Metasprite", ROM0
|
|
; Render a metasprite to OAM.
|
|
; @param bc: Q12.4 fixed-point Y position.
|
|
; @param de: Q12.4 fixed-point X position.
|
|
; @param hl: Pointer to current metasprite.
|
|
RenderMetasprite::
|
|
; Adjust Y and store in b.
|
|
ld a, c
|
|
rrc b
|
|
rra
|
|
rrc b
|
|
rra
|
|
rrc b
|
|
rra
|
|
rrc b
|
|
rra
|
|
ld b, a
|
|
; Adjust X and store in c.
|
|
ld a, e
|
|
rrc d
|
|
rra
|
|
rrc d
|
|
rra
|
|
rrc d
|
|
rra
|
|
rrc d
|
|
rra
|
|
ld c, a
|
|
; Load Shadow OAM pointer.
|
|
ld d, HIGH(wShadowOAM)
|
|
ldh a, [hOAMIndex]
|
|
ld e, a
|
|
; Now:
|
|
; bc - Y, X
|
|
; de - Shadow OAM
|
|
; hl - Metasprite
|
|
; Time to render!
|
|
.loop
|
|
; Load Y.
|
|
ld a, [hli]
|
|
add a, b
|
|
ld [de], a
|
|
inc e
|
|
; Load X.
|
|
ld a, [hli]
|
|
add a, c
|
|
ld [de], a
|
|
inc e
|
|
; Load Tile.
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc e
|
|
; Load Attribute.
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc e
|
|
; Check for null end byte.
|
|
ld a, [hl]
|
|
cp a, 128
|
|
jr nz, .loop
|
|
ld a, e
|
|
ldh [hOAMIndex], a
|
|
ret
|
|
|
|
SECTION "Shadow OAM", WRAM0, ALIGN[8]
|
|
wShadowOAM::
|
|
ds 160
|
|
|
|
SECTION "Shadow OAM Index", HRAM
|
|
; The current low byte of shadow OAM.
|
|
hOAMIndex::
|
|
db
|