14 template<
typename Pixel>
16 : vdp(vdp_), vram(vdp.getVRAM())
17 , palette64(palette64_)
21 template<
typename Pixel>
23 : vdp(vdp_), vram(vdp.getVRAM()), palette64(palette64_)
38 return (128 * ((spriteNo & 0xF0) + spriteY))
39 + ( 8 * (spriteNo & 0x0F));
47 template<
typename Pixel>
static void draw1(
48 const Pixel* palette,
Pixel* __restrict buffer,
49 byte* __restrict ,
size_t p)
56 template<
typename Pixel>
static void draw1(
57 const Pixel* palette,
Pixel* __restrict buffer,
58 byte* __restrict info,
size_t p)
61 if (p) *buffer = palette[p];
76 return (256 * (((spriteNo & 0xE0) >> 1) + spriteY))
77 + ( 8 * (spriteNo & 0x1F));
79 template<
typename Pixel>
static void draw1(
80 const Pixel* palette,
Pixel* __restrict buffer,
81 byte* __restrict info,
size_t p)
93 template<
typename Policy,
bool ALIGNED>
94 static unsigned getPatternAddress(
95 V9990VRAM& vram,
unsigned nameAddr,
unsigned patternBase,
unsigned x,
unsigned y)
97 assert(!ALIGNED || ((
x & 7) == 0));
98 unsigned patternNum = (Policy::readNameTable(vram, nameAddr + 0) +
99 Policy::readNameTable(vram, nameAddr + 1) * 256) & 0x1FFF;
100 constexpr
auto PATTERN_PITCH = Policy::PATTERN_CHARS * 8 * (8 / 2);
101 unsigned x2 = (patternNum % Policy::PATTERN_CHARS) * 4 + (ALIGNED ? 0 : ((
x & 7) / 2));
102 unsigned y2 = (patternNum / Policy::PATTERN_CHARS) * PATTERN_PITCH + y;
103 return patternBase + y2 + x2;
106 template<
typename Policy>
107 static constexpr
unsigned nextNameAddr(
unsigned addr)
109 constexpr
auto MASK = (2 * Policy::NAME_CHARS) - 1;
110 return (addr & ~MASK) | ((addr + 2) & MASK);
113 template<
typename Policy,
bool CHECK_WIDTH,
typename Pixel>
116 unsigned& address,
int& width)
118 byte data = Policy::readPatternTable(vram, address++);
119 Policy::draw1(palette, buffer + 0, info + 0, data >> 4);
120 if (!CHECK_WIDTH || (width != 1)) {
121 Policy::draw1(palette, buffer + 1, info + 1, data & 0x0F);
128 template<
typename Policy,
typename Pixel>
129 static void renderPattern(
131 Pixel bgCol,
int width,
unsigned x,
unsigned y,
132 unsigned nameTable,
unsigned patternBase,
const Pixel* palette0,
const Pixel* palette1)
134 assert(
x < Policy::IMAGE_WIDTH);
135 if (width == 0)
return;
137 std::optional<ScopedAssign<Pixel>> col0, col1;
138 if (Policy::DRAW_BACKDROP) {
143 col0.emplace(
const_cast<Pixel*
>(palette0)[0], bgCol);
144 col1.emplace(
const_cast<Pixel*
>(palette1)[0], bgCol);
147 unsigned nameAddr = nameTable + (((y / 8) * Policy::NAME_CHARS + (
x / 8)) * 2);
148 y = (y & 7) * Policy::NAME_CHARS * 2;
151 unsigned address = getPatternAddress<Policy, false>(vram, nameAddr, patternBase,
x, y);
153 byte data = Policy::readPatternTable(vram, address);
154 Policy::draw1((address & 1) ? palette1 : palette0, buffer, info, data & 0x0F);
161 while ((
x & 7) && (width > 0)) {
162 draw2<Policy, true>(vram, (address & 1) ? palette1 : palette0, buffer, info, address, width);
165 nameAddr = nextNameAddr<Policy>(nameAddr);
167 assert((
x & 7) == 0 || (width <= 0));
168 while ((width & ~7) > 0) {
169 unsigned address = getPatternAddress<Policy, true>(vram, nameAddr, patternBase,
x, y);
170 draw2<Policy, false>(vram, palette0, buffer, info, address, width);
171 draw2<Policy, false>(vram, palette1, buffer, info, address, width);
172 draw2<Policy, false>(vram, palette0, buffer, info, address, width);
173 draw2<Policy, false>(vram, palette1, buffer, info, address, width);
174 nameAddr = nextNameAddr<Policy>(nameAddr);
178 unsigned address = getPatternAddress<Policy, true>(vram, nameAddr, patternBase,
x, y);
180 draw2<Policy, true>(vram, (address & 1) ? palette1 : palette0, buffer, info, address, width);
185 template<
typename Policy,
typename Pixel>
186 static void renderPattern2(
188 unsigned displayAX,
unsigned displayAY,
unsigned nameA,
unsigned patternA,
const Pixel* palA,
189 unsigned displayBX,
unsigned displayBY,
unsigned nameB,
unsigned patternB,
const Pixel* palB)
191 renderPattern<Policy>(
192 vram, buffer, info, bgCol, width1,
193 displayAX, displayAY, nameA, patternA, palA, palA);
198 displayBX = (displayBX + width1) & 511;
200 renderPattern<Policy>(
201 vram, buffer, info, bgCol, width2,
202 displayBX, displayBY, nameB, patternB, palB, palB);
205 template<
typename Policy,
typename Pixel>
206 static void renderSprites(
207 V9990VRAM& vram,
unsigned spritePatternTable,
const Pixel* palette64,
208 Pixel* __restrict buffer,
byte* __restrict info,
209 int displayX,
int displayEnd,
unsigned displayY)
211 constexpr
unsigned spriteTable = 0x3FE00;
214 int visibleSprites[16 + 1];
217 for (
auto sprite :
xrange(125)) {
218 unsigned spriteInfo = spriteTable + 4 * sprite;
219 byte spriteY = Policy::readSpriteAttr(vram, spriteInfo) + 1;
220 byte posY = displayY - spriteY;
222 byte attr = Policy::readSpriteAttr(vram, spriteInfo + 3);
228 visibleSprites[index++] = sprite;
230 if (index == index_max)
break;
233 visibleSprites[index] = -1;
236 for (
unsigned sprite = 0; visibleSprites[sprite] != -1; ++sprite) {
237 unsigned addr = spriteTable + 4 * visibleSprites[sprite];
238 byte spriteAttr = Policy::readSpriteAttr(vram, addr + 3);
239 bool front = (spriteAttr & 0x20) == 0;
240 byte level = front ? 2 : 1;
241 int spriteX = Policy::readSpriteAttr(vram, addr + 2);
242 spriteX += 256 * (spriteAttr & 0x03);
243 if (spriteX > 1008) spriteX -= 1024;
244 byte spriteY = Policy::readSpriteAttr(vram, addr + 0);
245 byte spriteNo = Policy::readSpriteAttr(vram, addr + 1);
246 spriteY = displayY - (spriteY + 1);
247 unsigned patAddr = spritePatternTable + Policy::spritePatOfst(spriteNo, spriteY);
248 const Pixel* palette = palette64 + ((spriteAttr >> 2) & 0x30);
249 for (
int x = 0;
x < 16;
x +=2) {
250 auto draw = [&](
int xPos,
size_t p) {
251 if ((displayX <= xPos) && (xPos < displayEnd)) {
252 size_t xx = xPos - displayX;
254 if (info[xx] < level) {
255 buffer[xx] = palette[p];
261 byte data = Policy::readPatternTable(vram, patAddr++);
262 draw(spriteX +
x + 0, data >> 4);
263 draw(spriteX +
x + 1, data & 0x0F);
268 template<
typename Pixel>
270 Pixel* linePtr,
unsigned displayX,
unsigned displayWidth,
271 unsigned displayY,
unsigned displayYA,
unsigned displayYB,
274 unsigned prioX = vdp.getPriorityControlX();
275 unsigned prioY = vdp.getPriorityControlY();
276 if (displayY >= prioY) prioX = 0;
278 unsigned displayAX = (displayX + vdp.getScrollAX()) & 511;
279 unsigned displayBX = (displayX + vdp.getScrollBX()) & 511;
283 unsigned rollMask = vdp.getRollMask(0x1FF);
284 unsigned scrollAY = vdp.getScrollAY();
285 unsigned scrollBY = vdp.getScrollBY();
286 unsigned scrollAYBase = scrollAY & ~rollMask & 0x1FF;
287 unsigned displayAY = scrollAYBase + ((displayYA + scrollAY) & rollMask);
288 unsigned displayBY = (displayYB + scrollBY) & 0x1FF;
290 unsigned displayEnd = displayX + displayWidth;
291 unsigned end1 = std::max<int>(0, std::min<int>(prioX, displayEnd) - displayX);
294 Pixel bgCol = palette64[vdp.getBackDropColor()];
295 byte offset = vdp.getPaletteOffset();
296 const Pixel* palA = palette64 + ((offset & 0x03) << 4);
297 const Pixel* palB = palette64 + ((offset & 0x0C) << 2);
298 renderPattern2<P1BackgroundPolicy>(
299 vram, linePtr,
nullptr, bgCol, end1, displayWidth,
300 displayBX, displayBY, 0x7E000, 0x40000, palB,
301 displayAX, displayAY, 0x7C000, 0x00000, palA);
304 assert(displayWidth <= 256);
307 renderPattern2<P1ForegroundPolicy>(
308 vram, linePtr, info, bgCol, end1, displayWidth,
309 displayAX, displayAY, 0x7C000, 0x00000, palA,
310 displayBX, displayBY, 0x7E000, 0x40000, palB);
314 unsigned spritePatternTable = vdp.getSpritePatternAddress(
P1);
315 renderSprites<P1Policy>(
316 vram, spritePatternTable, palette64,
317 linePtr, info, displayX, displayEnd, displayY);
321 template<
typename Pixel>
323 Pixel* linePtr,
unsigned displayX,
unsigned displayWidth,
324 unsigned displayY,
unsigned displayYA,
bool drawSprites)
326 unsigned displayAX = (displayX + vdp.getScrollAX()) & 1023;
328 unsigned scrollY = vdp.getScrollAY();
329 unsigned rollMask = vdp.getRollMask(0x1FF);
330 unsigned scrollYBase = scrollY & ~rollMask & 0x1FF;
331 unsigned displayAY = scrollYBase + ((displayYA + scrollY) & rollMask);
333 unsigned displayEnd = displayX + displayWidth;
336 assert(displayWidth <= 512);
339 Pixel bgCol = palette64[vdp.getBackDropColor()];
340 byte offset = vdp.getPaletteOffset();
341 const Pixel* palette0 = palette64 + ((offset & 0x03) << 4);
342 const Pixel* palette1 = palette64 + ((offset & 0x0C) << 2);
343 renderPattern<P2Policy>(
344 vram, linePtr, info, bgCol, displayWidth,
345 displayAX, displayAY, 0x7C000, 0x00000, palette0, palette1);
349 unsigned spritePatternTable = vdp.getSpritePatternAddress(
P2);
350 renderSprites<P2Policy>(
351 vram, spritePatternTable, palette64,
352 linePtr, info, displayX, displayEnd, displayY);
361 #if HAVE_32BPP || COMPONENT_GL
V9990P1Converter(V9990 &vdp, const Pixel *palette64)
void convertLine(Pixel *linePtr, unsigned displayX, unsigned displayWidth, unsigned displayY, unsigned displayYA, unsigned displayYB, bool drawSprites)
V9990P2Converter(V9990 &vdp, const Pixel *palette64)
void convertLine(Pixel *linePtr, unsigned displayX, unsigned displayWidth, unsigned displayY, unsigned displayYA, bool drawSprites)
byte readVRAMDirect(unsigned address)
byte readVRAMP1(unsigned address)
byte readVRAMBx(unsigned address)
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
This file implemented 3 utility functions:
constexpr KeyMatrixPosition x
Keyboard bindings.
static constexpr bool DRAW_BACKDROP
static void draw1(const Pixel *palette, Pixel *buffer, byte *, size_t p)
static constexpr bool DRAW_BACKDROP
static void draw1(const Pixel *palette, Pixel *buffer, byte *info, size_t p)
static byte readSpriteAttr(V9990VRAM &vram, unsigned addr)
static constexpr unsigned NAME_CHARS
static byte readNameTable(V9990VRAM &vram, unsigned addr)
static byte readPatternTable(V9990VRAM &vram, unsigned addr)
static unsigned spritePatOfst(byte spriteNo, byte spriteY)
static constexpr unsigned IMAGE_WIDTH
static constexpr unsigned PATTERN_CHARS
static constexpr unsigned SCREEN_WIDTH
static byte readNameTable(V9990VRAM &vram, unsigned addr)
static byte readSpriteAttr(V9990VRAM &vram, unsigned addr)
static void draw1(const Pixel *palette, Pixel *buffer, byte *info, size_t p)
static byte readPatternTable(V9990VRAM &vram, unsigned addr)
static constexpr unsigned NAME_CHARS
static constexpr unsigned IMAGE_WIDTH
static unsigned spritePatOfst(byte spriteNo, byte spriteY)
static constexpr bool DRAW_BACKDROP
static constexpr unsigned SCREEN_WIDTH
static constexpr unsigned PATTERN_CHARS
constexpr auto xrange(T e)