add: Basic Font Rendering
This commit is contained in:
@@ -15,7 +15,10 @@ set(src
|
||||
src/display/Display.cpp
|
||||
src/render/RenderTarget.hpp
|
||||
src/render/RenderTarget.cpp
|
||||
|
||||
src/font/Font.hpp
|
||||
src/font/Font.cpp
|
||||
src/font/Glyph.hpp
|
||||
src/font/Glyph.cpp
|
||||
)
|
||||
|
||||
if (BUILD_EPD)
|
||||
@@ -33,12 +36,22 @@ if (BUILD_VIRTUAL_DISPLAY)
|
||||
endif (BUILD_VIRTUAL_DISPLAY)
|
||||
|
||||
add_executable(${target} ${src})
|
||||
target_link_libraries(${target} PRIVATE fmt::fmt)
|
||||
target_link_libraries(${target} PRIVATE
|
||||
fmt::fmt
|
||||
)
|
||||
|
||||
if (BUILD_EPD)
|
||||
target_link_libraries(${target} PRIVATE waveshare)
|
||||
target_link_libraries(${target} PRIVATE
|
||||
waveshare
|
||||
)
|
||||
endif (BUILD_EPD)
|
||||
|
||||
if (BUILD_VIRTUAL_DISPLAY)
|
||||
target_link_libraries(${target} PRIVATE sfml-system sfml-window sfml-graphics)
|
||||
target_link_libraries(${target} PRIVATE
|
||||
sfml-system
|
||||
sfml-window
|
||||
sfml-graphics
|
||||
fmt::fmt
|
||||
nlohmann_json::nlohmann_json
|
||||
)
|
||||
endif(BUILD_VIRTUAL_DISPLAY)
|
||||
@@ -17,6 +17,15 @@ namespace frame
|
||||
{
|
||||
}
|
||||
|
||||
void Image::Create(uint32_t pWidth, uint32_t pHeight)
|
||||
{
|
||||
mWidth = pWidth;
|
||||
mHeight = pHeight;
|
||||
|
||||
mBuffer.clear();
|
||||
mBuffer.resize(mWidth * mHeight);
|
||||
}
|
||||
|
||||
uint8_t& Image::at(uint32_t x, uint32_t y)
|
||||
{
|
||||
return mBuffer.at(toInternal(x, y));
|
||||
@@ -27,6 +36,13 @@ namespace frame
|
||||
return mBuffer.at(toInternal(x, y));
|
||||
}
|
||||
|
||||
void Image::operator=(Image const& image)
|
||||
{
|
||||
mHeight = image.mHeight;
|
||||
mWidth = image.mWidth;
|
||||
mBuffer = image.mBuffer;
|
||||
}
|
||||
|
||||
size_t Image::toInternal(uint32_t x, uint32_t y) const
|
||||
{
|
||||
return x + mWidth * y;
|
||||
|
||||
@@ -14,8 +14,13 @@ namespace frame
|
||||
std::vector<uint8_t> mBuffer;
|
||||
|
||||
public:
|
||||
Image() = default;
|
||||
Image(uint32_t pWidth, uint32_t pHeight);
|
||||
Image(Size size);
|
||||
Image(Image const&) = default;
|
||||
Image(Image&&) = default;
|
||||
|
||||
void Create(uint32_t pWidth, uint32_t pHeight);
|
||||
|
||||
uint8_t& at(uint32_t x, uint32_t y);
|
||||
uint8_t const& at(uint32_t x, uint32_t y) const;
|
||||
@@ -29,6 +34,8 @@ namespace frame
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void operator=(Image const& image);
|
||||
|
||||
private:
|
||||
size_t toInternal(uint32_t x, uint32_t y) const;
|
||||
};
|
||||
|
||||
54
frame/src/font/Font.cpp
Normal file
54
frame/src/font/Font.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "Font.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace frame::font
|
||||
{
|
||||
|
||||
std::shared_ptr<Font> Font::LoadFromFile(std::string_view file)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::fstream file_data(std::string{file}, std::ios::in);
|
||||
|
||||
auto out = std::make_shared<Font>();
|
||||
out->LoadFromStream(file_data);
|
||||
return out;
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Font::LoadFromStream(std::istream& os)
|
||||
{
|
||||
json file_data = json::parse(os);
|
||||
|
||||
name = file_data["name"];
|
||||
|
||||
for(auto& [key, el] : file_data["sizes"].items())
|
||||
{
|
||||
auto size = std::atoi(key.c_str());
|
||||
|
||||
Glyphs curren_glyphs;
|
||||
lineSpacing[size] = el["LineSpacing"];
|
||||
|
||||
for(auto& [glyph_c, glyph_d] : el["Glyphs"].items())
|
||||
{
|
||||
curren_glyphs[glyph_c[0]] = std::move(Glyph{glyph_d});
|
||||
}
|
||||
|
||||
sizes[size] = std::move(curren_glyphs);
|
||||
}
|
||||
}
|
||||
|
||||
Glyph const& Font::getGlyph(uint32_t size, char c) const
|
||||
{
|
||||
return sizes.at(size).at(c);
|
||||
}
|
||||
|
||||
} // namespace frame::font
|
||||
29
frame/src/font/Font.hpp
Normal file
29
frame/src/font/Font.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "Glyph.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace frame::font
|
||||
{
|
||||
using Glyphs = std::map<char, Glyph>;
|
||||
using LineSpacing = std::map<uint8_t, uint32_t>;
|
||||
|
||||
class Font
|
||||
{
|
||||
std::string name;
|
||||
std::map<uint8_t, Glyphs> sizes;
|
||||
LineSpacing lineSpacing;
|
||||
|
||||
public:
|
||||
Font() = default;
|
||||
static std::shared_ptr<Font> LoadFromFile(std::string_view file);
|
||||
|
||||
Glyph const& getGlyph(uint32_t size, char c) const;
|
||||
|
||||
protected:
|
||||
void LoadFromStream(std::istream& os);
|
||||
};
|
||||
} // namespace frame::font
|
||||
39
frame/src/font/Glyph.cpp
Normal file
39
frame/src/font/Glyph.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "Glyph.hpp"
|
||||
|
||||
namespace frame::font
|
||||
{
|
||||
Glyph::Glyph(json const& data)
|
||||
{
|
||||
height = data["height"];
|
||||
width = data["width"];
|
||||
x_offset = data["x_offset"];
|
||||
y_offset = data["y_offset"];
|
||||
advance = data["advance"];
|
||||
|
||||
image.Create(width, height);
|
||||
|
||||
auto& image_data = data["data"];
|
||||
|
||||
int index = 0;
|
||||
for(auto y = 0; y < height; ++y)
|
||||
{
|
||||
for(auto x = 0; x < width; ++x)
|
||||
{
|
||||
uint8_t i = image_data[index];
|
||||
image.at(x, y) = i * 0xFF;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Glyph::operator=(Glyph const& glyph)
|
||||
{
|
||||
image = glyph.image;
|
||||
height = glyph.height;
|
||||
width = glyph.width;
|
||||
x_offset = glyph.x_offset;
|
||||
y_offset = glyph.y_offset;
|
||||
advance = glyph.advance;
|
||||
}
|
||||
|
||||
} // namespace frame::font
|
||||
28
frame/src/font/Glyph.hpp
Normal file
28
frame/src/font/Glyph.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Image.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace frame::font
|
||||
{
|
||||
struct Glyph
|
||||
{
|
||||
Image image;
|
||||
uint8_t height;
|
||||
uint8_t width;
|
||||
int8_t x_offset;
|
||||
int8_t y_offset;
|
||||
int8_t advance;
|
||||
|
||||
public:
|
||||
Glyph() = default;
|
||||
Glyph(json const& data);
|
||||
Glyph(Glyph const&) = default;
|
||||
Glyph(Glyph&&) = default;
|
||||
|
||||
void operator=(Glyph const& glyph);
|
||||
};
|
||||
} // namespace frame::font
|
||||
@@ -7,12 +7,15 @@
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#include "display/Display.hpp"
|
||||
#include "font/Font.hpp"
|
||||
#include "render/RenderTarget.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr double pi = 3.14159;
|
||||
|
||||
auto font = frame::font::Font::LoadFromFile("Fira Code.json");
|
||||
|
||||
auto display = frame::display::Create();
|
||||
|
||||
if(!display)
|
||||
@@ -62,6 +65,8 @@ int main()
|
||||
{110, (int)display->getSize().height - 10},
|
||||
5);
|
||||
|
||||
target.DrawText("abcdefghijklmnopqrstuvwxyz", {100, 50}, *font, 14);
|
||||
|
||||
display->Display(target.getImage());
|
||||
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
@@ -142,6 +142,46 @@ namespace frame::render
|
||||
{BottomRight.x, BottomRight.y - lw});
|
||||
}
|
||||
|
||||
void RenderTarget::DrawImage(Vector topLeft, Image const& image)
|
||||
{
|
||||
auto pos = topLeft;
|
||||
|
||||
for(auto y = 0; y < image.getHeight(); ++y)
|
||||
{
|
||||
for(auto x = 0; x < image.getWidth(); ++x)
|
||||
{
|
||||
DrawPixel({pos.x + x, pos.y + y}, (Color)image.at(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector RenderTarget::DrawGlyph(Vector centerLine,
|
||||
font::Glyph const& g,
|
||||
Color color)
|
||||
{
|
||||
auto const& height = g.height;
|
||||
|
||||
Vector topleft = centerLine;
|
||||
topleft.x += g.x_offset;
|
||||
topleft.y += g.y_offset;
|
||||
|
||||
DrawImage(topleft, g.image);
|
||||
centerLine.x += g.advance;
|
||||
return centerLine;
|
||||
}
|
||||
|
||||
void RenderTarget::DrawText(std::string_view pText,
|
||||
Vector pCenterLineStart,
|
||||
font::Font const& pFont,
|
||||
uint8_t size)
|
||||
{
|
||||
auto pos = pCenterLineStart;
|
||||
for(auto c : pText)
|
||||
{
|
||||
pos = DrawGlyph(pos, pFont.getGlyph(size, c));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTarget::DrawPointsMirrorCircle(Vector const& center,
|
||||
Vector const& pos,
|
||||
Color color)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../Color.hpp"
|
||||
#include "../Image.hpp"
|
||||
#include "../Vector.hpp"
|
||||
#include "../font/Font.hpp"
|
||||
|
||||
namespace frame::render
|
||||
{
|
||||
@@ -24,17 +25,35 @@ namespace frame::render
|
||||
int32_t radius,
|
||||
Color color = BLACK);
|
||||
|
||||
void DrawRectFilled(Vector const& TopLeft, Vector const& BottomRight, Color color = BLACK);
|
||||
void DrawRectFilled(Vector const& TopLeft,
|
||||
Vector const& BottomRight,
|
||||
Color color = BLACK);
|
||||
|
||||
void DrawRect(Vector const& TopLeft, Vector const& BottomRight, uint8_t LineWidth, Color color = BLACK);
|
||||
void DrawRect(Vector const& TopLeft,
|
||||
Vector const& BottomRight,
|
||||
uint8_t LineWidth,
|
||||
Color color = BLACK);
|
||||
|
||||
void DrawImage(Vector topLeft, Image const& image);
|
||||
|
||||
Vector DrawGlyph(Vector centerLine,
|
||||
font::Glyph const& g,
|
||||
Color color = BLACK);
|
||||
|
||||
void DrawText(std::string_view pText,
|
||||
Vector pCenterLineStart,
|
||||
font::Font const& pFont,
|
||||
uint8_t size);
|
||||
|
||||
Image const& getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
private:
|
||||
void DrawPointsMirrorCircle(Vector const& center, Vector const& pos, Color color);
|
||||
|
||||
private:
|
||||
void DrawPointsMirrorCircle(Vector const& center,
|
||||
Vector const& pos,
|
||||
Color color);
|
||||
};
|
||||
|
||||
} // namespace frame::render
|
||||
|
||||
Reference in New Issue
Block a user