18 : vdp(vdp_), vram(vdp.getVRAM())
19 , palette64(palette64_)
24 : vdp(vdp_), vram(vdp.getVRAM()), palette64(palette64_)
39 return (128 * ((spriteNo & 0xF0) + spriteY))
40 + ( 8 * (spriteNo & 0x0F));
49 std::span<const Pixel, 16> palette,
Pixel* __restrict buffer,
50 byte* __restrict ,
size_t p)
58 std::span<const Pixel, 16> palette,
Pixel* __restrict buffer,
59 byte* __restrict info,
size_t p)
62 if (p) *buffer = palette[p];
77 return (256 * (((spriteNo & 0xE0) >> 1) + spriteY))
78 + ( 8 * (spriteNo & 0x1F));
81 std::span<const Pixel, 16> palette,
Pixel* __restrict buffer,
82 byte* __restrict info,
size_t p)
94template<
typename Policy,
bool ALIGNED>
95static unsigned getPatternAddress(
96 V9990VRAM& vram,
unsigned nameAddr,
unsigned patternBase,
unsigned x,
unsigned y)
98 assert(!ALIGNED || ((x & 7) == 0));
99 unsigned patternNum = (Policy::readNameTable(vram, nameAddr + 0) +
100 Policy::readNameTable(vram, nameAddr + 1) * 256) & 0x1FFF;
101 constexpr auto PATTERN_PITCH = Policy::PATTERN_CHARS * 8 * (8 / 2);
102 unsigned x2 = (patternNum % Policy::PATTERN_CHARS) * 4 + (ALIGNED ? 0 : ((x & 7) / 2));
103 unsigned y2 = (patternNum / Policy::PATTERN_CHARS) * PATTERN_PITCH + y;
104 return patternBase + y2 + x2;
107template<
typename Policy>
108static constexpr unsigned nextNameAddr(
unsigned addr)
110 constexpr auto MASK = (2 * Policy::NAME_CHARS) - 1;
111 return (addr & ~MASK) | ((addr + 2) & MASK);
114template<
typename Policy,
bool CHECK_WIDTH>
116 V9990VRAM& vram, std::span<const Pixel, 16> palette,
Pixel* __restrict& buffer,
byte* __restrict& info,
117 unsigned& address,
int& width)
119 byte data = Policy::readPatternTable(vram, address++);
120 Policy::draw1(palette, buffer + 0, info + 0, data >> 4);
121 if (!CHECK_WIDTH || (width != 1)) {
122 Policy::draw1(palette, buffer + 1, info + 1, data & 0x0F);
129template<
typename Policy>
130static void renderPattern(
131 V9990VRAM& vram,
Pixel* __restrict buffer, std::span<byte> info_,
132 Pixel bgCol,
unsigned x,
unsigned y,
133 unsigned nameTable,
unsigned patternBase,
134 std::span<const Pixel, 16> palette0, std::span<const Pixel, 16> palette1)
136 assert(x < Policy::IMAGE_WIDTH);
137 auto width = narrow<int>(info_.size());
138 if (width == 0)
return;
139 byte* info = info_.data();
141 std::optional<ScopedAssign<Pixel>> col0, col1;
142 if constexpr (Policy::DRAW_BACKDROP) {
147 col0.emplace(*
const_cast<Pixel*
>(palette0.data()), bgCol);
148 col1.emplace(*
const_cast<Pixel*
>(palette1.data()), bgCol);
151 unsigned nameAddr = nameTable + (((y / 8) * Policy::NAME_CHARS + (x / 8)) * 2);
152 y = (y & 7) * Policy::NAME_CHARS * 2;
155 unsigned address = getPatternAddress<Policy, false>(vram, nameAddr, patternBase, x, y);
157 byte data = Policy::readPatternTable(vram, address);
158 Policy::draw1((address & 1) ? palette1 : palette0, buffer, info, data & 0x0F);
165 while ((x & 7) && (width > 0)) {
166 draw2<Policy, true>(vram, (address & 1) ? palette1 : palette0, buffer, info, address, width);
169 nameAddr = nextNameAddr<Policy>(nameAddr);
171 assert((x & 7) == 0 || (width <= 0));
172 while ((width & ~7) > 0) {
173 unsigned address = getPatternAddress<Policy, true>(vram, nameAddr, patternBase, x, y);
174 draw2<Policy, false>(vram, palette0, buffer, info, address, width);
175 draw2<Policy, false>(vram, palette1, buffer, info, address, width);
176 draw2<Policy, false>(vram, palette0, buffer, info, address, width);
177 draw2<Policy, false>(vram, palette1, buffer, info, address, width);
178 nameAddr = nextNameAddr<Policy>(nameAddr);
182 unsigned address = getPatternAddress<Policy, true>(vram, nameAddr, patternBase, x, y);
184 draw2<Policy, true>(vram, (address & 1) ? palette1 : palette0, buffer, info, address, width);
189template<
typename Policy>
190static void renderPattern2(
191 V9990VRAM& vram,
Pixel* buffer, std::span<byte, 256> info,
Pixel bgCol,
unsigned width1,
unsigned width2,
192 unsigned displayAX,
unsigned displayAY,
unsigned nameA,
unsigned patternA, std::span<const Pixel, 16> palA,
193 unsigned displayBX,
unsigned displayBY,
unsigned nameB,
unsigned patternB, std::span<const Pixel, 16> palB)
195 renderPattern<Policy>(
196 vram, buffer,
subspan(info, 0, width1), bgCol,
197 displayAX, displayAY, nameA, patternA, palA, palA);
201 displayBX = (displayBX + width1) & 511;
203 renderPattern<Policy>(
204 vram, buffer,
subspan(info, width1, width2), bgCol,
205 displayBX, displayBY, nameB, patternB, palB, palB);
208template<
typename Policy>
209static void renderSprites(
210 V9990VRAM& vram,
unsigned spritePatternTable, std::span<const Pixel, 64> palette64,
211 Pixel* __restrict buffer, std::span<byte> info,
212 int displayX,
int displayEnd,
unsigned displayY)
214 constexpr unsigned spriteTable = 0x3FE00;
217 std::array<int, 16 + 1> visibleSprites;
220 for (
auto sprite :
xrange(125)) {
221 unsigned spriteInfo = spriteTable + 4 * sprite;
222 byte spriteY = Policy::readSpriteAttr(vram, spriteInfo) + 1;
223 auto posY = narrow_cast<byte>(displayY - spriteY);
225 if (
byte attr = Policy::readSpriteAttr(vram, spriteInfo + 3);
231 visibleSprites[index++] = sprite;
233 if (index == index_max)
break;
236 visibleSprites[index] = -1;
239 for (
unsigned sprite = 0; visibleSprites[sprite] != -1; ++sprite) {
240 unsigned addr = spriteTable + 4 * visibleSprites[sprite];
241 byte spriteAttr = Policy::readSpriteAttr(vram, addr + 3);
242 bool front = (spriteAttr & 0x20) == 0;
243 byte level = front ? 2 : 1;
244 int spriteX = Policy::readSpriteAttr(vram, addr + 2);
245 spriteX += 256 * (spriteAttr & 0x03);
246 if (spriteX > 1008) spriteX -= 1024;
247 byte spriteY = Policy::readSpriteAttr(vram, addr + 0);
248 byte spriteNo = Policy::readSpriteAttr(vram, addr + 1);
249 spriteY = narrow_cast<byte>(displayY - (spriteY + 1));
250 unsigned patAddr = spritePatternTable + Policy::spritePatOfst(spriteNo, spriteY);
251 auto palette16 = subspan<16>(palette64, (spriteAttr >> 2) & 0x30);
252 for (
int x = 0; x < 16; x +=2) {
253 auto draw = [&](
int xPos,
size_t p) {
254 if ((displayX <= xPos) && (xPos < displayEnd)) {
255 size_t xx = xPos - displayX;
257 if (info[xx] < level) {
258 buffer[xx] = palette16[p];
264 byte data = Policy::readPatternTable(vram, patAddr++);
265 draw(spriteX + x + 0, data >> 4);
266 draw(spriteX + x + 1, data & 0x0F);
272 std::span<Pixel> buf,
unsigned displayX,
unsigned displayY,
273 unsigned displayYA,
unsigned displayYB,
bool drawSprites)
275 Pixel* __restrict linePtr = buf.data();
276 auto displayWidth = narrow<unsigned>(buf.size());
280 if (displayY >= prioY) prioX = 0;
282 unsigned displayAX = (displayX + vdp.
getScrollAX()) & 511;
283 unsigned displayBX = (displayX + vdp.
getScrollBX()) & 511;
290 unsigned scrollAYBase = scrollAY & ~rollMask & 0x1FF;
291 unsigned displayAY = scrollAYBase + ((displayYA + scrollAY) & rollMask);
292 unsigned displayBY = (displayYB + scrollBY) & 0x1FF;
294 unsigned displayEnd = displayX + displayWidth;
295 unsigned end1 = std::max(0, narrow<int>(std::min(prioX, displayEnd)) - narrow<int>(displayX));
297 std::array<byte, 256> info;
302 auto palA = subspan<16>(palette64, (offset & 0x03) << 4);
303 auto palB = subspan<16>(palette64, (offset & 0x0C) << 2);
304 renderPattern2<P1BackgroundPolicy>(
305 vram, linePtr, info, bgCol, end1, displayWidth,
306 displayBX, displayBY, 0x7E000, 0x40000, palB,
307 displayAX, displayAY, 0x7C000, 0x00000, palA);
310 assert(displayWidth <= 256);
311 renderPattern2<P1ForegroundPolicy>(
312 vram, linePtr, info, bgCol, end1, displayWidth,
313 displayAX, displayAY, 0x7C000, 0x00000, palA,
314 displayBX, displayBY, 0x7E000, 0x40000, palB);
319 renderSprites<P1Policy>(
320 vram, spritePatternTable, palette64,
321 linePtr, info, displayX, displayEnd, displayY);
326 std::span<Pixel> buf,
unsigned displayX,
unsigned displayY,
327 unsigned displayYA,
bool drawSprites)
329 Pixel* __restrict linePtr = buf.data();
330 auto displayWidth = narrow<unsigned>(buf.size());
332 unsigned displayAX = (displayX + vdp.
getScrollAX()) & 1023;
336 unsigned scrollYBase = scrollY & ~rollMask & 0x1FF;
337 unsigned displayAY = scrollYBase + ((displayYA + scrollY) & rollMask);
339 unsigned displayEnd = displayX + displayWidth;
342 assert(displayWidth <= 512);
343 std::array<byte, 512> info;
346 auto palette0 = subspan<16>(palette64, (offset & 0x03) << 4);
347 auto palette1 = subspan<16>(palette64, (offset & 0x0C) << 2);
348 renderPattern<P2Policy>(
349 vram, linePtr,
subspan(info, 0, displayWidth), bgCol,
350 displayAX, displayAY, 0x7C000, 0x00000, palette0, palette1);
355 renderSprites<P2Policy>(
356 vram, spritePatternTable, palette64,
357 linePtr, info, displayX, displayEnd, displayY);
V9990P1Converter(V9990 &vdp, std::span< const Pixel, 64 > palette64)
void convertLine(std::span< Pixel > buf, unsigned displayX, unsigned displayY, unsigned displayYA, unsigned displayYB, bool drawSprites)
V9990P2Converter(V9990 &vdp, std::span< const Pixel, 64 > palette64)
void convertLine(std::span< Pixel > buf, unsigned displayX, unsigned displayY, unsigned displayYA, bool drawSprites)
byte readVRAMDirect(unsigned address) const
byte readVRAMBx(unsigned address) const
byte readVRAMP1(unsigned address) const
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
int getSpritePatternAddress(V9990DisplayMode m) const
Return the sprite pattern table base address.
byte getPaletteOffset() const
Get palette offset.
byte getBackDropColor() const
Return the current back drop color.
unsigned getScrollBX() const
Returns the X scroll offset for screen B of P1 mode.
unsigned getPriorityControlX() const
unsigned getPriorityControlY() const
unsigned getScrollAX() const
Returns the X scroll offset for screen A of P1 and other modes.
unsigned getScrollBY() const
Returns the Y scroll offset for screen B of P1 mode.
unsigned getScrollAY() const
Returns the Y scroll offset for screen A of P1 and other modes.
unsigned getRollMask(unsigned maxMask) const
Returns the vertical roll mask.
This file implemented 3 utility functions:
CharacterConverter::Pixel Pixel
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
static void draw1(std::span< const Pixel, 16 > palette, Pixel *buffer, byte *, size_t p)
static constexpr bool DRAW_BACKDROP
static constexpr bool DRAW_BACKDROP
static void draw1(std::span< const Pixel, 16 > palette, Pixel *buffer, byte *info, size_t p)
static constexpr unsigned NAME_CHARS
static byte readSpriteAttr(const 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 readPatternTable(const V9990VRAM &vram, unsigned addr)
static byte readNameTable(const V9990VRAM &vram, unsigned addr)
static void draw1(std::span< const Pixel, 16 > palette, Pixel *buffer, byte *info, size_t p)
static constexpr unsigned NAME_CHARS
static constexpr unsigned IMAGE_WIDTH
static byte readNameTable(const V9990VRAM &vram, unsigned addr)
static byte readPatternTable(const V9990VRAM &vram, unsigned addr)
static unsigned spritePatOfst(byte spriteNo, byte spriteY)
static constexpr bool DRAW_BACKDROP
static constexpr unsigned SCREEN_WIDTH
static constexpr unsigned PATTERN_CHARS
static byte readSpriteAttr(const V9990VRAM &vram, unsigned addr)
constexpr auto xrange(T e)