221 lines
4.9 KiB
C++
221 lines
4.9 KiB
C++
#include "NoSignalFeed.hpp"
|
|
#include "PixelFormat.hpp"
|
|
|
|
namespace
|
|
{
|
|
constexpr uint32_t TileBorderPixels = 0;
|
|
|
|
uint32_t glyphRows(char c, uint32_t row)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'A':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'G':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0E};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'I':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1F};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'L':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'N':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'O':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E};
|
|
return rows[row];
|
|
}
|
|
|
|
case 'S':
|
|
{
|
|
constexpr uint32_t rows[] =
|
|
{0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E};
|
|
return rows[row];
|
|
}
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void drawText(
|
|
VideoFrame& frame,
|
|
const char* text,
|
|
uint32_t originX,
|
|
uint32_t originY,
|
|
uint32_t scale,
|
|
RgbColor color)
|
|
{
|
|
for (uint32_t charIndex = 0; text[charIndex] != '\0'; ++charIndex)
|
|
{
|
|
const char c = text[charIndex];
|
|
|
|
if (c == ' ')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const uint32_t charX =
|
|
originX + charIndex * 6 * scale;
|
|
|
|
for (uint32_t gy = 0; gy < 7; ++gy)
|
|
{
|
|
const uint32_t bits = glyphRows(c, gy);
|
|
|
|
for (uint32_t gx = 0; gx < 5; ++gx)
|
|
{
|
|
if ((bits & (1u << (4 - gx))) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (uint32_t sy = 0; sy < scale; ++sy)
|
|
{
|
|
for (uint32_t sx = 0; sx < scale; ++sx)
|
|
{
|
|
const uint32_t x =
|
|
charX + gx * scale + sx;
|
|
const uint32_t y =
|
|
originY + gy * scale + sy;
|
|
|
|
if (x < frame.width && y < frame.height)
|
|
{
|
|
frame.pixels[y * frame.width + x] =
|
|
packRgba8(color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void fillNoSignalFrame(VideoFrame& frame)
|
|
{
|
|
frame.pixels.resize(frame.width * frame.height);
|
|
|
|
for (uint32_t y = 0; y < frame.height; ++y)
|
|
{
|
|
for (uint32_t x = 0; x < frame.width; ++x)
|
|
{
|
|
const bool isBorder =
|
|
x < TileBorderPixels ||
|
|
y < TileBorderPixels ||
|
|
x >= frame.width - TileBorderPixels ||
|
|
y >= frame.height - TileBorderPixels;
|
|
|
|
const bool hatch =
|
|
((x + y) / 18) % 2 == 0;
|
|
|
|
const RgbColor color =
|
|
isBorder
|
|
? RgbColor{95, 100, 110}
|
|
: (hatch
|
|
? RgbColor{18, 20, 24}
|
|
: RgbColor{12, 14, 18});
|
|
|
|
frame.pixels[y * frame.width + x] =
|
|
packRgba8(color);
|
|
}
|
|
}
|
|
|
|
const uint32_t scale =
|
|
frame.width >= 512 ? 5 : 3;
|
|
constexpr uint32_t textChars = 9;
|
|
const uint32_t textWidth =
|
|
(textChars * 6 - 1) * scale;
|
|
const uint32_t textHeight = 7 * scale;
|
|
const uint32_t textX =
|
|
frame.width > textWidth
|
|
? (frame.width - textWidth) / 2
|
|
: 0;
|
|
const uint32_t textY =
|
|
frame.height > textHeight
|
|
? (frame.height - textHeight) / 2
|
|
: 0;
|
|
|
|
drawText(
|
|
frame,
|
|
"NO SIGNAL",
|
|
textX,
|
|
textY,
|
|
scale,
|
|
{210, 215, 225}
|
|
);
|
|
}
|
|
}
|
|
|
|
NoSignalFeed::NoSignalFeed(
|
|
uint32_t feedIndex,
|
|
uint32_t frameWidth,
|
|
uint32_t frameHeight)
|
|
{
|
|
configure(
|
|
feedIndex,
|
|
frameWidth,
|
|
frameHeight
|
|
);
|
|
}
|
|
|
|
void NoSignalFeed::configure(
|
|
uint32_t feedIndex,
|
|
uint32_t frameWidth,
|
|
uint32_t frameHeight)
|
|
{
|
|
(void)feedIndex;
|
|
generated = false;
|
|
version = 0;
|
|
frame.width = frameWidth;
|
|
frame.height = frameHeight;
|
|
frame.pixels.resize(frame.width * frame.height);
|
|
}
|
|
|
|
const VideoFrame& NoSignalFeed::getFrame(uint32_t frameCounter)
|
|
{
|
|
(void)frameCounter;
|
|
|
|
if (!generated)
|
|
{
|
|
fillNoSignalFrame(frame);
|
|
generated = true;
|
|
++version;
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
FeedRuntimeStatus NoSignalFeed::status() const
|
|
{
|
|
return FeedRuntimeStatus::NoSignal;
|
|
}
|
|
|
|
std::string NoSignalFeed::displayName() const
|
|
{
|
|
return "NO SIGNAL";
|
|
}
|