18
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-14 13:25:56 +01:00
Files
maszyna/scripting/scriptscreendrawing.h

127 lines
3.6 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
// the drawing the Lua screens get from the game (eu07.image, eu07.font, eu07.sprite): bitmap fonts and sprites in the
// format of the python LED screens (scripts/led_util.py: a .png with the glyphs side by side and a .txt with their
// widths), and RGBA images to draw them on. drawn natively, the script only says what goes where
#include <array>
#include <cstdint>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
namespace script_screens
{
using rgb = std::array<std::uint8_t, 3>;
// the code points of UTF-8 text; a byte that doesn't start a valid sequence stands for itself
std::u32string decode_utf8(std::string_view Text);
// a character or a sprite: its lit pixels, column by column
class glyph
{
public:
glyph() = default;
glyph(int Width, int Height, std::vector<bool> Lit) : m_width{Width}, m_height{Height}, m_lit{std::move(Lit)} {}
int width() const
{
return m_width;
}
int height() const
{
return m_height;
}
bool lit(int const X, int const Y) const
{
return m_lit[static_cast<std::size_t>(X) * m_height + Y];
}
private:
int m_width{0};
int m_height{0};
std::vector<bool> m_lit;
};
class bitmap_font
{
public:
// a font as led_util.load_font() reads it: Rgba (Width x Height) has the glyphs side by side, a column apart;
// Description has a comment line, then a line per glyph: the character and its width. a pixel is lit unless it is
// opaque white. nothing for a description without glyphs
static std::optional<bitmap_font> parse(std::span<std::uint8_t const> Rgba, int Width, int Height, std::string_view Description);
// a sprite as led_util.load_spr() reads it: the whole image as one glyph
static glyph sprite(std::span<std::uint8_t const> Rgba, int Width, int Height);
int height() const
{
return m_height;
}
// the glyph of the character. a character the font lacks gets the font's first glyph (led_util picks a random one;
// here every refresh draws the same)
glyph const &find(char32_t Character) const;
// the width of the text, a column of Spacing after every character (led_util's get_str_len)
int text_width(std::string_view Text, int Spacing) const;
private:
int m_height{0};
std::unordered_map<char32_t, glyph> m_glyphs;
glyph m_fallback;
};
// an RGBA image, from the top row down
class canvas
{
public:
canvas(int Width, int Height, rgb Color);
canvas(int Width, int Height, std::vector<std::uint8_t> Pixels);
int width() const
{
return m_width;
}
int height() const
{
return m_height;
}
std::vector<std::uint8_t> const &pixels() const
{
return m_pixels;
}
void fill(rgb Color);
// a pixel outside the image is skipped
void set(int X, int Y, rgb Color);
// black outside the image
rgb get(int X, int Y) const;
// clipped to the image
void fill_rect(int X, int Y, int Width, int Height, rgb Color);
// the lit pixels of the glyph, its top left corner at (X, Y)
void draw_glyph(glyph const &Glyph, int X, int Y, rgb Color);
// text from X rightwards, Spacing columns between the characters (led_util's draw_str). returns the X after it
int draw_text(bitmap_font const &Font, int X, int Y, std::string_view Text, rgb Color, int Spacing);
// another image, its top left corner at (X, Y), clipped
void draw_image(canvas const &Image, int X, int Y);
private:
int m_width;
int m_height;
std::vector<std::uint8_t> m_pixels;
};
} // namespace script_screens