Add monochrome rendering modes

These modes can be used to see the inner workings of colourful artworks that
frequently use "foreground colour, new background, foreground colour",
particularly to show exactly which colours are represented by set or clear
sixels.

One mode renders all characters in white on a black background and the other
mode renders black characters on a white background. The latter could be used
to save ink if the resulting image is printed.

Flash is suppressed in these mono modes, this may or may not change.
This commit is contained in:
Gavin MacGregor
2024-12-01 17:44:58 +00:00
parent 26b5974421
commit 48a2b48964
5 changed files with 110 additions and 74 deletions

View File

@@ -60,7 +60,7 @@ TeletextPageRender::TeletextPageRender()
m_pageImage[i] = new QImage(864, 250, QImage::Format_ARGB32_Premultiplied);
m_reveal = false;
m_mix = false;
m_renderMode = RenderNormal;
m_showControlCodes = false;
m_flashBuffersHz = 0;
@@ -226,6 +226,13 @@ inline void TeletextPageRender::drawBoldOrItalicCharacter(QPainter &painter, int
void TeletextPageRender::renderPage(bool force)
{
if (m_renderMode == RenderWhiteOnBlack) {
m_foregroundQColor = Qt::white;
m_backgroundQColor = Qt::black;
} else if (m_renderMode == RenderBlackOnWhite) {
m_foregroundQColor = Qt::black;
m_backgroundQColor = Qt::white;
}
for (int r=0; r<25; r++)
renderRow(r, 0, force);
}
@@ -253,9 +260,11 @@ void TeletextPageRender::renderRow(int r, int ph, bool force)
}
}
if (ph == 0) {
// Second part of "if" suppresses all flashing on monochrome render modes
if (ph == 0 && m_renderMode < RenderWhiteOnBlack) {
if (m_decoder->cellFlashMode(r, c) != 0)
flashingRow = qMax(flashingRow, (m_decoder->cellFlashRatePhase(r, c) == 0) ? 1 : 2);
// } else if (!force)
} else
force = m_decoder->cellFlashMode(r, c) != 0;
@@ -278,36 +287,38 @@ void TeletextPageRender::renderRow(int r, int ph, bool force)
characterDiacritical = m_decoder->cellCharacterDiacritical(r, c);
}
if (m_decoder->cellFlashMode(r, c) == 0)
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c);
else {
// Flashing cell, decide if phase in this cycle is on or off
bool phaseOn;
if (m_decoder->cellFlashRatePhase(r, c) == 0)
phaseOn = (ph < 3) ^ (m_decoder->cellFlashMode(r, c) == 2);
else
phaseOn = ((ph == m_decoder->cellFlash2HzPhaseNumber(r, c)-1) || (ph == m_decoder->cellFlash2HzPhaseNumber(r, c)+2)) ^ (m_decoder->cellFlashMode(r, c) == 2);
// If flashing to adjacent CLUT select the appropriate foreground colour
if (m_decoder->cellFlashMode(r, c) == 3 && !phaseOn)
m_foregroundQColor = m_decoder->cellFlashForegroundQColor(r, c);
else
if (m_renderMode < RenderWhiteOnBlack) {
if (m_decoder->cellFlashMode(r, c) == 0)
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c);
else {
// Flashing cell, decide if phase in this cycle is on or off
bool phaseOn;
// If flashing mode is Normal or Invert, draw a space instead of a character on phase
if ((m_decoder->cellFlashMode(r, c) == 1 || m_decoder->cellFlashMode(r, c) == 2) && !phaseOn) {
// Character 0x00 draws space without underline
characterCode = 0x00;
characterSet = 0;
characterDiacritical = 0;
if (m_decoder->cellFlashRatePhase(r, c) == 0)
phaseOn = (ph < 3) ^ (m_decoder->cellFlashMode(r, c) == 2);
else
phaseOn = ((ph == m_decoder->cellFlash2HzPhaseNumber(r, c)-1) || (ph == m_decoder->cellFlash2HzPhaseNumber(r, c)+2)) ^ (m_decoder->cellFlashMode(r, c) == 2);
// If flashing to adjacent CLUT select the appropriate foreground colour
if (m_decoder->cellFlashMode(r, c) == 3 && !phaseOn)
m_foregroundQColor = m_decoder->cellFlashForegroundQColor(r, c);
else
m_foregroundQColor = m_decoder->cellForegroundQColor(r, c);
// If flashing mode is Normal or Invert, draw a space instead of a character on phase
if ((m_decoder->cellFlashMode(r, c) == 1 || m_decoder->cellFlashMode(r, c) == 2) && !phaseOn) {
// Character 0x00 draws space without underline
characterCode = 0x00;
characterSet = 0;
characterDiacritical = 0;
}
}
}
if (!m_mix || m_decoder->cellBoxed(r, c))
m_backgroundQColor = m_decoder->cellBackgroundQColor(r, c);
else
m_backgroundQColor = Qt::transparent;
if (m_renderMode != RenderMix || m_decoder->cellBoxed(r, c))
m_backgroundQColor = m_decoder->cellBackgroundQColor(r, c);
else
m_backgroundQColor = Qt::transparent;
}
drawCharacter(painter, r, c, characterCode, characterSet, characterDiacritical, m_decoder->cellCharacterFragment(r, c));
@@ -439,17 +450,16 @@ void TeletextPageRender::setReveal(bool reveal)
m_decoder->setRefresh(r, c, true);
}
void TeletextPageRender::setMix(bool mix)
void TeletextPageRender::setRenderMode(RenderMode renderMode)
{
if (mix == m_mix)
if (renderMode == m_renderMode)
return;
m_mix = mix;
m_renderMode = renderMode;
for (int r=0; r<25; r++)
for (int c=0; c<72; c++)
if (!m_decoder->cellBoxed(r, c))
m_decoder->setRefresh(r, c, true);
m_decoder->setRefresh(r, c, true);
}

View File

@@ -49,11 +49,13 @@ class TeletextPageRender : public QObject
Q_OBJECT
public:
enum RenderMode { RenderNormal, RenderMix, RenderWhiteOnBlack, RenderBlackOnWhite };
TeletextPageRender();
~TeletextPageRender();
QImage* image(int i) const { return m_pageImage[i]; };
bool mix() const { return m_mix; };
RenderMode renderMode() const { return m_renderMode; };
void setDecoder(TeletextPageDecode *decoder);
void renderPage(bool force=false);
bool showControlCodes() const { return m_showControlCodes; };
@@ -61,7 +63,7 @@ public:
public slots:
void colourChanged(int index);
void setReveal(bool reveal);
void setMix(bool mix);
void setRenderMode(RenderMode renderMode);
void setShowControlCodes(bool showControlCodes);
signals:
@@ -71,7 +73,8 @@ protected:
TeletextFontBitmap m_fontBitmap;
QImage* m_pageImage[6];
unsigned char m_controlCodeCache[25][40];
bool m_reveal, m_mix, m_showControlCodes;
RenderMode m_renderMode;
bool m_reveal, m_showControlCodes;
int m_flashBuffersHz;
int m_flashingRow[25];