15 std::span<const Pixel, 64> palette64_, std::span<const int16_t, 64> palette64_32768_,
16 std::span<const Pixel, 256> palette256_, std::span<const int16_t, 256> palette256_32768_,
17 std::span<const Pixel, 32768> palette32768_)
18 : vdp(vdp_), vram(vdp.getVRAM())
19 , palette64 (palette64_ ), palette64_32768 (palette64_32768_ )
20 , palette256(palette256_), palette256_32768(palette256_32768_)
21 , palette32768(palette32768_)
26template<
bool YJK,
bool PAL,
bool SKIP, std::
unsigned_
integral Pixel,
typename ColorLookup>
27static inline void draw_YJK_YUV_PAL(
29 Pixel* __restrict& out,
unsigned& address,
int firstX = 0)
31 std::array<byte, 4> data;
32 for (
auto& d : data) {
36 int u = (data[2] & 7) + ((data[3] & 3) << 3) - ((data[3] & 4) << 3);
37 int v = (data[0] & 7) + ((data[1] & 3) << 3) - ((data[1] & 4) << 3);
39 for (
auto i :
xrange(SKIP ? firstX : 0, 4)) {
40 if (PAL && (data[i] & 0x08)) {
41 *out++ = color.lookup64(data[i] >> 4);
43 int y = (data[i] & 0xF8) >> 3;
44 int r = std::clamp(y + u, 0, 31);
45 int g = std::clamp((5 * y - 2 * u - v) / 4, 0, 31);
46 int b = std::clamp(y + v, 0, 31);
49 if constexpr (YJK) std::swap(
g, b);
50 *out++ = color.lookup32768((
g << 10) + (r << 5) + b);
55template<std::
unsigned_
integral Pixel,
typename ColorLookup>
56static void rasterBYUV(
57 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
58 std::span<Pixel> buf,
unsigned x,
unsigned y)
60 Pixel* __restrict out = buf.data();
61 int nrPixels = narrow<int>(buf.size());
62 unsigned address = (x & ~3) + y * vdp.getImageWidth();
64 draw_YJK_YUV_PAL<false, false, true>(
65 color, vram, out, address, x & 3);
66 nrPixels -= narrow<int>(4 - (x & 3));
68 for (; nrPixels > 0; nrPixels -= 4) {
69 draw_YJK_YUV_PAL<false, false, false>(
70 color, vram, out, address);
75template<std::
unsigned_
integral Pixel,
typename ColorLookup>
76static void rasterBYUVP(
77 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
78 std::span<Pixel> buf,
unsigned x,
unsigned y)
82 Pixel* __restrict out = buf.data();
83 int nrPixels = narrow<int>(buf.size());
84 unsigned address = (x & ~3) + y * vdp.getImageWidth();
86 draw_YJK_YUV_PAL<false, true, true>(
87 color, vram, out, address, x & 3);
88 nrPixels -= narrow<int>(4 - (x & 3));
90 for (; nrPixels > 0; nrPixels -= 4) {
91 draw_YJK_YUV_PAL<false, true, false>(
92 color, vram, out, address);
97template<std::
unsigned_
integral Pixel,
typename ColorLookup>
98static void rasterBYJK(
99 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
100 std::span<Pixel> buf,
unsigned x,
unsigned y)
102 Pixel* __restrict out = buf.data();
103 int nrPixels = narrow<int>(buf.size());
104 unsigned address = (x & ~3) + y * vdp.getImageWidth();
106 draw_YJK_YUV_PAL<true, false, true>(
107 color, vram, out, address, x & 3);
108 nrPixels -= narrow<int>(4 - (x & 3));
110 for (; nrPixels > 0; nrPixels -= 4) {
111 draw_YJK_YUV_PAL<true, false, false>(
112 color, vram, out, address);
117template<std::
unsigned_
integral Pixel,
typename ColorLookup>
118static void rasterBYJKP(
119 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
120 std::span<Pixel> buf,
unsigned x,
unsigned y)
124 Pixel* __restrict out = buf.data();
125 int nrPixels = narrow<int>(buf.size());
126 unsigned address = (x & ~3) + y * vdp.getImageWidth();
128 draw_YJK_YUV_PAL<true, true, true>(
129 color, vram, out, address, x & 3);
130 nrPixels -= narrow<int>(4 - (x & 3));
132 for (; nrPixels > 0; nrPixels -= 4) {
133 draw_YJK_YUV_PAL<true, true, false>(
134 color, vram, out, address);
139template<std::
unsigned_
integral Pixel,
typename ColorLookup>
140static void rasterBD16(
141 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
142 std::span<Pixel> buf,
unsigned x,
unsigned y)
144 Pixel* __restrict out = buf.data();
145 int nrPixels = narrow<int>(buf.size());
146 unsigned address = 2 * (x + y * vdp.getImageWidth());
147 if (vdp.isSuperimposing()) {
148 auto transparent = color.lookup256(0);
149 for (; nrPixels > 0; --nrPixels) {
150 byte high = vram.readVRAMBx(address + 1);
154 byte low = vram.readVRAMBx(address + 0);
155 *out = color.lookup32768(low + 256 * high);
161 for (; nrPixels > 0; --nrPixels) {
162 byte low = vram.readVRAMBx(address++);
163 byte high = vram.readVRAMBx(address++);
164 *out++ = color.lookup32768((low + 256 * high) & 0x7FFF);
169template<std::
unsigned_
integral Pixel,
typename ColorLookup>
170static void rasterBD8(
171 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
172 std::span<Pixel> buf,
unsigned x,
unsigned y)
174 Pixel* __restrict out = buf.data();
175 int nrPixels = narrow<int>(buf.size());
176 unsigned address = x + y * vdp.getImageWidth();
177 for (; nrPixels > 0; --nrPixels) {
178 *out++ = color.lookup256(vram.readVRAMBx(address++));
182template<std::
unsigned_
integral Pixel,
typename ColorLookup>
183static void rasterBP6(
184 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
185 std::span<Pixel> buf,
unsigned x,
unsigned y)
187 Pixel* __restrict out = buf.data();
188 int nrPixels = narrow<int>(buf.size());
189 unsigned address = x + y * vdp.getImageWidth();
190 for (; nrPixels > 0; --nrPixels) {
191 *out++ = color.lookup64(vram.readVRAMBx(address++) & 0x3F);
195template<std::
unsigned_
integral Pixel,
typename ColorLookup>
196static void rasterBP4(
197 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
198 std::span<Pixel> buf,
unsigned x,
unsigned y)
200 Pixel* __restrict out = buf.data();
201 int nrPixels = narrow<int>(buf.size());
202 assert(nrPixels > 0);
203 unsigned address = (x + y * vdp.getImageWidth()) / 2;
204 color.set64Offset((vdp.getPaletteOffset() & 0xC) << 2);
206 byte data = vram.readVRAMBx(address++);
207 *out++ = color.lookup64(data & 0x0F);
210 for (; nrPixels > 0; nrPixels -= 2) {
211 byte data = vram.readVRAMBx(address++);
212 *out++ = color.lookup64(data >> 4);
213 *out++ = color.lookup64(data & 0x0F);
217template<std::
unsigned_
integral Pixel,
typename ColorLookup>
218static void rasterBP4HiRes(
219 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
220 std::span<Pixel> buf,
unsigned x,
unsigned y)
225 Pixel* __restrict out = buf.data();
226 int nrPixels = narrow<int>(buf.size());
227 unsigned address = (x + y * vdp.getImageWidth()) / 2;
228 color.set64Offset((vdp.getPaletteOffset() & 0x4) << 2);
230 byte data = vram.readVRAMBx(address++);
231 *out++ = color.lookup64(32 | (data & 0x0F));
234 for (; nrPixels > 0; nrPixels -= 2) {
235 byte data = vram.readVRAMBx(address++);
236 *out++ = color.lookup64( 0 | (data >> 4 ));
237 *out++ = color.lookup64(32 | (data & 0x0F));
242template<std::
unsigned_
integral Pixel,
typename ColorLookup>
243static void rasterBP2(
244 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
245 std::span<Pixel> buf,
unsigned x,
unsigned y)
247 Pixel* __restrict out = buf.data();
248 int nrPixels = narrow<int>(buf.size());
249 assert(nrPixels > 0);
250 unsigned address = (x + y * vdp.getImageWidth()) / 4;
251 color.set64Offset(vdp.getPaletteOffset() << 2);
253 byte data = vram.readVRAMBx(address++);
254 if ((x & 3) <= 1) *out++ = color.lookup64((data & 0x30) >> 4);
255 if ((x & 3) <= 2) *out++ = color.lookup64((data & 0x0C) >> 2);
256 if (
true) *out++ = color.lookup64((data & 0x03) >> 0);
257 nrPixels -= narrow<int>(4 - (x & 3));
259 for (; nrPixels > 0; nrPixels -= 4) {
260 byte data = vram.readVRAMBx(address++);
261 *out++ = color.lookup64((data & 0xC0) >> 6);
262 *out++ = color.lookup64((data & 0x30) >> 4);
263 *out++ = color.lookup64((data & 0x0C) >> 2);
264 *out++ = color.lookup64((data & 0x03) >> 0);
268template<std::
unsigned_
integral Pixel,
typename ColorLookup>
269static void rasterBP2HiRes(
270 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
271 std::span<Pixel> buf,
unsigned x,
unsigned y)
276 Pixel* __restrict out = buf.data();
277 int nrPixels = narrow<int>(buf.size());
278 assert(nrPixels > 0);
279 unsigned address = (x + y * vdp.getImageWidth()) / 4;
280 color.set64Offset((vdp.getPaletteOffset() & 0x7) << 2);
282 byte data = vram.readVRAMBx(address++);
283 if ((x & 3) <= 1) *out++ = color.lookup64(32 | ((data & 0x30) >> 4));
284 if ((x & 3) <= 2) *out++ = color.lookup64( 0 | ((data & 0x0C) >> 2));
285 if (
true) *out++ = color.lookup64(32 | ((data & 0x03) >> 0));
286 nrPixels -= narrow<int>(4 - (x & 3));
288 for (; nrPixels > 0; nrPixels -= 4) {
289 byte data = vram.readVRAMBx(address++);
290 *out++ = color.lookup64( 0 | ((data & 0xC0) >> 6));
291 *out++ = color.lookup64(32 | ((data & 0x30) >> 4));
292 *out++ = color.lookup64( 0 | ((data & 0x0C) >> 2));
293 *out++ = color.lookup64(32 | ((data & 0x03) >> 0));
299template<std::
unsigned_
integral Pixel>
304 std::span<const Pixel, 256> palette256_,
305 std::span<const Pixel, 32768> palette32768_)
306 : palette64Base(palette64_)
307 , palette64(palette64_)
308 , palette256(palette256_)
309 , palette32768(palette32768_)
313 void set64Offset(
size_t offset) { palette64 = palette64Base.subspan(offset); }
319 std::span<const Pixel, 64> palette64Base;
320 std::span<const Pixel> palette64;
321 std::span<const Pixel, 256> palette256;
322 std::span<const Pixel, 32768> palette32768;
330 IndexLookup(std::span<const int16_t, 64> palette64_, std::span<const int16_t, 256> palette256_)
331 : palette64_32768Base(palette64_)
332 , palette64_32768(palette64_)
333 , palette256_32768(palette256_)
337 void set64Offset(
size_t offset) { palette64_32768 = palette64_32768Base.subspan(offset); }
338 [[nodiscard]] int16_t
lookup64 (
size_t idx)
const {
return palette64_32768 [idx]; }
339 [[nodiscard]] int16_t
lookup256 (
size_t idx)
const {
return palette256_32768[idx]; }
340 [[nodiscard]] int16_t
lookup32768(
size_t idx)
const {
return int16_t(idx); }
343 std::span<const int16_t, 64> palette64_32768Base;
344 std::span<const int16_t> palette64_32768;
345 std::span<const int16_t, 256> palette256_32768;
348template<std::
unsigned_
integral Pixel,
typename ColorLookup>
350 ColorLookup color,
const V9990& vdp,
const V9990VRAM& vram,
351 std::span<Pixel> out,
unsigned x,
unsigned y)
355 case BYUV:
return rasterBYUV <Pixel>(color, vdp, vram, out, x, y);
356 case BYUVP:
return rasterBYUVP<Pixel>(color, vdp, vram, out, x, y);
357 case BYJK:
return rasterBYJK <Pixel>(color, vdp, vram, out, x, y);
358 case BYJKP:
return rasterBYJKP<Pixel>(color, vdp, vram, out, x, y);
359 case BD16:
return rasterBD16 <Pixel>(color, vdp, vram, out, x, y);
360 case BD8:
return rasterBD8 <Pixel>(color, vdp, vram, out, x, y);
361 case BP6:
return rasterBP6 <Pixel>(color, vdp, vram, out, x, y);
362 case BP4:
return highRes ? rasterBP4HiRes<Pixel>(color, vdp, vram, out, x, y)
363 : rasterBP4 <
Pixel>(color, vdp, vram, out, x, y);
364 case BP2:
return highRes ? rasterBP2HiRes<Pixel>(color, vdp, vram, out, x, y)
365 : rasterBP2 <
Pixel>(color, vdp, vram, out, x, y);
403 unsigned attrAddr,
unsigned patAddr,
404 int displayY,
bool drawCursor)
406 if (!drawCursor)
return;
408 unsigned attrY = vram.
readVRAMBx(attrAddr + 0) +
411 unsigned cursorLine = (displayY - attrY) & 511;
412 if (cursorLine >= 32)
return;
415 if ((attr & 0x10) || ((attr & 0xe0) == 0x00)) {
421 + (vram.
readVRAMBx(patAddr + 4 * cursorLine + 1) << 16)
422 + (vram.
readVRAMBx(patAddr + 4 * cursorLine + 2) << 8)
423 + (vram.
readVRAMBx(patAddr + 4 * cursorLine + 3) << 0);
430 x = vram.
readVRAMBx(attrAddr + 4) + (attr & 3) * 256;
432 doXor = (attr & 0xe0) == 0x20;
435 color = palette64_32768[colorIdx];
436 if (attr & 0x20)
color ^= 0x7fff;
440 return x != unsigned(-1);
442 [[nodiscard]]
bool dot()
const {
443 return (
x == 0) && (
pattern & 0x80000000);
454 unsigned x{unsigned(-1)};
461 std::span<Pixel> dst,
unsigned x,
unsigned y,
462 int cursorY,
bool drawCursors)
const
464 assert(dst.size() <= 1024);
466 CursorInfo cursor0(vdp, vram, palette64_32768, 0x7fe00, 0x7ff00, cursorY, drawCursors);
467 CursorInfo cursor1(vdp, vram, palette64_32768, 0x7fe08, 0x7ff80, cursorY, drawCursors);
471 std::array<uint16_t, 1024 + 3> buf;
472 raster(colorMode, highRes,
475 subspan(buf, 0, dst.size()), x, y);
482 for (
auto i :
xrange(dst.size())) {
487 buf[i] = cursor0.
color;
489 }
else if (cursor1.
dot()) {
493 buf[i] = cursor1.
color;
502 for (
auto i :
xrange(dst.size())) {
503 dst[i] = palette32768[buf[i]];
507 raster(colorMode, highRes,
509 vdp, vram, dst, x, y);
CursorInfo(const V9990 &vdp, const V9990VRAM &vram, std::span< const int16_t, 64 > palette64_32768, unsigned attrAddr, unsigned patAddr, int displayY, bool drawCursor)
int16_t lookup64(size_t idx) const
IndexLookup(std::span< const int16_t, 64 > palette64_, std::span< const int16_t, 256 > palette256_)
void set64Offset(size_t offset)
int16_t lookup256(size_t idx) const
int16_t lookup32768(size_t idx) const
Pixel lookup256(size_t idx) const
Pixel lookup64(size_t idx) const
void set64Offset(size_t offset)
Pixel lookup32768(size_t idx) const
PaletteLookup(std::span< const Pixel, 64 > palette64_, std::span< const Pixel, 256 > palette256_, std::span< const Pixel, 32768 > palette32768_)
void convertLine(std::span< Pixel > dst, unsigned x, unsigned y, int cursorY, bool drawCursors) const
Convert a line of VRAM into host pixels.
V9990BitmapConverter(V9990 &vdp, std::span< const Pixel, 64 > palette64, std::span< const int16_t, 64 > palette64_32768, std::span< const Pixel, 256 > palette256, std::span< const int16_t, 256 > palette256_32768, std::span< const Pixel, 32768 > palette32768)
void setColorMode(V9990ColorMode colorMode_, V9990DisplayMode display)
Set a different rendering mode.
byte readVRAMBx(unsigned address) const
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
bool isInterlaced() const
Get interlace status.
byte getSpritePaletteOffset() const
return sprite palette offset
This file implemented 3 utility functions:
CharacterConverter::Pixel Pixel
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
constexpr auto xrange(T e)