32 #pragma GCC optimize ("O2") 39 static const RGB222 CGAPalette[16] = {
60 static const RGB222 CGAGraphics4ColorsPalette[4][4] = {
94 GraphicsAdapter::GraphicsAdapter()
96 m_emulation(Emulation::
None),
97 m_videoBuffer(nullptr),
103 m_cursorVisible(false),
104 m_cursorGlyph(nullptr),
106 m_PCGraphicsBackgroundColorIndex(0),
107 m_PCGraphicsForegroundColorIndex(15),
108 m_PCGraphicsPaletteInUse(0)
110 m_font.data =
nullptr;
115 GraphicsAdapter::~GraphicsAdapter()
120 heap_caps_free(m_cursorGlyph);
124 void GraphicsAdapter::setEmulation(Emulation emulation)
126 if (m_emulation != emulation) {
127 m_emulation = emulation;
132 switch (m_emulation) {
138 case Emulation::PC_Text_40x25_16Colors:
141 setCursorShape(5, 7);
142 m_VGADCtrl.setDrawScanlineCallback(drawScanline_PC_Text_40x25_16Colors,
this);
143 m_VGADCtrl.setScanlinesPerCallBack(4);
145 m_columns = m_VGADCtrl.getViewPortWidth() / m_font.width;
146 m_rows = m_VGADCtrl.getViewPortHeight() / m_font.height;
149 case Emulation::PC_Text_80x25_16Colors:
152 setCursorShape(13, 15);
153 m_VGADCtrl.setDrawScanlineCallback(drawScanline_PC_Text_80x25_16Colors,
this);
154 m_VGADCtrl.setScanlinesPerCallBack(8);
156 m_columns = m_VGADCtrl.getViewPortWidth() / m_font.width;
157 m_rows = m_VGADCtrl.getViewPortHeight() / m_font.height;
160 case Emulation::PC_Graphics_320x200_4Colors:
162 m_VGADCtrl.setDrawScanlineCallback(drawScanline_PC_Graphics_320x200_4Colors,
this);
163 m_VGADCtrl.setScanlinesPerCallBack(1);
167 case Emulation::PC_Graphics_640x200_2Colors:
169 m_VGADCtrl.setDrawScanlineCallback(drawScanline_PC_Graphics_640x200_2Colors,
this);
170 m_VGADCtrl.setScanlinesPerCallBack(1);
174 case Emulation::PC_Graphics_HGC_720x348:
176 m_VGADCtrl.setDrawScanlineCallback(drawScanline_PC_Graphics_HGC_720x348,
this);
177 m_VGADCtrl.setScanlinesPerCallBack(2);
191 void GraphicsAdapter::freeLUT()
194 heap_caps_free(m_rawLUT);
199 void GraphicsAdapter::setupLUT()
201 switch (m_emulation) {
206 case Emulation::PC_Text_80x25_16Colors:
207 case Emulation::PC_Text_40x25_16Colors:
210 m_rawLUT = (uint8_t*) heap_caps_malloc(16, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
211 for (
int i = 0; i < 16; ++i)
212 m_rawLUT[i] = m_VGADCtrl.createRawPixel(CGAPalette[i]);
215 case Emulation::PC_Graphics_320x200_4Colors:
218 m_rawLUT = (uint8_t*) heap_caps_malloc(256 * 4, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
219 for (
int i = 0; i < 256; ++i) {
220 for (
int j = 0; j < 4; ++j) {
221 int pixel = (i >> (6 - j * 2)) & 0b11;
222 uint8_t rawPixel = m_VGADCtrl.createRawPixel(pixel == 0 ? CGAPalette[m_PCGraphicsBackgroundColorIndex] : CGAGraphics4ColorsPalette[m_PCGraphicsPaletteInUse][pixel]);
223 m_rawLUT[(i * 4) + (j ^ 2)] = rawPixel;
228 case Emulation::PC_Graphics_640x200_2Colors:
231 m_rawLUT = (uint8_t*) heap_caps_malloc(256 * 8, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
232 for (
int i = 0; i < 256; ++i) {
233 for (
int j = 0; j < 8; ++j) {
234 bool pixel = (i >> (7 - j)) & 1;
235 uint8_t rawPixel = m_VGADCtrl.createRawPixel(pixel ? CGAPalette[m_PCGraphicsForegroundColorIndex] :
RGB222(0, 0, 0));
236 m_rawLUT[(i * 8) + (j ^ 2)] = rawPixel;
241 case Emulation::PC_Graphics_HGC_720x348:
244 m_rawLUT = (uint8_t*) heap_caps_malloc(256 * 8, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
245 for (
int i = 0; i < 256; ++i) {
246 for (
int j = 0; j < 8; ++j) {
247 bool pixel = (i >> (7 - j)) & 1;
248 uint8_t rawPixel = m_VGADCtrl.createRawPixel(
RGB222(pixel * 3, pixel * 3, pixel * 3));
249 m_rawLUT[(i * 8) + (j ^ 2)] = rawPixel;
258 void GraphicsAdapter::setPCGraphicsBackgroundColorIndex(
int colorIndex)
260 m_PCGraphicsBackgroundColorIndex = colorIndex;
265 void GraphicsAdapter::setPCGraphicsForegroundColorIndex(
int colorIndex)
267 m_PCGraphicsForegroundColorIndex = colorIndex;
272 void GraphicsAdapter::setPCGraphicsPaletteInUse(
int paletteIndex)
274 m_PCGraphicsPaletteInUse = paletteIndex;
279 void GraphicsAdapter::setVideoBuffer(
void const * videoBuffer)
281 m_videoBuffer = (uint8_t*) videoBuffer;
285 void GraphicsAdapter::cleanupFont()
288 heap_caps_free((
void*)m_font.data);
289 m_font.data =
nullptr;
294 void GraphicsAdapter::setFont(FontInfo
const * font)
300 auto size = 256 * ((m_font.width + 7) / 8) * m_font.
height;
301 m_font.data = (uint8_t
const *) heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
302 memcpy((
void*)m_font.data, font->data, size);
307 void GraphicsAdapter::setCursorShape(
int start,
int end)
309 if (start != m_cursorStart || end != m_cursorEnd) {
310 m_cursorStart = start;
314 if (start <= end && end >= m_font.height) {
316 end = m_font.height - 1;
320 int charWidthInBytes = (m_font.width + 7) / 8;
322 m_cursorGlyph = (uint8_t*) heap_caps_malloc(charWidthInBytes * m_font.height, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
323 memset(m_cursorGlyph, 0, charWidthInBytes * m_font.height);
324 if (end >= start && start >= 0 && start < m_font.height && end < m_font.height)
325 memset(m_cursorGlyph + (start * charWidthInBytes), 0xff, (end - start + 1) * charWidthInBytes);
330 void GraphicsAdapter::setCursorPos(
int row,
int column)
333 m_cursorCol = column;
337 void IRAM_ATTR GraphicsAdapter::drawScanline_PC_Text_40x25_16Colors(
void * arg, uint8_t * dest,
int scanLine)
339 auto ga = (GraphicsAdapter*) arg;
341 constexpr
int CHARWIDTH = 8;
342 constexpr
int CHARHEIGHT = 8;
343 constexpr
int CHARWIDTHINBYTES = (CHARWIDTH + 7) / 8;
344 constexpr
int CHARSIZEINBYTES = CHARWIDTHINBYTES * CHARHEIGHT;
345 constexpr
int COLUMNS = 40;
346 constexpr
int SCREENWIDTH = 320;
347 constexpr
int LINES = 8;
350 ++ga->m_frameCounter;
352 int charScanline = scanLine & (CHARHEIGHT - 1);
353 int textRow = scanLine / CHARHEIGHT;
355 uint8_t
const * fontData = ga->m_font.data + (charScanline * CHARWIDTHINBYTES);
357 uint8_t * rawLUT = ga->m_rawLUT;
359 uint8_t
const * curItem = ga->m_videoBuffer + (textRow * COLUMNS * 2);
361 bool showCursor = ga->m_cursorVisible && ga->m_cursorRow == textRow && ((ga->m_frameCounter & 0x1f) < 0xf);
362 int cursorCol = ga->m_cursorCol;
364 bool bit7blink = ga->m_bit7blink;
365 bool blinktime = bit7blink && !((ga->m_frameCounter & 0x3f) < 0x1f);
367 for (
int textCol = 0; textCol < COLUMNS; ++textCol) {
369 int charIdx = *curItem++;
370 int charAttr = *curItem++;
374 blink = blinktime && (charAttr & 0x80);
378 uint8_t bg = rawLUT[charAttr >> 4];
379 uint8_t fg = blink ? bg : rawLUT[charAttr & 0xf];
381 const uint8_t colors[2] = { bg, fg };
383 uint8_t
const * charBitmapPtr = fontData + charIdx * CHARSIZEINBYTES;
387 if (showCursor && textCol == cursorCol) {
389 uint8_t
const * cursorBitmapPtr = ga->m_cursorGlyph + (charScanline * CHARWIDTHINBYTES);
391 for (
int charRow = 0; charRow < LINES / 2; ++charRow) {
393 uint32_t charBitmap = *charBitmapPtr | *cursorBitmapPtr;
395 *(destptr + 0) = colors[(
bool)(charBitmap & 0x20)];
396 *(destptr + 1) = colors[(
bool)(charBitmap & 0x10)];
397 *(destptr + 2) = colors[(
bool)(charBitmap & 0x80)];
398 *(destptr + 3) = colors[(
bool)(charBitmap & 0x40)];
399 *(destptr + 4) = colors[(
bool)(charBitmap & 0x02)];
400 *(destptr + 5) = colors[(
bool)(charBitmap & 0x01)];
401 *(destptr + 6) = colors[(
bool)(charBitmap & 0x08)];
402 *(destptr + 7) = colors[(
bool)(charBitmap & 0x04)];
404 destptr += SCREENWIDTH;
405 charBitmapPtr += CHARWIDTHINBYTES;
406 cursorBitmapPtr += CHARWIDTHINBYTES;
411 for (
int charRow = 0; charRow < LINES / 2; ++charRow) {
413 uint32_t charBitmap = *charBitmapPtr;
415 *(destptr + 0) = colors[(
bool)(charBitmap & 0x20)];
416 *(destptr + 1) = colors[(
bool)(charBitmap & 0x10)];
417 *(destptr + 2) = colors[(
bool)(charBitmap & 0x80)];
418 *(destptr + 3) = colors[(
bool)(charBitmap & 0x40)];
419 *(destptr + 4) = colors[(
bool)(charBitmap & 0x02)];
420 *(destptr + 5) = colors[(
bool)(charBitmap & 0x01)];
421 *(destptr + 6) = colors[(
bool)(charBitmap & 0x08)];
422 *(destptr + 7) = colors[(
bool)(charBitmap & 0x04)];
424 destptr += SCREENWIDTH;
425 charBitmapPtr += CHARWIDTHINBYTES;
436 void IRAM_ATTR GraphicsAdapter::drawScanline_PC_Text_80x25_16Colors(
void * arg, uint8_t * dest,
int scanLine)
438 auto ga = (GraphicsAdapter*) arg;
440 constexpr
int CHARWIDTH = 8;
441 constexpr
int CHARHEIGHT = 16;
442 constexpr
int CHARWIDTHINBYTES = (CHARWIDTH + 7) / 8;
443 constexpr
int CHARSIZEINBYTES = CHARWIDTHINBYTES * CHARHEIGHT;
444 constexpr
int COLUMNS = 80;
445 constexpr
int SCREENWIDTH = 640;
446 constexpr
int LINES = 16;
449 ++ga->m_frameCounter;
451 int charScanline = scanLine & (CHARHEIGHT - 1);
452 int textRow = scanLine / CHARHEIGHT;
454 uint8_t
const * fontData = ga->m_font.data + (charScanline * CHARWIDTHINBYTES);
456 uint8_t * rawLUT = ga->m_rawLUT;
458 uint8_t
const * curItem = ga->m_videoBuffer + (textRow * COLUMNS * 2);
460 bool showCursor = ga->m_cursorVisible && ga->m_cursorRow == textRow && ((ga->m_frameCounter & 0x1f) < 0xf);
461 int cursorCol = ga->m_cursorCol;
463 bool bit7blink = ga->m_bit7blink;
464 bool blinktime = bit7blink && !((ga->m_frameCounter & 0x3f) < 0x1f);
466 for (
int textCol = 0; textCol < COLUMNS; ++textCol) {
468 int charIdx = *curItem++;
469 int charAttr = *curItem++;
473 blink = blinktime && (charAttr & 0x80);
477 uint8_t bg = rawLUT[charAttr >> 4];
478 uint8_t fg = blink ? bg : rawLUT[charAttr & 0xf];
480 const uint8_t colors[2] = { bg, fg };
482 uint8_t
const * charBitmapPtr = fontData + charIdx * CHARSIZEINBYTES;
486 if (showCursor && textCol == cursorCol) {
488 uint8_t
const * cursorBitmapPtr = ga->m_cursorGlyph + (charScanline * CHARWIDTHINBYTES);
490 for (
int charRow = 0; charRow < LINES / 2; ++charRow) {
492 uint32_t charBitmap = *charBitmapPtr | *cursorBitmapPtr;
494 *(destptr + 0) = colors[(
bool)(charBitmap & 0x20)];
495 *(destptr + 1) = colors[(
bool)(charBitmap & 0x10)];
496 *(destptr + 2) = colors[(
bool)(charBitmap & 0x80)];
497 *(destptr + 3) = colors[(
bool)(charBitmap & 0x40)];
498 *(destptr + 4) = colors[(
bool)(charBitmap & 0x02)];
499 *(destptr + 5) = colors[(
bool)(charBitmap & 0x01)];
500 *(destptr + 6) = colors[(
bool)(charBitmap & 0x08)];
501 *(destptr + 7) = colors[(
bool)(charBitmap & 0x04)];
503 destptr += SCREENWIDTH;
504 charBitmapPtr += CHARWIDTHINBYTES;
505 cursorBitmapPtr += CHARWIDTHINBYTES;
510 for (
int charRow = 0; charRow < LINES / 2; ++charRow) {
512 uint32_t charBitmap = *charBitmapPtr;
514 *(destptr + 0) = colors[(
bool)(charBitmap & 0x20)];
515 *(destptr + 1) = colors[(
bool)(charBitmap & 0x10)];
516 *(destptr + 2) = colors[(
bool)(charBitmap & 0x80)];
517 *(destptr + 3) = colors[(
bool)(charBitmap & 0x40)];
518 *(destptr + 4) = colors[(
bool)(charBitmap & 0x02)];
519 *(destptr + 5) = colors[(
bool)(charBitmap & 0x01)];
520 *(destptr + 6) = colors[(
bool)(charBitmap & 0x08)];
521 *(destptr + 7) = colors[(
bool)(charBitmap & 0x04)];
523 destptr += SCREENWIDTH;
524 charBitmapPtr += CHARWIDTHINBYTES;
537 void IRAM_ATTR GraphicsAdapter::drawScanline_PC_Graphics_320x200_4Colors(
void * arg, uint8_t * dest,
int scanLine)
539 constexpr
int WIDTH = 320;
540 constexpr
int PIXELSPERBYTE = 4;
541 constexpr
int WIDTHINBYTES = WIDTH / PIXELSPERBYTE;
543 auto ga = (GraphicsAdapter*) arg;
545 auto src = ga->m_videoBuffer + ((scanLine & 1) << 13) + WIDTHINBYTES * (scanLine >> 1);
547 auto dest32 = (uint32_t*) dest;
549 auto LUT32 = (uint32_t*) ga->m_rawLUT;
551 for (
int col = 0; col < WIDTH; col += PIXELSPERBYTE) {
552 *dest32++ = LUT32[*src++];
559 void IRAM_ATTR GraphicsAdapter::drawScanline_PC_Graphics_640x200_2Colors(
void * arg, uint8_t * dest,
int scanLine)
561 constexpr
int WIDTH = 640;
562 constexpr
int PIXELSPERBYTE = 8;
563 constexpr
int WIDTHINBYTES = WIDTH / PIXELSPERBYTE;
565 auto ga = (GraphicsAdapter*) arg;
567 auto src = ga->m_videoBuffer + ((scanLine & 1) << 13) + WIDTHINBYTES * (scanLine >> 1);
569 auto dest64 = (uint64_t*) dest;
571 auto LUT64 = (uint64_t*) ga->m_rawLUT;
573 for (
int col = 0; col < WIDTH; col += PIXELSPERBYTE) {
574 *dest64++ = LUT64[*src++];
583 void IRAM_ATTR GraphicsAdapter::drawScanline_PC_Graphics_HGC_720x348(
void * arg, uint8_t * dest,
int scanLine)
585 constexpr
int WIDTH = 720;
586 constexpr
int PIXELSPERBYTE = 8;
587 constexpr
int WIDTHINBYTES = WIDTH / PIXELSPERBYTE;
589 auto ga = (GraphicsAdapter*) arg;
591 auto src = ga->m_videoBuffer + ((scanLine & 0b11) << 13) + WIDTHINBYTES * (scanLine >> 2);
593 auto dest64 = (uint64_t*) dest;
595 auto LUT64 = (uint64_t*) ga->m_rawLUT;
597 for (
int col = 0; col < WIDTH; col += PIXELSPERBYTE)
598 *dest64++ = LUT64[*src++];
601 src = ga->m_videoBuffer + ((scanLine & 0b11) << 13) + WIDTHINBYTES * (scanLine >> 2);
603 for (
int col = 0; col < WIDTH; col += PIXELSPERBYTE)
604 *dest64++ = LUT64[*src++];
This file contains fabgl::GraphicsAdapter definition.
Represents a 6 bit RGB color.