#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"; }