1+ ; Sprite Objects Library - by Eievui
2+ ;
3+ ; This is a small, lightweight library meant to facilitate the rendering of
4+ ; sprite objects, including Shadow OAM and OAM DMA, single-entry "simple" sprite
5+ ; objects, and Q12.4 fixed-point position metasprite rendering.
6+ ;
7+ ; The library is only 127 bytes of ROM0, 160 bytes of WRAM0 for Shadow OAM, and a
8+ ; single HRAM byte for tracking the current position in OAM.
9+ ;
10+ ; The library is relatively simple to use, with 4 steps to rendering:
11+ ; 1. Call InitSprObjLib during initilizations - This copies the OAMDMA function to
12+ ; HRAM.
13+ ; 2. Call ResetShadowOAM at the beginning of each frame - This hides all sprites
14+ ; and resets hOAMIndex, allowing you to render a new frame of sprites.
15+ ; 3. Call rendering functions - Push simple sprites or metasprites to Shadow OAM.
16+ ; 4. Wait for VBlank and call hOAMDMA - Copies wShadowOAM to the Game Boy's OAM in
17+ ; just 160 M-cycles. Make sure to pass HIGH(wShadowOAM) in the a register.
18+ ;
19+ ; Copyright 2021, Eievui
20+ ;
21+ ; This software is provided 'as-is', without any express or implied
22+ ; warranty. In no event will the authors be held liable for any damages
23+ ; arising from the use of this software.
24+ ;
25+ ; Permission is granted to anyone to use this software for any purpose,
26+ ; including commercial applications, and to alter it and redistribute it
27+ ; freely, subject to the following restrictions:
28+ ;
29+ ; 1. The origin of this software must not be misrepresented; you must not
30+ ; claim that you wrote the original software. If you use this software
31+ ; in a product, an acknowledgment in the product documentation would be
32+ ; appreciated but is not required.
33+ ; 2. Altered source versions must be plainly marked as such, and must not be
34+ ; misrepresented as being the original software.
35+ ; 3. This notice may not be removed or altered from any source distribution.
36+ ;
37+
38+ INCLUDE "src/main/utils/hardware.inc"
39+
40+ SECTION "OAM DMA Code" , ROM0
41+ OAMDMACode::
42+ LOAD "OAM DMA" , HRAM
43+ ; Begin an OAM DMA, waiting 160 cycles for the DMA to finish.
44+ ; This quickly copies Shadow OAM to the Game Boy's OAM, allowing the PPU to draw
45+ ; the objects. hOAMDMA should be called once per frame near the end of your
46+ ; VBlank interrupt. While an OAM DMA is running no sprites objects can be drawn
47+ ; by the PPU, which makes it preferrable to run within the VBlank interrupt, but
48+ ; it can be run at any point if more than 40 sprite objects are needed.
49+ ; @param a: High byte of active Shadow OAM. Shadow OAM must be aligned to start
50+ ; at the beginning of a page (low byte == $00).
51+ hOAMDMA::
52+ ldh [ rDMA ], a
53+ ld a , 40
54+ . wait
55+ dec a
56+ jr nz , . wait
57+ ret
58+ ENDL
59+ OAMDMACodeEnd::
60+
61+ SECTION "Initialize Sprite Object Library" , ROM0
62+
63+ ; A wrapper or the InitSprObjLib code
64+ ; from: https://github.com/eievui5/gb-sprobj-lib
65+ ; The library is relatively simple to get set up. First, put the following in your initialization code:
66+ ; Initilize Sprite Object Library.
67+ InitSprObjLibWrapper::
68+
69+ call InitSprObjLib
70+ ; Reset hardware OAM
71+ xor a , a
72+ ld b , 160
73+ ld hl , _OAMRAM
74+
75+ .resetOAM
76+ ld [ hli ], a
77+ dec b
78+ jr nz , .resetOAM
79+
80+ ret
81+
82+ ; Initializes the sprite object library, copying things such as the hOAMDMA
83+ ; function and reseting hOAMIndex
84+ ; @clobbers: a, bc, hl
85+ InitSprObjLib::
86+ ; Copy OAM DMA.
87+ ld b , OAMDMACodeEnd - OAMDMACode
88+ ld c , LOW(hOAMDMA)
89+ ld hl , OAMDMACode
90+ .memcpy
91+ ld a , [ hli ]
92+ ldh [ c ], a
93+ inc c
94+ dec b
95+ jr nz , .memcpy
96+ xor a , a
97+ ldh [ hOAMIndex ], a ; hOAMIndex must be reset before running ResetShadowOAM.
98+ ret
99+
100+ SECTION "Reset Shadow OAM" , ROM0
101+ ; Reset the Y positions of every sprite object that was used in the last frame,
102+ ; effectily hiding them, and reset hOAMIndex. Run this function each frame
103+ ; before rendering sprite objects.
104+ ; @clobbers: a, c, hl
105+ ResetShadowOAM::
106+ xor a , a ; clear carry
107+ ldh a , [ hOAMIndex ]
108+ rra
109+ rra ; a / 4
110+ and a , a
111+ jr z , .skip
112+ ld c , a
113+ ld hl , wShadowOAM
114+ xor a , a
115+ .clearOAM
116+ ld [ hli ], a
117+ inc l
118+ inc l
119+ inc l
120+ dec c
121+ jr nz , .clearOAM
122+ ldh [ hOAMIndex ], a
123+ .skip
124+ ret
125+
126+ SECTION "Render Simple Sprite" , ROM0
127+ ; Render a single object, or sprite, to OAM.
128+ ; @param b: Y position
129+ ; @param c: X position
130+ ; @param d: Tile ID
131+ ; @param e: Tile Attribute
132+ ; @clobbers: hl
133+ RenderSimpleSprite::
134+ ld h , HIGH(wShadowOAM)
135+ ldh a , [ hOAMIndex ]
136+ ld l , a
137+ ld a , b
138+ add a , 16
139+ ld [ hli ], a
140+ ld a , c
141+ add a , 8
142+ ld [ hli ], a
143+ ld a , d
144+ ld [ hli ], a
145+ ld a , e
146+ ld [ hli ], a
147+ ld a , l
148+ ldh [ hOAMIndex ], a
149+ ret
150+
151+ SECTION "Render Metasprite" , ROM0
152+ ; Render a metasprite to OAM.
153+ ; @param bc: Q12.4 fixed-point Y position.
154+ ; @param de: Q12.4 fixed-point X position.
155+ ; @param hl: Pointer to current metasprite.
156+ RenderMetasprite::
157+ ; Adjust Y and store in b.
158+ ld a , c
159+ rrc b
160+ rra
161+ rrc b
162+ rra
163+ rrc b
164+ rra
165+ rrc b
166+ rra
167+ ld b , a
168+ ; Adjust X and store in c.
169+ ld a , e
170+ rrc d
171+ rra
172+ rrc d
173+ rra
174+ rrc d
175+ rra
176+ rrc d
177+ rra
178+ ld c , a
179+ ; Load Shadow OAM pointer.
180+ ld d , HIGH(wShadowOAM)
181+ ldh a , [ hOAMIndex ]
182+ ld e , a
183+ ; Now:
184+ ; bc - Y, X
185+ ; de - Shadow OAM
186+ ; hl - Metasprite
187+ ; Time to render!
188+ . loop
189+ ; Load Y.
190+ ld a , [ hli ]
191+ add a , b
192+ ld [ de ], a
193+ inc e
194+ ; Load X.
195+ ld a , [ hli ]
196+ add a , c
197+ ld [ de ], a
198+ inc e
199+ ; Load Tile.
200+ ld a , [ hli ]
201+ ld [ de ], a
202+ inc e
203+ ; Load Attribute.
204+ ld a , [ hli ]
205+ ld [ de ], a
206+ inc e
207+ ; Check for null end byte.
208+ ld a , [ hl ]
209+ cp a , 128
210+ jr nz , . loop
211+ ld a , e
212+ ldh [ hOAMIndex ], a
213+ ret
214+
215+ SECTION "Shadow OAM" , WRAM0 , ALIGN [ 8 ]
216+ wShadowOAM::
217+ ds 160
218+
219+ SECTION "Shadow OAM Index" , HRAM
220+ ; The current low byte of shadow OAM.
221+ hOAMIndex::
222+ db
0 commit comments