diff --git a/include/glez/draw.hpp b/include/glez/draw.hpp index aadd5fa..c6be95e 100644 --- a/include/glez/draw.hpp +++ b/include/glez/draw.hpp @@ -8,6 +8,7 @@ #include #include "color.hpp" #include "font.hpp" +#include "texture.hpp" namespace glez::draw { @@ -15,9 +16,10 @@ namespace glez::draw void line(int x, int y, int dx, int dy, rgba color, int thickness); void rect(int x, int y, int w, int h, rgba color); void rect_outline(int x, int y, int w, int h, rgba color, int thickness); +void rect_textured(int x, int y, int w, int h, rgba color, texture& texture, int tx, int ty, int tw, int th); void circle(int x, int y, int radius, rgba color, int thickness, int steps); -void string(int x, int y, const std::string& string, const font& font, rgba color, int *width, int *height); -void outlined_string(int x, int y, const std::string& string, const font& font, rgba color, rgba outline, int *width, int *height); +void string(int x, int y, const std::string& string, font& font, rgba color, int *width, int *height); +void outlined_string(int x, int y, const std::string& string, font& font, rgba color, rgba outline, int *width, int *height); } \ No newline at end of file diff --git a/include/glez/font.hpp b/include/glez/font.hpp index 5131871..0e1d78d 100644 --- a/include/glez/font.hpp +++ b/include/glez/font.hpp @@ -20,22 +20,23 @@ public: } ~font(); - inline float getSize() const + inline unsigned getHandle() const { - return size; + return handle; } - inline const std::string& getPath() const + inline bool isLoaded() const { - return path; + return loaded; } -protected: + void load(); void unload(); const std::string path; const float size; +protected: bool loaded{ false }; unsigned handle{ std::numeric_limits::max() }; diff --git a/include/glez/texture.hpp b/include/glez/texture.hpp index 595b309..9f1ca63 100644 --- a/include/glez/texture.hpp +++ b/include/glez/texture.hpp @@ -30,16 +30,22 @@ public: return height; } - inline const std::string& getPath() const + inline unsigned getHandle() const { - return path; + return handle; } -protected: + + inline bool isLoaded() const + { + return loaded; + } + void load(); void unload(); const std::string path; +protected: int width{ 0 }; int height{ 0 }; bool loaded{ false }; diff --git a/src/detail/font.cpp b/src/detail/font.cpp index 9153887..7c7178b 100644 --- a/src/detail/font.cpp +++ b/src/detail/font.cpp @@ -83,14 +83,13 @@ unsigned create() for (auto i = 0u; i < cache->size(); ++i) if (not (*cache)[i].init) return i; - auto result = cache->size() - 1; + auto result = cache->size(); cache->push_back(font{}); return result; } font &get(unsigned handle) { - assert(cache->at(handle).init); return (*cache)[handle]; } diff --git a/src/detail/texture.cpp b/src/detail/texture.cpp index 7a07eed..58193cb 100644 --- a/src/detail/texture.cpp +++ b/src/detail/texture.cpp @@ -68,7 +68,6 @@ void texture::unload() texture& get(unsigned handle) { - assert(cache->at(handle).init); return (*cache)[handle]; } @@ -77,7 +76,7 @@ unsigned create() for (auto i = 0u; i < cache->size(); ++i) if (not (*cache)[i].init) return i; - auto result = cache->size() - 1; + auto result = cache->size(); cache->push_back(texture{}); return result; } diff --git a/src/draw.cpp b/src/draw.cpp index 8a67ee2..4e03e83 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -4,9 +4,12 @@ */ #include +#include #include #include #include +#include +#include namespace indices { @@ -15,6 +18,88 @@ static GLuint rectangle[6] = { 0, 1, 2, 2, 3, 0 }; } +void internal_draw_string(int x, int y, const std::string& string, texture_font_t *fnt, glez::rgba color, int *width, int *height) +{ + float pen_x = x; + float pen_y = y + fnt->height / 1.5f; + float size_y = 0; + + if (fnt->atlas->id == 0) + { + glGenTextures(1, &fnt->atlas->id); + } + + glez::detail::render::bind(fnt->atlas->id); + + if (fnt->atlas->dirty) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, fnt->atlas->width, + fnt->atlas->height, 0, GL_RED, GL_UNSIGNED_BYTE, + fnt->atlas->data); + fnt->atlas->dirty = 0; + } + + const char *sstring = string.c_str(); + + for (size_t i = 0; i < string.size(); ++i) + { + texture_glyph_t *glyph = texture_font_find_glyph(fnt, &sstring[i]); + if (glyph == NULL) + { + texture_font_load_glyph(fnt, &sstring[i]); + continue; + } + glez::detail::render::vertex vertices[4]; + for (auto& vertex: vertices) + { + vertex.color = color; + vertex.mode = static_cast(glez::detail::program::mode::FREETYPE); + } + + if (i > 0) + { + x += texture_glyph_get_kerning(glyph, &sstring[i - 1]); + } + + float x0 = (int)(pen_x + glyph->offset_x); + float y0 = (int)(pen_y - glyph->offset_y); + float x1 = (int)(x0 + glyph->width); + float y1 = (int)(y0 + glyph->height); + float s0 = glyph->s0; + float t0 = glyph->t0; + float s1 = glyph->s1; + float t1 = glyph->t1; + + vertices[0].position = {x0, y0}; + vertices[0].uv = {s0, t0}; + + vertices[1].position = {x0, y1}; + vertices[1].uv = {s0, t1}; + + vertices[2].position = {x1, y1}; + vertices[2].uv = {s1, t1}; + + vertices[3].position = {x1, y0}; + vertices[3].uv = {s1, t0}; + + pen_x += glyph->advance_x; + //pen_x = (int) pen_x + 1; + if (glyph->height > size_y) + size_y = glyph->height; + + vertex_buffer_push_back(glez::detail::program::buffer, vertices, 4, indices::rectangle, 6); + } + + if (width) + *width = int(pen_x - x); + if (height) + *height = int(size_y); +} + namespace glez::draw { @@ -53,17 +138,65 @@ void circle(int x, int y, int radius, rgba color, int thickness, } -void string(int x, int y, const std::string &string, const font& font, +void string(int x, int y, const std::string &string, font& font, rgba color, int *width, int *height) { + if (!font.isLoaded()) + font.load(); + + auto fnt = glez::detail::font::get(font.getHandle()).font; + fnt->rendermode = RENDER_NORMAL; + fnt->outline_thickness = 0.0f; + internal_draw_string(x, y, string, fnt, color, width, height); } void outlined_string(int x, int y, const std::string &string, - const font& font, rgba color, + font& font, rgba color, rgba outline, int *width, int *height) { + if (!font.isLoaded()) + font.load(); + auto fnt = glez::detail::font::get(font.getHandle()).font; + fnt->rendermode = RENDER_OUTLINE_POSITIVE; + fnt->outline_thickness = 1.0f; + internal_draw_string(x, y, string, fnt, outline, width, height); + fnt->rendermode = RENDER_NORMAL; + fnt->outline_thickness = 0.0f; + internal_draw_string(x, y, string, fnt, color, width, height); +} + +void +rect_textured(int x, int y, int w, int h, rgba color, texture &texture, int tx, int ty, int tw, int th) +{ + if (!texture.isLoaded()) + texture.load(); + + detail::render::vertex vertices[4]; + + for (auto &vertex : vertices) + { + vertex.mode = static_cast(detail::program::mode::TEXTURED); + vertex.color = color; + } + + vertices[0].position = { x, y }; + vertices[1].position = { x, y + h }; + vertices[2].position = { x + w, y + h }; + vertices[3].position = { x + w, y }; + + float s0 = tx / texture.getWidth(); + float s1 = (tx + tw) / texture.getWidth(); + float t0 = ty / texture.getHeight(); + float t1 = (ty + th) / texture.getHeight(); + + vertices[0].uv = {s0, t1}; + vertices[1].uv = {s0, t0}; + vertices[2].uv = {s1, t0}; + vertices[3].uv = {s1, t1}; + + ftgl::vertex_buffer_push_back(detail::program::buffer, vertices, 4, indices::rectangle, 6); } diff --git a/src/font.cpp b/src/font.cpp index ea3617e..899b80c 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -12,18 +12,21 @@ namespace glez font::~font() { if (loaded) - { - - } + unload(); } void font::load() { + handle = detail::font::create(); + auto& font = detail::font::get(handle); + font.load(path, size); + loaded = true; } void font::unload() { - + auto& font = detail::font::get(handle); + font.unload(); } } \ No newline at end of file diff --git a/src/texture.cpp b/src/texture.cpp index eb862bf..7dbbe50 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -18,14 +18,16 @@ texture::~texture() void texture::load() { handle = detail::texture::create(); - auto texture = detail::texture::get(handle); + auto& texture = detail::texture::get(handle); texture.load(path); + width = texture.width; + height = texture.height; loaded = true; } void texture::unload() { - auto texture = detail::texture::get(handle); + auto& texture = detail::texture::get(handle); texture.unload(); }