Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/ppu/sprite/sprite.cpp
2 views
1
#ifdef PPU_CPP
2
3
#include "list.cpp"
4
5
void PPU::Sprite::address_reset() {
6
self.regs.oam_addr = self.regs.oam_baseaddr;
7
set_first_sprite();
8
}
9
10
void PPU::Sprite::set_first_sprite() {
11
regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);
12
}
13
14
void PPU::Sprite::frame() {
15
regs.time_over = false;
16
regs.range_over = false;
17
}
18
19
void PPU::Sprite::scanline() {
20
t.x = 0;
21
t.y = self.vcounter();
22
23
t.item_count = 0;
24
t.tile_count = 0;
25
26
t.active = !t.active;
27
auto oam_item = t.item[t.active];
28
auto oam_tile = t.tile[t.active];
29
30
if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disable == false) address_reset();
31
if(t.y >= (!self.regs.overscan ? 224 : 239)) return;
32
33
memset(oam_item, 0xff, 32); //default to invalid
34
for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid
35
36
for(unsigned i = 0; i < 128; i++) {
37
unsigned sprite = (regs.first_sprite + i) & 127;
38
if(on_scanline(list[sprite]) == false) continue;
39
if(t.item_count++ >= 32) break;
40
oam_item[t.item_count - 1] = sprite;
41
}
42
43
if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) {
44
ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2);
45
}
46
}
47
48
bool PPU::Sprite::on_scanline(SpriteItem &sprite) {
49
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
50
signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1));
51
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
52
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
53
return false;
54
}
55
56
void PPU::Sprite::run() {
57
output.main.priority = 0;
58
output.sub.priority = 0;
59
60
auto oam_tile = t.tile[!t.active];
61
unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
62
unsigned x = t.x++;
63
64
for(unsigned n = 0; n < 34; n++) {
65
auto tile = oam_tile[n];
66
if(tile.x == 0xffff) break;
67
68
int px = x - sclip<9>(tile.x);
69
if(px & ~7) continue;
70
71
unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px);
72
unsigned color;
73
color = ((bool)(tile.d0 & mask)) << 0;
74
color |= ((bool)(tile.d1 & mask)) << 1;
75
color |= ((bool)(tile.d2 & mask)) << 2;
76
color |= ((bool)(tile.d3 & mask)) << 3;
77
78
if(color) {
79
if(regs.main_enable) {
80
output.main.palette = tile.palette + color;
81
output.main.priority = priority_table[tile.priority];
82
}
83
84
if(regs.sub_enable) {
85
output.sub.palette = tile.palette + color;
86
output.sub.priority = priority_table[tile.priority];
87
}
88
}
89
}
90
}
91
92
void PPU::Sprite::tilefetch() {
93
auto oam_item = t.item[t.active];
94
auto oam_tile = t.tile[t.active];
95
96
for(signed i = 31; i >= 0; i--) {
97
if(oam_item[i] == 0xff) continue;
98
auto sprite = list[oam_item[i]];
99
100
unsigned tile_width = sprite.width() >> 3;
101
signed x = sprite.x;
102
signed y = (t.y - sprite.y) & 0xff;
103
if(regs.interlace) y <<= 1;
104
105
if(sprite.vflip) {
106
if(sprite.width() == sprite.height()) {
107
y = (sprite.height() - 1) - y;
108
} else if(y < sprite.width()) {
109
y = (sprite.width() - 1) - y;
110
} else {
111
y = sprite.width() + ((sprite.width() - 1) - (y - sprite.width()));
112
}
113
}
114
115
if(regs.interlace) {
116
y = (sprite.vflip == false ? y + self.field() : y - self.field());
117
}
118
119
x &= 511;
120
y &= 255;
121
122
uint16 tiledata_addr = regs.tiledata_addr;
123
uint16 chrx = (sprite.character >> 0) & 15;
124
uint16 chry = (sprite.character >> 4) & 15;
125
if(sprite.nameselect) {
126
tiledata_addr += (256 * 32) + (regs.nameselect << 13);
127
}
128
chry += (y >> 3);
129
chry &= 15;
130
chry <<= 4;
131
132
for(unsigned tx = 0; tx < tile_width; tx++) {
133
unsigned sx = (x + (tx << 3)) & 511;
134
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
135
if(t.tile_count++ >= 34) break;
136
137
unsigned n = t.tile_count - 1;
138
oam_tile[n].x = sx;
139
oam_tile[n].priority = sprite.priority;
140
oam_tile[n].palette = 128 + (sprite.palette << 4);
141
oam_tile[n].hflip = sprite.hflip;
142
143
unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx);
144
unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
145
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
146
147
oam_tile[n].d0 = ppu.vram[addr + 0];
148
oam_tile[n].d1 = ppu.vram[addr + 1];
149
self.add_clocks(2);
150
151
oam_tile[n].d2 = ppu.vram[addr + 16];
152
oam_tile[n].d3 = ppu.vram[addr + 17];
153
self.add_clocks(2);
154
}
155
}
156
157
if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4);
158
regs.time_over |= (t.tile_count > 34);
159
regs.range_over |= (t.item_count > 32);
160
}
161
162
void PPU::Sprite::reset() {
163
for(unsigned i = 0; i < 128; i++) {
164
list[i].x = 0;
165
list[i].y = 0;
166
list[i].character = 0;
167
list[i].nameselect = 0;
168
list[i].vflip = 0;
169
list[i].hflip = 0;
170
list[i].priority = 0;
171
list[i].palette = 0;
172
list[i].size = 0;
173
}
174
synchronize();
175
176
t.x = 0;
177
t.y = 0;
178
179
t.item_count = 0;
180
t.tile_count = 0;
181
182
t.active = 0;
183
for(unsigned n = 0; n < 2; n++) {
184
memset(t.item[n], 0, 32);
185
for(unsigned i = 0; i < 34; i++) {
186
t.tile[n][i].x = 0;
187
t.tile[n][i].priority = 0;
188
t.tile[n][i].palette = 0;
189
t.tile[n][i].hflip = 0;
190
t.tile[n][i].d0 = 0;
191
t.tile[n][i].d1 = 0;
192
t.tile[n][i].d2 = 0;
193
t.tile[n][i].d3 = 0;
194
}
195
}
196
197
regs.main_enable = random(false);
198
regs.sub_enable = random(false);
199
regs.interlace = random(false);
200
201
regs.base_size = random(0);
202
regs.nameselect = random(0);
203
regs.tiledata_addr = (random(0x0000) & 3) << 14;
204
regs.first_sprite = 0;
205
206
regs.priority0 = 0;
207
regs.priority1 = 0;
208
regs.priority2 = 0;
209
regs.priority3 = 0;
210
211
regs.time_over = false;
212
regs.range_over = false;
213
214
output.main.palette = 0;
215
output.main.priority = 0;
216
output.sub.palette = 0;
217
output.sub.priority = 0;
218
}
219
220
PPU::Sprite::Sprite(PPU &self) : self(self) {
221
}
222
223
#endif
224
225