diff --git a/ares/gba/ppu/background.cpp b/ares/gba/ppu/background.cpp index eb051925e5..5c3ee4b36e 100644 --- a/ares/gba/ppu/background.cpp +++ b/ares/gba/ppu/background.cpp @@ -86,14 +86,14 @@ auto PPU::Background::linear(u32 x, u32 y) -> void { if(n4 color = ppu.readVRAM_BG(Byte, offset) >> (px & 1 ? 4 : 0)) { output.enable = true; output.priority = io.priority; - output.color = ppu.pram[latch.palette << 4 | color]; + output.color = latch.palette << 4 | color; } } else { u32 offset = (io.characterBase << 14) + (latch.character << 6) + (py << 3) + (px); if(n8 color = ppu.readVRAM_BG(Byte, offset)) { output.enable = true; output.priority = io.priority; - output.color = ppu.pram[color]; + output.color = color; } } @@ -127,7 +127,7 @@ auto PPU::Background::affine(u32 x, u32 y) -> void { if(n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (character << 6) + (py << 3) + px)) { output.enable = true; output.priority = io.priority; - output.color = ppu.pram[color]; + output.color = color; } } @@ -165,7 +165,7 @@ auto PPU::Background::bitmap(u32 x, u32 y) -> void { n15 color = ppu.readVRAM_BG(mode, baseAddress + (offset << depth)); if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque - if(depth == 0) color = ppu.pram[color]; + if(depth) output.directColor = true; output.enable = true; output.priority = io.priority; output.color = color; diff --git a/ares/gba/ppu/dac.cpp b/ares/gba/ppu/dac.cpp index c46ac3f0a4..9ae7bb04bb 100644 --- a/ares/gba/ppu/dac.cpp +++ b/ares/gba/ppu/dac.cpp @@ -1,5 +1,8 @@ -auto PPU::DAC::run(u32 x, u32 y) -> n15 { - if(ppu.blank()) return 0x7fff; +auto PPU::DAC::upperLayer() -> bool { + if(ppu.blank()) { + color = 0x7fff; + return false; + } //determine active window n1 active[6] = {true, true, true, true, true, true}; //enable all layers if no windows are enabled @@ -11,16 +14,15 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 { } //priority sorting: find topmost two pixels - Pixel layers[6] = { - ppu.objects.mosaic, - ppu.bg0.mosaic, - ppu.bg1.mosaic, - ppu.bg2.mosaic, - ppu.bg3.mosaic, - {true, 3, ppu.pram[0]}, - }; + layers[OBJ] = ppu.objects.mosaic; + layers[BG0] = ppu.bg0.mosaic; + layers[BG1] = ppu.bg1.mosaic; + layers[BG2] = ppu.bg2.mosaic; + layers[BG3] = ppu.bg3.mosaic; + layers[SFX] = {true, 3, 0}; - u32 aboveLayer = 5, belowLayer = 5; + aboveLayer = 5; + belowLayer = 5; for(s32 priority = 3; priority >= 0; priority--) { for(s32 layer = 5; layer >= 0; layer--) { if(layers[layer].enable && layers[layer].priority == priority && active[layer]) { @@ -31,26 +33,35 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 { } auto above = layers[aboveLayer]; - auto below = layers[belowLayer]; - auto eva = min(16u, (u32)io.blendEVA); - auto evb = min(16u, (u32)io.blendEVB); - auto evy = min(16u, (u32)io.blendEVY); - n15 color = above.color; + color = pramLookup(above); //color blending - if(active[SFX] || (above.translucent && io.blendBelow[belowLayer])) { - if(above.translucent && io.blendBelow[belowLayer]) { - color = blend(above.color, eva, below.color, evb); - } else if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) { - color = blend(above.color, eva, below.color, evb); + if(above.translucent && io.blendBelow[belowLayer]) return true; + if(active[SFX]) { + auto evy = min(16u, (u32)io.blendEVY); + if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) { + return true; } else if(io.blendMode == 2 && io.blendAbove[aboveLayer]) { - color = blend(above.color, 16 - evy, 0x7fff, evy); + color = blend(color, 16 - evy, 0x7fff, evy); } else if(io.blendMode == 3 && io.blendAbove[aboveLayer]) { - color = blend(above.color, 16 - evy, 0x0000, evy); + color = blend(color, 16 - evy, 0x0000, evy); } } - return color; + return false; +} + +auto PPU::DAC::lowerLayer() -> void { + auto below = layers[belowLayer]; + auto eva = min(16u, (u32)io.blendEVA); + auto evb = min(16u, (u32)io.blendEVB); + + color = blend(color, eva, pramLookup(below), evb); +} + +inline auto PPU::DAC::pramLookup(Pixel& layer) -> n15 { + if(layer.directColor) return layer.color; + return ppu.pram[layer.color]; } auto PPU::DAC::blend(n15 above, u32 eva, n15 below, u32 evb) -> n15 { diff --git a/ares/gba/ppu/object.cpp b/ares/gba/ppu/object.cpp index df923777c4..4a85039062 100644 --- a/ares/gba/ppu/object.cpp +++ b/ares/gba/ppu/object.cpp @@ -90,7 +90,6 @@ auto PPU::Objects::run(u32 x, u32 y) -> void { auto& buffer = lineBuffers[y & 1]; output = buffer[x]; - output.color = ppu.pram[output.color]; //horizontal mosaic if(!mosaicOffset) { diff --git a/ares/gba/ppu/ppu.cpp b/ares/gba/ppu/ppu.cpp index 11099cf4b2..67359912ed 100644 --- a/ares/gba/ppu/ppu.cpp +++ b/ares/gba/ppu/ppu.cpp @@ -147,9 +147,15 @@ auto PPU::main() -> void { window1.run(x, y); window2.output = objects.output.window; window3.output = true; - n15 color = dac.run(x, y); - line[x] = color; - if(accurate) step(4); + bool blending = dac.upperLayer(); + if(blending) { + if(accurate) step(2); + dac.lowerLayer(); + if(accurate) step(2); + } else { + if(accurate) step(4); + } + line[x] = dac.color; } if(!accurate) step(960); } else { diff --git a/ares/gba/ppu/ppu.hpp b/ares/gba/ppu/ppu.hpp index 8ddee98ade..910c710b1b 100644 --- a/ares/gba/ppu/ppu.hpp +++ b/ares/gba/ppu/ppu.hpp @@ -93,6 +93,9 @@ struct PPU : Thread, IO { n2 priority; n15 color; + //BG2 only + n1 directColor; + //OBJ only n1 translucent; n1 mosaic; @@ -216,7 +219,9 @@ struct PPU : Thread, IO { struct DAC { //dac.cpp - auto run(u32 x, u32 y) -> n15; + auto upperLayer() -> bool; + auto lowerLayer() -> void; + auto pramLookup(Pixel& layer) -> n15; auto blend(n15 above, u32 eva, n15 below, u32 evb) -> n15; auto power() -> void; @@ -232,6 +237,12 @@ struct PPU : Thread, IO { n5 blendEVB; n5 blendEVY; } io; + + u32 aboveLayer; + u32 belowLayer; + n15 color; + + Pixel layers[6]; } dac; struct Object {