auto VDP::scanline() -> void { if(state.vcounter < screenHeight()) { planeA.scanline(state.vcounter); window.scanline(state.vcounter); planeB.scanline(state.vcounter); sprite.scanline(state.vcounter); } if(state.vcounter == 240) scheduler.exit(Scheduler::Event::Frame); state.output = output + (state.vcounter * 2 + 0) * 1280; } auto VDP::run() -> void { if(!io.displayEnable) return outputPixel(0); if(state.vcounter >= screenHeight()) return outputPixel(0); auto& planeA = window.isWindowed(state.hdot, state.vcounter) ? window : this->planeA; planeA.run(state.hdot, state.vcounter); planeB.run(state.hdot, state.vcounter); sprite.run(state.hdot, state.vcounter); Pixel g = {io.backgroundColor, 0}; Pixel a = planeA.output; Pixel b = planeB.output; Pixel s = sprite.output; auto& bg = a.above() || a.color && !b.above() ? a : b.color ? b : g; auto& fg = s.above() || s.color && !b.above() && !a.above() ? s : bg; if(!io.shadowHighlightEnable) { auto color = cram.read(fg.color); outputPixel(1 << 9 | color); } else { uint mode = a.priority || b.priority; //0 = shadow, 1 = normal, 2 = highlight if(&fg == &s) switch(s.color) { case 0x0e: case 0x1e: case 0x2e: mode = 1; break; case 0x3e: mode += 1; fg = bg; break; case 0x3f: mode = 0; fg = bg; break; default: mode |= s.priority; break; } auto color = cram.read(fg.color); outputPixel(mode << 9 | color); } } auto VDP::outputPixel(uint32 color) -> void { uint32* field[2] = {&state.output[0], &state.output[1280]}; if(!io.interlaceMode.bit(0)) { for(auto n : range(pixelWidth())) { field[0][n] = color; field[1][n] = color; } } else { for(auto n : range(pixelWidth())) { field[state.field][n] = color; } } state.output += pixelWidth(); }