mirror of https://github.com/bsnes-emu/bsnes.git
103 lines
2.8 KiB
C++
103 lines
2.8 KiB
C++
auto VDC::Sprite::scanline(uint y) -> void {
|
|
y += 64;
|
|
objects.reset();
|
|
|
|
static const uint widths[] = {15, 31};
|
|
static const uint heights[] = {15, 31, 63, 63};
|
|
|
|
uint count = 0;
|
|
for(uint index : range(64)) {
|
|
uint16 d0 = vdc->satb.read(index << 2 | 0);
|
|
uint16 d1 = vdc->satb.read(index << 2 | 1);
|
|
uint16 d2 = vdc->satb.read(index << 2 | 2);
|
|
uint16 d3 = vdc->satb.read(index << 2 | 3);
|
|
|
|
Object object;
|
|
object.y = d0.bits(0,9);
|
|
object.height = heights[d3.bits(12,13)];
|
|
if(y < object.y) continue;
|
|
if(y > object.y + object.height) continue;
|
|
|
|
object.x = d1.bits(0,9);
|
|
object.mode = d2.bit(0);
|
|
object.pattern = d2.bits(1,10);
|
|
object.palette = d3.bits(0,3);
|
|
object.priority = d3.bit(7);
|
|
object.width = widths[d3.bit(8)];
|
|
object.hflip = d3.bit(11);
|
|
object.vflip = d3.bit(15);
|
|
object.first = index == 0;
|
|
|
|
if(object.width == 31) object.pattern.bit(0) = 0;
|
|
if(object.height == 31) object.pattern.bit(1) = 0;
|
|
if(object.height == 63) object.pattern.bits(1,2) = 0;
|
|
|
|
if(object.width == 15) {
|
|
objects.append(object);
|
|
if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow);
|
|
} else {
|
|
//32-width sprites count as two 16-width sprite slots
|
|
object.pattern ^= object.hflip;
|
|
object.width = 15;
|
|
objects.append(object);
|
|
if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow);
|
|
|
|
object.x += 16;
|
|
object.pattern ^= 1;
|
|
objects.append(object);
|
|
if(++count >= 16) return vdc->irq.raise(VDC::IRQ::Line::Overflow);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto VDC::Sprite::run(uint x, uint y) -> void {
|
|
x += 32;
|
|
y += 64;
|
|
|
|
color = 0;
|
|
palette = 0;
|
|
priority = 0;
|
|
if(!enable) return;
|
|
|
|
bool first = false;
|
|
for(auto& object : objects) {
|
|
if(x < object.x) continue;
|
|
if(x > object.x + object.width) continue;
|
|
|
|
uint10 hoffset = x - object.x;
|
|
uint10 voffset = y - object.y;
|
|
if(object.hflip) hoffset ^= object.width;
|
|
if(object.vflip) voffset ^= object.height;
|
|
|
|
uint16 patternAddress = object.pattern;
|
|
patternAddress += (voffset >> 4) << 1;
|
|
patternAddress += (hoffset >> 4);
|
|
patternAddress <<= 6;
|
|
patternAddress += (voffset & 15);
|
|
|
|
uint16 d0 = vdc->vram.read(patternAddress + 0);
|
|
uint16 d1 = vdc->vram.read(patternAddress + 16);
|
|
uint16 d2 = vdc->vram.read(patternAddress + 32);
|
|
uint16 d3 = vdc->vram.read(patternAddress + 48);
|
|
|
|
uint4 index = 15 - (hoffset & 15);
|
|
uint4 color;
|
|
color.bit(0) = d0.bit(index);
|
|
color.bit(1) = d1.bit(index);
|
|
color.bit(2) = d2.bit(index);
|
|
color.bit(3) = d3.bit(index);
|
|
if(color == 0) continue;
|
|
|
|
if(this->color) {
|
|
if(first) return vdc->irq.raise(VDC::IRQ::Line::Collision);
|
|
return;
|
|
}
|
|
|
|
this->color = color;
|
|
this->palette = object.palette;
|
|
this->priority = object.priority;
|
|
|
|
if(object.first) first = true;
|
|
}
|
|
}
|