7 #include "build-info.hh" 8 #include "components.hh" 15 template<
typename Pixel>
17 : vdp(vdp_), vram(vdp.getVRAM())
18 , palette64(palette64_)
22 template<
bool ALIGNED>
23 static unsigned getPatternAddress(
24 V9990VRAM& vram,
unsigned nameAddr,
unsigned patternBase,
unsigned x,
unsigned y)
26 assert(!
ALIGNED || ((x & 7) == 0));
27 unsigned patternNum = (vram.
readVRAMP1(nameAddr + 0) +
29 unsigned x2 = (patternNum % 32) * 4 + (
ALIGNED ? 0 : ((x & 7) / 2));
30 unsigned y2 = (patternNum / 32) * 1024 + y;
31 return patternBase + y2 + x2;
34 static unsigned nextNameAddr(
unsigned addr)
36 return (addr & ~127) | ((addr + 2) & 127);
39 template<
bool BACKGROUND,
typename Pixel>
40 static void draw1(
const Pixel* palette,
Pixel* __restrict buffer,
byte* __restrict info,
size_t p)
46 if (p) *buffer = palette[p];
50 template<
bool BACKGROUND,
bool CHECK_WIDTH,
typename Pixel>
53 unsigned& address,
int& width)
56 draw1<BACKGROUND>(palette, buffer + 0, info + 0, data >> 4);
57 if (!CHECK_WIDTH || (width != 1)) {
58 draw1<BACKGROUND>(palette, buffer + 1, info + 1, data & 0x0F);
65 template<
bool BACKGROUND,
typename Pixel>
66 static void renderPattern2(
68 int width,
unsigned x,
unsigned y,
69 unsigned nameTable,
unsigned patternBase,
const Pixel* palette)
72 if (width == 0)
return;
74 unsigned nameAddr = nameTable + (((y / 8) * 64 + (x / 8)) * 2);
78 unsigned address = getPatternAddress<false>(vram, nameAddr, patternBase, x, y);
80 byte data = vram.readVRAMP1(address++);
81 draw1<BACKGROUND>(palette, buffer, info, data & 0x0F);
86 while ((x & 7) && (width > 0)) {
87 draw2<BACKGROUND, true>(vram, palette, buffer, info, address, width);
90 nameAddr = nextNameAddr(nameAddr);
92 assert((x & 7) == 0 || (width <= 0));
94 unsigned address = getPatternAddress<true>(vram, nameAddr, patternBase, x, y);
95 draw2<BACKGROUND, false>(vram, palette, buffer, info, address, width);
96 draw2<BACKGROUND, false>(vram, palette, buffer, info, address, width);
97 draw2<BACKGROUND, false>(vram, palette, buffer, info, address, width);
98 draw2<BACKGROUND, false>(vram, palette, buffer, info, address, width);
99 nameAddr = nextNameAddr(nameAddr);
103 unsigned address = getPatternAddress<true>(vram, nameAddr, patternBase, x, y);
105 draw2<BACKGROUND, true>(vram, palette, buffer, info, address, width);
110 template<
bool BACKGROUND,
typename Pixel>
111 static void renderPattern(
113 unsigned displayAX,
unsigned displayAY,
unsigned nameA,
unsigned patternA,
const Pixel* palA,
114 unsigned displayBX,
unsigned displayBY,
unsigned nameB,
unsigned patternB,
const Pixel* palB)
120 col0A.
emplace(const_cast<Pixel*>(palA)[0], bgcol);
121 col0B.
emplace(const_cast<Pixel*>(palB)[0], bgcol);
124 renderPattern2<BACKGROUND>(
125 vram, buffer, info, width1,
126 displayAX, displayAY, nameA, patternA, palA);
131 displayBX = (displayBX + width1) & 511;
133 renderPattern2<BACKGROUND>(
134 vram, buffer, info, width2,
135 displayBX, displayBY, nameB, patternB, palB);
138 static void determineVisibleSprites(
139 V9990VRAM& vram,
int* __restrict visibleSprites,
unsigned displayY)
141 constexpr
unsigned spriteTable = 0x3FE00;
145 for (
unsigned sprite = 0; sprite < 125; ++sprite) {
146 unsigned spriteInfo = spriteTable + 4 * sprite;
148 byte posY = displayY - spriteY;
156 visibleSprites[index++] = sprite;
158 if (index == index_max)
break;
161 visibleSprites[index] = -1;
164 template<
typename Pixel>
165 static void renderSprites(
166 V9990VRAM& vram,
unsigned spritePatternTable,
const Pixel* palette64,
167 Pixel* __restrict buffer,
byte* __restrict info,
168 int displayX,
int displayEnd,
unsigned displayY,
169 const int* __restrict visibleSprites)
171 static const unsigned spriteTable = 0x3FE00;
173 for (
unsigned sprite = 0; visibleSprites[sprite] != -1; ++sprite) {
174 unsigned addr = spriteTable + 4 * visibleSprites[sprite];
176 bool front = (spriteAttr & 0x20) == 0;
177 byte level = front ? 2 : 1;
179 spriteX += 256 * (spriteAttr & 0x03);
180 if (spriteX > 1008) spriteX -= 1024;
183 spriteY = displayY - (spriteY + 1);
184 unsigned patAddr = spritePatternTable
185 + (128 * ((spriteNo & 0xF0) + spriteY))
186 + ( 8 * (spriteNo & 0x0F));
187 const Pixel* palette = palette64 + ((spriteAttr >> 2) & 0x30);
188 for (
int x = 0; x < 16; x +=2) {
189 auto draw = [&](
int xPos,
size_t p) {
190 if ((displayX <= xPos) && (xPos < displayEnd)) {
191 size_t xx = xPos - displayX;
193 if (info[xx] < level) {
194 buffer[xx] = palette[p];
201 draw(spriteX + x + 0, data >> 4);
202 draw(spriteX + x + 1, data & 0x0F);
207 template<
typename Pixel>
209 Pixel* linePtr,
unsigned displayX,
unsigned displayWidth,
210 unsigned displayY,
unsigned displayYA,
unsigned displayYB,
215 if (displayY >= prioY) prioX = 0;
217 unsigned displayAX = (displayX + vdp.
getScrollAX()) & 511;
218 unsigned displayBX = (displayX + vdp.
getScrollBX()) & 511;
225 unsigned scrollAYBase = scrollAY & ~rollMask & 0x1FF;
226 unsigned displayAY = scrollAYBase + ((displayYA + scrollAY) & rollMask);
227 unsigned displayBY = (displayYB + scrollBY) & 0x1FF;
229 unsigned displayEnd = displayX + displayWidth;
230 unsigned end1 = std::max<int>(0, std::min<int>(prioX, displayEnd) - displayX);
235 const Pixel* palA = palette64 + ((offset & 0x03) << 4);
236 const Pixel* palB = palette64 + ((offset & 0x0C) << 2);
237 renderPattern<true>(vram, linePtr,
nullptr, bgcol, end1, displayWidth,
238 displayBX, displayBY, 0x7E000, 0x40000, palB,
239 displayAX, displayAY, 0x7C000, 0x00000, palA);
242 assert(displayWidth <= 256);
245 renderPattern<false>(vram, linePtr, info, bgcol, end1, displayWidth,
246 displayAX, displayAY, 0x7C000, 0x00000, palA,
247 displayBX, displayBY, 0x7E000, 0x40000, palB);
251 int visibleSprites[16 + 1];
252 determineVisibleSprites(vram, visibleSprites, displayY);
254 renderSprites(vram, spritePatternTable, palette64,
255 linePtr, info, displayX, displayEnd, displayY,
264 #if HAVE_32BPP || COMPONENT_GL Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
#define ALIGNED(EXPRESSION, ALIGNMENT)
unsigned getRollMask(unsigned maxMask) const
Returns the vertical roll mask.
int getSpritePatternAddress(V9990DisplayMode m) const
Return the sprite pattern table base address.
uint8_t byte
8 bit unsigned integer
byte readVRAMP1(unsigned address)
void emplace(Args &&... args)
constexpr auto data(C &c) -> decltype(c.data())
byte getPaletteOffset() const
Get palette offset.
unsigned getPriorityControlX() const
Thanks to enen for testing this on a real cartridge:
unsigned getScrollBY() const
Returns the Y scroll offset for screen B of P1 mode.
unsigned getScrollBX() const
Returns the X scroll offset for screen B of P1 mode.
unsigned getScrollAX() const
Returns the X scroll offset for screen A of P1 and other modes.
V9990P1Converter(V9990 &vdp, const Pixel *palette64)
unsigned getPriorityControlY() const
unsigned getScrollAY() const
Returns the Y scroll offset for screen A of P1 and other modes.
byte getBackDropColor() const
Return the current back drop color.
void convertLine(Pixel *linePtr, unsigned displayX, unsigned displayWidth, unsigned displayY, unsigned displayYA, unsigned displayYB, bool drawSprites)