diff --git a/other/build.nr b/other/build.nr index ec3cc3d..22c92a2 100644 --- a/other/build.nr +++ b/other/build.nr @@ -1 +1 @@ -1969 +1971 diff --git a/src/ogfx/PixelRenderer.cpp b/src/ogfx/PixelRenderer.cpp index baba8ce..88f81ee 100644 --- a/src/ogfx/PixelRenderer.cpp +++ b/src/ogfx/PixelRenderer.cpp @@ -4,6 +4,106 @@ namespace ogfx { + void PixelRenderer::TextRenderer::initialize(void) + { + for (char c = ' '; c <= '~'; c++) + characterMap[c] = getCharacterIndex(c); + } + + bool PixelRenderer::TextRenderer::drawString(ostd::String str, uint32_t column, uint32_t row, uint32_t* screenPixels, int32_t screenWidth, int32_t screenHeight, uint32_t* fontPixels, ostd::Color color, ostd::Color background) + { + ostd::String se(str); + if (se == "") return false; + if (row >= CONSOLE_CHARS_V) return false; + if (column >= CONSOLE_CHARS_H) return false; + if (column + str.len() > CONSOLE_CHARS_H) return false; + int32_t x = column * FONT_CHAR_W; + int32_t y = row * FONT_CHAR_H; + for (auto& c : str) + { + drawCharacter((uint8_t*)screenPixels, screenWidth, screenHeight, (uint8_t*)fontPixels, x, y, c, color, background); + x += FONT_CHAR_W; + } + s_cursor_pos_x = x; + if (s_cursor_pos_x >= CONSOLE_CHARS_H) + s_cursor_pos_x = 0; + return true; + } + + int32_t PixelRenderer::TextRenderer::getCharacterIndex(char c) + { + using namespace ostd; + + int32_t charIndex = (int)c - 32; + IPoint charCoords = CONVERT_1D_2D(charIndex, FONT_H_CHARS); + charCoords.x *= FONT_CHAR_W * 4; + charCoords.y *= FONT_CHAR_H; + charIndex = CONVERT_2D_1D(charCoords.x, charCoords.y, (FONT_H_CHARS * FONT_CHAR_W * 4)); + + return charIndex; + } + + ostd::Color PixelRenderer::TextRenderer::applyTint(ostd::Color baseColor, ostd::Color tintColor) + { + auto nBase = baseColor.getNormalizedColor(); + auto nTint = tintColor.getNormalizedColor(); + + float r = nBase.r * nTint.r; + float g = nBase.r * nTint.g; + float b = nBase.r * nTint.b; + + ostd::Color::FloatCol nTinted(r, g, b, 1.0f); + + return ostd::Color(nTinted); + } + + void PixelRenderer::TextRenderer::drawCharacter(uint8_t* screenPixels, int32_t screenWidth, int32_t screenHeight, uint8_t* fontPixels, int32_t x, int32_t y, char c, ostd::Color color, ostd::Color background) + { + using namespace ostd; + int32_t charIndex = characterMap[c]; + IPoint charCoords = CONVERT_1D_2D(charIndex, (FONT_CHAR_W * FONT_H_CHARS * 4)); + + int32_t screenx = x * 4, screeny = y; + + ostd::Color tintedColor; + + bool applyBackground = false; + for (int32_t y = charCoords.y; y < charCoords.y + (FONT_CHAR_H); y += 1) + { + for (int32_t x = charCoords.x; x < charCoords.x + (FONT_CHAR_W * 4); x += 4) + { + int32_t index = CONVERT_2D_1D(x, y, (FONT_CHAR_W * FONT_H_CHARS * 4)); + int32_t screenIndex = CONVERT_2D_1D(screenx, screeny, (screenWidth * 4)); + screenx += 4; + if (fontPixels[index] == 0x00 && fontPixels[index + 1] == 0x00 && fontPixels[index + 2] == 0x00) + { + if (background.a == 0) + continue; + applyBackground = true; + } + if (applyBackground) + { + screenPixels[screenIndex + 0] = background.b; + screenPixels[screenIndex + 1] = background.g; + screenPixels[screenIndex + 2] = background.r; + screenPixels[screenIndex + 3] = 255; + applyBackground = false; + continue; + } + tintedColor = applyTint({ fontPixels[index], fontPixels[index + 1], fontPixels[index + 2], 255 }, color); + screenPixels[screenIndex + 0] = tintedColor.b; + screenPixels[screenIndex + 1] = tintedColor.g; + screenPixels[screenIndex + 2] = tintedColor.r; + screenPixels[screenIndex + 3] = fontPixels[index + 3]; + } + screeny += 1; + screenx = x * 4; + } + } + + + + PixelRenderer::~PixelRenderer(void) { if (isInvalid()) return; diff --git a/src/ogfx/PixelRenderer.hpp b/src/ogfx/PixelRenderer.hpp index 7fe14b6..856c55b 100644 --- a/src/ogfx/PixelRenderer.hpp +++ b/src/ogfx/PixelRenderer.hpp @@ -2,12 +2,37 @@ #include #include +#include namespace ogfx { class WindowBase; class PixelRenderer : public ostd::BaseObject { + public: class TextRenderer + { + private: + inline static std::unordered_map characterMap; + + public: + static void initialize(void); + static bool drawString(ostd::String str, uint32_t column, uint32_t row, uint32_t* screenPixels, int32_t screenWidth, int32_t screenHeight, uint32_t* fontPixels, ostd::Color color = { 255, 255, 255, 255 }, ostd::Color background = { 255, 255, 255, 0 }); + + private: + static int32_t getCharacterIndex(char c); + static ostd::Color applyTint(ostd::Color baseColor, ostd::Color tintColor); + static void drawCharacter(uint8_t* screenPixels, int32_t screenWidth, int32_t screenHeight, uint8_t* fontPixels, int32_t x, int32_t y, char c, ostd::Color color = { 255, 255, 255, 255 }, ostd::Color background = { 255, 255, 255, 0 }); + + public: + inline static constexpr int32_t FONT_CHAR_W = 11; + inline static constexpr int32_t FONT_CHAR_H = 26; + inline static constexpr int32_t FONT_V_CHARS = 6; + inline static constexpr int32_t FONT_H_CHARS = 16; + inline static constexpr int32_t CONSOLE_CHARS_H = 90; + inline static constexpr int32_t CONSOLE_CHARS_V = 21; + + inline static int8_t s_cursor_pos_x = 0; + }; public: inline PixelRenderer(void) { invalidate(); } ~PixelRenderer(void);