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