2024-11-12 05:58:16 +03:00

180 lines
4.0 KiB
C++

#include "Font.hpp"
#include <utility>
#include "Texture.hpp"
#include "Batch2D.hpp"
#include "Batch3D.hpp"
#include "window/Camera.hpp"
inline constexpr uint GLYPH_SIZE = 16;
inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has
inline constexpr glm::vec4 SHADOW_TINT(0.0f, 0.0f, 0.0f, 1.0f);
Font::Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset)
: lineHeight(lineHeight), yoffset(yoffset), pages(std::move(pages)) {
}
Font::~Font() = default;
int Font::getYOffset() const {
return yoffset;
}
int Font::getLineHeight() const {
return lineHeight;
}
bool Font::isPrintableChar(uint codepoint) const {
switch (codepoint){
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
return false;
default:
return true;
}
}
int Font::calcWidth(const std::wstring& text, size_t length) const {
return calcWidth(text, 0, length);
}
int Font::calcWidth(const std::wstring& text, size_t offset, size_t length) const {
return std::min(text.length()-offset, length) * glyphInterval;
}
static inline void draw_glyph(
Batch2D& batch,
const glm::vec3& pos,
const glm::vec2& offset,
uint c,
const glm::vec3& right,
const glm::vec3& up,
float glyphInterval,
float lineHeight
) {
batch.sprite(
pos.x + offset.x * right.x,
pos.y + offset.y * right.y,
right.x / glyphInterval,
up.y,
16,
c,
batch.getColor()
);
}
static inline void draw_glyph(
Batch3D& batch,
const glm::vec3& pos,
const glm::vec2& offset,
uint c,
const glm::vec3& right,
const glm::vec3& up,
float glyphInterval,
float lineHeight
) {
batch.sprite(
pos + right * offset.x + up * offset.y,
up, right / glyphInterval,
0.5f,
0.5f,
16,
c,
glm::vec4(1.0f)
);
}
template <class Batch>
static inline void draw_text(
const Font& font,
Batch& batch,
std::wstring_view text,
const glm::vec3& pos,
const glm::vec3& right,
const glm::vec3& up,
float glyphInterval,
float lineHeight
) {
uint page = 0;
uint next = MAX_CODEPAGES;
int x = 0;
int y = 0;
do {
for (uint c : text){
if (!font.isPrintableChar(c)) {
x++;
continue;
}
uint charpage = c >> 8;
if (charpage == page){
batch.texture(font.getPage(charpage));
draw_glyph(
batch,
pos,
glm::vec2(x, y),
c,
right,
up,
glyphInterval,
lineHeight
);
}
else if (charpage > page && charpage < next){
next = charpage;
}
x++;
}
page = next;
next = MAX_CODEPAGES;
x = 0;
} while (page < MAX_CODEPAGES);
}
const Texture* Font::getPage(int charpage) const {
Texture* texture = nullptr;
if (charpage < pages.size()) {
texture = pages[charpage].get();
}
if (texture == nullptr){
texture = pages[0].get();
}
return texture;
}
void Font::draw(
Batch2D& batch, std::wstring_view text, int x, int y, float scale
) const {
draw_text(
*this,
batch,
text,
glm::vec3(x, y, 0),
glm::vec3(glyphInterval*scale, 0, 0),
glm::vec3(0, lineHeight*scale, 0),
glyphInterval/static_cast<float>(lineHeight),
lineHeight
);
}
void Font::draw(
Batch3D& batch,
std::wstring_view text,
const glm::vec3& pos,
const glm::vec3& right,
const glm::vec3& up
) const {
draw_text(
*this,
batch,
text,
pos,
right * static_cast<float>(glyphInterval),
up * static_cast<float>(lineHeight),
glyphInterval/static_cast<float>(lineHeight),
lineHeight
);
}