mirror of https://github.com/bsnes-emu/bsnes.git
134 lines
3.9 KiB
C++
134 lines
3.9 KiB
C++
auto VDP::Sprite::setup(uint9 voffset) -> void {
|
|
objectsValid = 0;
|
|
uint limit = vdp.io.spriteTile ? 15 : 7;
|
|
|
|
if(!vdp.io.mode.bit(3)) {
|
|
uint14 attributeAddress;
|
|
attributeAddress.bits(7,13) = vdp.io.spriteAttributeTableAddress;
|
|
for(uint index : range(32)) {
|
|
uint8 y = vdp.vram[attributeAddress++];
|
|
if(y == 0xd0) break;
|
|
|
|
uint8 x = vdp.vram[attributeAddress++];
|
|
uint8 pattern = vdp.vram[attributeAddress++];
|
|
uint8 extra = vdp.vram[attributeAddress++];
|
|
|
|
if(extra.bit(7)) x -= 32;
|
|
y += 1;
|
|
if(voffset < y) continue;
|
|
if(voffset > y + limit) continue;
|
|
|
|
if(limit == 15) pattern.bits(0,1) = 0;
|
|
|
|
objects[objectsValid] = {x, y, pattern, extra.bits(0,3)};
|
|
if(++objectsValid == 4) {
|
|
vdp.io.spriteOverflow = 1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
uint14 attributeAddress;
|
|
attributeAddress.bits(8,13) = vdp.io.spriteAttributeTableAddress.bits(1,6);
|
|
for(uint index : range(64)) {
|
|
uint8 y = vdp.vram[attributeAddress + index];
|
|
uint8 x = vdp.vram[attributeAddress + 0x80 + (index << 1)];
|
|
uint8 pattern = vdp.vram[attributeAddress + 0x81 + (index << 1)];
|
|
if(vdp.vlines() == 192 && y == 0xd0) break;
|
|
|
|
if(vdp.io.spriteShift) x -= 8;
|
|
y += 1;
|
|
if(voffset < y) continue;
|
|
if(voffset > y + limit) continue;
|
|
|
|
if(limit == 15) pattern.bit(0) = 0;
|
|
|
|
objects[objectsValid] = {x, y, pattern};
|
|
if(++objectsValid == 8) {
|
|
vdp.io.spriteOverflow = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto VDP::Sprite::run(uint8 hoffset, uint9 voffset) -> void {
|
|
output = {};
|
|
switch(vdp.io.mode) {
|
|
case 0b0000: return graphics1(hoffset, voffset);
|
|
case 0b0001: return;
|
|
case 0b0010: return graphics2(hoffset, voffset);
|
|
case 0b0011: return;
|
|
case 0b0100: return;
|
|
case 0b0101: return;
|
|
case 0b0110: return;
|
|
case 0b0111: return;
|
|
case 0b1000: return graphics3(hoffset, voffset, 192);
|
|
case 0b1001: return;
|
|
case 0b1010: return graphics3(hoffset, voffset, 192);
|
|
case 0b1011: return graphics3(hoffset, voffset, 224);
|
|
case 0b1100: return graphics3(hoffset, voffset, 192);
|
|
case 0b1101: return;
|
|
case 0b1110: return graphics3(hoffset, voffset, 240);
|
|
case 0b1111: return graphics3(hoffset, voffset, 192);
|
|
}
|
|
}
|
|
|
|
auto VDP::Sprite::graphics1(uint8 hoffset, uint9 voffset) -> void {
|
|
//todo: are sprites different in graphics mode 1?
|
|
return graphics2(hoffset, voffset);
|
|
}
|
|
|
|
auto VDP::Sprite::graphics2(uint8 hoffset, uint9 voffset) -> void {
|
|
uint limit = vdp.io.spriteTile ? 15 : 7;
|
|
for(uint objectIndex : range(objectsValid)) {
|
|
auto& o = objects[objectIndex];
|
|
if(hoffset < o.x) continue;
|
|
if(hoffset > o.x + limit) continue;
|
|
|
|
uint x = hoffset - o.x;
|
|
uint y = voffset - o.y;
|
|
|
|
uint14 address;
|
|
address.bits( 0,10) = (o.pattern << 3) + (x >> 3 << 4) + (y & limit);
|
|
address.bits(11,13) = vdp.io.spritePatternTableAddress;
|
|
|
|
uint3 index = x ^ 7;
|
|
if(vdp.vram[address].bit(index)) {
|
|
if(output.color) { vdp.io.spriteCollision = true; break; }
|
|
output.color = o.color;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto VDP::Sprite::graphics3(uint8 hoffset, uint9 voffset, uint vlines) -> void {
|
|
uint limit = vdp.io.spriteTile ? 15 : 7;
|
|
for(uint objectIndex : range(objectsValid)) {
|
|
auto& o = objects[objectIndex];
|
|
if(hoffset < o.x) continue;
|
|
if(hoffset > o.x + 7) continue;
|
|
|
|
uint x = hoffset - o.x;
|
|
uint y = voffset - o.y;
|
|
|
|
uint14 address;
|
|
address.bits(2,12) = (o.pattern << 3) + (y & limit);
|
|
address.bit (13) = vdp.io.spritePatternTableAddress.bit(2);
|
|
|
|
uint3 index = x ^ 7;
|
|
uint4 color;
|
|
color.bit(0) = vdp.vram[address | 0].bit(index);
|
|
color.bit(1) = vdp.vram[address | 1].bit(index);
|
|
color.bit(2) = vdp.vram[address | 2].bit(index);
|
|
color.bit(3) = vdp.vram[address | 3].bit(index);
|
|
if(color == 0) continue;
|
|
|
|
if(output.color) { vdp.io.spriteCollision = true; break; }
|
|
output.color = color;
|
|
}
|
|
}
|
|
|
|
auto VDP::Sprite::power() -> void {
|
|
output = {};
|
|
objectsValid = 0;
|
|
}
|