Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/alt/ppu-performance/sprite/sprite.cpp
2 views
1
#ifdef PPU_CPP
2
3
void PPU::Sprite::frame() {
4
regs.time_over = false;
5
regs.range_over = false;
6
}
7
8
void PPU::Sprite::update_list(unsigned addr, uint8 data) {
9
if(addr < 0x0200) {
10
unsigned i = addr >> 2;
11
switch(addr & 3) {
12
case 0: list[i].x = (list[i].x & 0x0100) | data; break;
13
case 1: list[i].y = (data + 1) & 0xff; break;
14
case 2: list[i].character = data; break;
15
case 3: list[i].vflip = data & 0x80;
16
list[i].hflip = data & 0x40;
17
list[i].priority = (data >> 4) & 3;
18
list[i].palette = (data >> 1) & 7;
19
list[i].use_nameselect = data & 0x01;
20
break;
21
}
22
} else {
23
unsigned i = (addr & 0x1f) << 2;
24
list[i + 0].x = ((data & 0x01) << 8) | (list[i + 0].x & 0xff);
25
list[i + 0].size = data & 0x02;
26
list[i + 1].x = ((data & 0x04) << 6) | (list[i + 1].x & 0xff);
27
list[i + 1].size = data & 0x08;
28
list[i + 2].x = ((data & 0x10) << 4) | (list[i + 2].x & 0xff);
29
list[i + 2].size = data & 0x20;
30
list[i + 3].x = ((data & 0x40) << 2) | (list[i + 3].x & 0xff);
31
list[i + 3].size = data & 0x80;
32
list_valid = false;
33
}
34
}
35
36
void PPU::Sprite::address_reset() {
37
self.regs.oam_addr = self.regs.oam_baseaddr << 1;
38
set_first();
39
}
40
41
void PPU::Sprite::set_first() {
42
regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);
43
}
44
45
bool PPU::Sprite::on_scanline(unsigned sprite) {
46
auto &s = list[sprite];
47
if(s.x > 256 && (s.x + s.width - 1) < 512) return false;
48
signed height = (regs.interlace == false ? s.height : s.height >> 1);
49
if(self.vcounter() >= s.y && self.vcounter() < (s.y + height)) return true;
50
if((s.y + height) >= 256 && self.vcounter() < ((s.y + height) & 255)) return true;
51
return false;
52
}
53
54
void PPU::Sprite::render() {
55
if(list_valid == false) {
56
list_valid = true;
57
for(unsigned i = 0; i < 128; i++) {
58
if(list[i].size == 0) {
59
static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 };
60
static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 };
61
list[i].width = width[regs.base_size];
62
list[i].height = height[regs.base_size];
63
} else {
64
static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 };
65
static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 };
66
list[i].width = width[regs.base_size];
67
list[i].height = height[regs.base_size];
68
if(regs.interlace && regs.base_size >= 6) list[i].height = 16;
69
}
70
}
71
}
72
73
unsigned itemcount = 0;
74
unsigned tilecount = 0;
75
memset(output.priority, 0xff, 256);
76
memset(itemlist, 0xff, 32);
77
for(unsigned i = 0; i < 34; i++) tilelist[i].tile = 0xffff;
78
79
for(unsigned i = 0; i < 128; i++) {
80
unsigned s = (regs.first_sprite + i) & 127;
81
if(on_scanline(s) == false) continue;
82
if(itemcount++ >= 32) break;
83
itemlist[itemcount - 1] = s;
84
}
85
86
for(signed i = 31; i >= 0; i--) {
87
if(itemlist[i] == 0xff) continue;
88
auto &s = list[itemlist[i]];
89
unsigned tile_width = s.width >> 3;
90
signed x = s.x;
91
signed y = (self.vcounter() - s.y) & 0xff;
92
if(regs.interlace) y <<= 1;
93
94
if(s.vflip) {
95
if(s.width == s.height) {
96
y = (s.height - 1) - y;
97
} else {
98
y = (y < s.width) ? ((s.width - 1) - y) : (s.width + ((s.width - 1) - (y - s.width)));
99
}
100
}
101
102
if(regs.interlace) {
103
y = (s.vflip == false) ? (y + self.field()) : (y - self.field());
104
}
105
106
x &= 511;
107
y &= 255;
108
109
uint16 tdaddr = regs.tiledata_addr;
110
uint16 chrx = (s.character >> 0) & 15;
111
uint16 chry = (s.character >> 4) & 15;
112
if(s.use_nameselect) {
113
tdaddr += (256 * 32) + (regs.nameselect << 13);
114
}
115
chry += (y >> 3);
116
chry &= 15;
117
chry <<= 4;
118
119
for(unsigned tx = 0; tx < tile_width; tx++) {
120
unsigned sx = (x + (tx << 3)) & 511;
121
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
122
if(tilecount++ >= 34) break;
123
124
unsigned n = tilecount - 1;
125
tilelist[n].x = sx;
126
tilelist[n].y = y;
127
tilelist[n].priority = s.priority;
128
tilelist[n].palette = 128 + (s.palette << 4);
129
tilelist[n].hflip = s.hflip;
130
131
unsigned mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx);
132
unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
133
tilelist[n].tile = (pos >> 5) & 0x07ff;
134
}
135
}
136
137
regs.time_over |= (tilecount > 34);
138
regs.range_over |= (itemcount > 32);
139
140
if(regs.main_enable == false && regs.sub_enable == false) return;
141
142
for(unsigned i = 0; i < 34; i++) {
143
if(tilelist[i].tile == 0xffff) continue;
144
145
auto &t = tilelist[i];
146
uint8 *tiledata = self.cache.tile_4bpp(t.tile);
147
tiledata += (t.y & 7) << 3;
148
unsigned sx = t.x;
149
for(unsigned x = 0; x < 8; x++) {
150
sx &= 511;
151
if(sx < 256) {
152
unsigned color = *(tiledata + (t.hflip == false ? x : 7 - x));
153
if(color) {
154
color += t.palette;
155
output.palette[sx] = color;
156
output.priority[sx] = t.priority;
157
}
158
}
159
sx++;
160
}
161
}
162
163
if(regs.main_enable) window.render(0);
164
if(regs.sub_enable) window.render(1);
165
166
unsigned priority0 = (priority0_enable ? regs.priority0 : 0);
167
unsigned priority1 = (priority1_enable ? regs.priority1 : 0);
168
unsigned priority2 = (priority2_enable ? regs.priority2 : 0);
169
unsigned priority3 = (priority3_enable ? regs.priority3 : 0);
170
if(priority0 + priority1 + priority2 + priority3 == 0) return;
171
const unsigned priority_table[] = { priority0, priority1, priority2, priority3 };
172
173
for(unsigned x = 0; x < 256; x++) {
174
if(output.priority[x] == 0xff) continue;
175
unsigned priority = priority_table[output.priority[x]];
176
unsigned palette = output.palette[x];
177
unsigned color = self.screen.get_palette(output.palette[x]);
178
if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192));
179
if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192));
180
}
181
}
182
183
PPU::Sprite::Sprite(PPU &self) : self(self) {
184
priority0_enable = true;
185
priority1_enable = true;
186
priority2_enable = true;
187
priority3_enable = true;
188
}
189
190
#endif
191
192