Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/alt/ppu-compatibility/render/oam.cpp
2 views
1
#ifdef PPU_CPP
2
3
void PPU::update_sprite_list(unsigned addr, uint8 data) {
4
if(addr < 0x0200) {
5
unsigned i = addr >> 2;
6
switch(addr & 3) {
7
case 0: sprite_list[i].x = (sprite_list[i].x & 0x0100) | data; break;
8
case 1: sprite_list[i].y = (data + 1) & 0xff; break;
9
case 2: sprite_list[i].character = data; break;
10
case 3: sprite_list[i].vflip = data & 0x80;
11
sprite_list[i].hflip = data & 0x40;
12
sprite_list[i].priority = (data >> 4) & 3;
13
sprite_list[i].palette = (data >> 1) & 7;
14
sprite_list[i].use_nameselect = data & 0x01;
15
}
16
} else {
17
unsigned i = (addr & 0x1f) << 2;
18
sprite_list[i + 0].x = ((data & 0x01) << 8) | (sprite_list[i + 0].x & 0xff);
19
sprite_list[i + 0].size = data & 0x02;
20
sprite_list[i + 1].x = ((data & 0x04) << 6) | (sprite_list[i + 1].x & 0xff);
21
sprite_list[i + 1].size = data & 0x08;
22
sprite_list[i + 2].x = ((data & 0x10) << 4) | (sprite_list[i + 2].x & 0xff);
23
sprite_list[i + 2].size = data & 0x20;
24
sprite_list[i + 3].x = ((data & 0x40) << 2) | (sprite_list[i + 3].x & 0xff);
25
sprite_list[i + 3].size = data & 0x80;
26
}
27
}
28
29
void PPU::build_sprite_list() {
30
if(sprite_list_valid == true) return;
31
sprite_list_valid = true;
32
33
for(unsigned i = 0; i < 128; i++) {
34
const bool size = sprite_list[i].size;
35
36
switch(cache.oam_basesize) {
37
case 0: sprite_list[i].width = (!size) ? 8 : 16;
38
sprite_list[i].height = (!size) ? 8 : 16;
39
break;
40
case 1: sprite_list[i].width = (!size) ? 8 : 32;
41
sprite_list[i].height = (!size) ? 8 : 32;
42
break;
43
case 2: sprite_list[i].width = (!size) ? 8 : 64;
44
sprite_list[i].height = (!size) ? 8 : 64;
45
break;
46
case 3: sprite_list[i].width = (!size) ? 16 : 32;
47
sprite_list[i].height = (!size) ? 16 : 32;
48
break;
49
case 4: sprite_list[i].width = (!size) ? 16 : 64;
50
sprite_list[i].height = (!size) ? 16 : 64;
51
break;
52
case 5: sprite_list[i].width = (!size) ? 32 : 64;
53
sprite_list[i].height = (!size) ? 32 : 64;
54
break;
55
case 6: sprite_list[i].width = (!size) ? 16 : 32;
56
sprite_list[i].height = (!size) ? 32 : 64;
57
if(regs.oam_interlace && !size) sprite_list[i].height = 16;
58
//32x64 height is not affected by oam_interlace setting
59
break;
60
case 7: sprite_list[i].width = (!size) ? 16 : 32;
61
sprite_list[i].height = (!size) ? 32 : 32;
62
if(regs.oam_interlace && !size) sprite_list[i].height = 16;
63
break;
64
}
65
}
66
}
67
68
bool PPU::is_sprite_on_scanline() {
69
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
70
//then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen.
71
sprite_item *spr = &sprite_list[active_sprite];
72
if(spr->x > 256 && (spr->x + spr->width - 1) < 512) return false;
73
74
int spr_height = (regs.oam_interlace == false) ? (spr->height) : (spr->height >> 1);
75
if(line >= spr->y && line < (spr->y + spr_height)) return true;
76
if((spr->y + spr_height) >= 256 && line < ((spr->y + spr_height) & 255)) return true;
77
return false;
78
}
79
80
void PPU::load_oam_tiles() {
81
sprite_item *spr = &sprite_list[active_sprite];
82
uint16 tile_width = spr->width >> 3;
83
int x = spr->x;
84
int y = (line - spr->y) & 0xff;
85
if(regs.oam_interlace == true) {
86
y <<= 1;
87
}
88
89
if(spr->vflip == true) {
90
if(spr->width == spr->height) {
91
y = (spr->height - 1) - y;
92
} else {
93
y = (y < spr->width) ? ((spr->width - 1) - y) : (spr->width + ((spr->width - 1) - (y - spr->width)));
94
}
95
}
96
97
if(regs.oam_interlace == true) {
98
y = (spr->vflip == false) ? (y + field()) : (y - field());
99
}
100
101
x &= 511;
102
y &= 255;
103
104
uint16 tdaddr = cache.oam_tdaddr;
105
uint16 chrx = (spr->character ) & 15;
106
uint16 chry = (spr->character >> 4) & 15;
107
if(spr->use_nameselect == true) {
108
tdaddr += (256 * 32) + (cache.oam_nameselect << 13);
109
}
110
chry += (y >> 3);
111
chry &= 15;
112
chry <<= 4;
113
114
for(unsigned tx = 0; tx < tile_width; tx++) {
115
unsigned sx = (x + (tx << 3)) & 511;
116
//ignore sprites that are offscreen, x==256 is a special case that loads all tiles in OBJ
117
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
118
119
if(regs.oam_tilecount++ >= 34) break;
120
unsigned n = regs.oam_tilecount - 1;
121
oam_tilelist[n].x = sx;
122
oam_tilelist[n].y = y;
123
oam_tilelist[n].pri = spr->priority;
124
oam_tilelist[n].pal = 128 + (spr->palette << 4);
125
oam_tilelist[n].hflip = spr->hflip;
126
127
unsigned mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx);
128
unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
129
oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
130
}
131
}
132
133
void PPU::render_oam_tile(int tile_num) {
134
oam_tileitem *t = &oam_tilelist[tile_num];
135
uint8 *oam_td = (uint8*)bg_tiledata[COLORDEPTH_16];
136
uint8 *oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16];
137
138
if(oam_td_state[t->tile] == 1) {
139
render_bg_tile<COLORDEPTH_16>(t->tile);
140
}
141
142
unsigned sx = t->x;
143
uint8 *tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3);
144
for(unsigned x = 0; x < 8; x++) {
145
sx &= 511;
146
if(sx < 256) {
147
unsigned col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x)));
148
if(col) {
149
col += t->pal;
150
oam_line_pal[sx] = col;
151
oam_line_pri[sx] = t->pri;
152
}
153
}
154
sx++;
155
}
156
}
157
158
void PPU::render_line_oam_rto() {
159
build_sprite_list();
160
161
regs.oam_itemcount = 0;
162
regs.oam_tilecount = 0;
163
memset(oam_line_pri, OAM_PRI_NONE, 256);
164
memset(oam_itemlist, 0xff, 32);
165
for(int s = 0; s < 34; s++) oam_tilelist[s].tile = 0xffff;
166
167
for(int s = 0; s < 128; s++) {
168
active_sprite = (s + regs.oam_firstsprite) & 127;
169
if(is_sprite_on_scanline() == false) continue;
170
if(regs.oam_itemcount++ >= 32) break;
171
oam_itemlist[regs.oam_itemcount - 1] = (s + regs.oam_firstsprite) & 127;
172
}
173
174
if(regs.oam_itemcount > 0 && oam_itemlist[regs.oam_itemcount - 1] != 0xff) {
175
regs.ioamaddr = 0x0200 + (oam_itemlist[regs.oam_itemcount - 1] >> 2);
176
}
177
178
for(int s = 31; s >= 0; s--) {
179
if(oam_itemlist[s] == 0xff) continue;
180
active_sprite = oam_itemlist[s];
181
load_oam_tiles();
182
}
183
184
regs.time_over |= (regs.oam_tilecount > 34);
185
regs.range_over |= (regs.oam_itemcount > 32);
186
}
187
188
#define setpixel_main(x) \
189
if(pixel_cache[x].pri_main < pri) { \
190
pixel_cache[x].pri_main = pri; \
191
pixel_cache[x].bg_main = OAM; \
192
pixel_cache[x].src_main = get_palette(oam_line_pal[x]); \
193
pixel_cache[x].ce_main = (oam_line_pal[x] < 192); \
194
}
195
#define setpixel_sub(x) \
196
if(pixel_cache[x].pri_sub < pri) { \
197
pixel_cache[x].pri_sub = pri; \
198
pixel_cache[x].bg_sub = OAM; \
199
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); \
200
pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \
201
}
202
203
void PPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
204
if(layer_enabled[OAM][0] == false) pri0_pos = 0;
205
if(layer_enabled[OAM][1] == false) pri1_pos = 0;
206
if(layer_enabled[OAM][2] == false) pri2_pos = 0;
207
if(layer_enabled[OAM][3] == false) pri3_pos = 0;
208
if(pri0_pos + pri1_pos + pri2_pos + pri3_pos == 0) return;
209
210
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return;
211
212
for(unsigned s = 0; s < 34; s++) {
213
if(oam_tilelist[s].tile == 0xffff) continue;
214
render_oam_tile(s);
215
}
216
217
bool bg_enabled = regs.bg_enabled[OAM];
218
bool bgsub_enabled = regs.bgsub_enabled[OAM];
219
220
build_window_tables(OAM);
221
uint8 *wt_main = window[OAM].main;
222
uint8 *wt_sub = window[OAM].sub;
223
224
unsigned pri_tbl[4] = { pri0_pos, pri1_pos, pri2_pos, pri3_pos };
225
for(int x = 0; x < 256; x++) {
226
if(oam_line_pri[x] == OAM_PRI_NONE) continue;
227
228
unsigned pri = pri_tbl[oam_line_pri[x]];
229
if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); }
230
if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); }
231
}
232
}
233
234
#undef setpixel_main
235
#undef setpixel_sub
236
237
#endif
238
239