diff options
Diffstat (limited to 'src/libjin')
35 files changed, 1551 insertions, 792 deletions
diff --git a/src/libjin/Common/Exception.cpp b/src/libjin/Common/Exception.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/libjin/Common/Exception.cpp diff --git a/src/libjin/Common/Exception.h b/src/libjin/Common/Exception.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/libjin/Common/Exception.h diff --git a/src/libjin/Filesystem/Filesystem.cpp b/src/libjin/Filesystem/Filesystem.cpp index 3f91274..c3d271c 100644 --- a/src/libjin/Filesystem/Filesystem.cpp +++ b/src/libjin/Filesystem/Filesystem.cpp @@ -43,6 +43,8 @@ namespace filesystem return smtread(S, path, len); } + + const char* Filesystem::getFull(const char* path) { return smtfullpath(S, path); diff --git a/src/libjin/Game/Game.cpp b/src/libjin/Game/Game.cpp index 6dc75ce..f4e672d 100644 --- a/src/libjin/Game/Game.cpp +++ b/src/libjin/Game/Game.cpp @@ -46,6 +46,7 @@ namespace core if (_onDraw != nullptr) _onDraw(); wnd->swapBuffers(); + sleep(1); } quitloop:; } diff --git a/src/libjin/Graphics/Bitmap.h b/src/libjin/Graphics/Bitmap.h index 5510569..553d999 100644 --- a/src/libjin/Graphics/Bitmap.h +++ b/src/libjin/Graphics/Bitmap.h @@ -6,6 +6,7 @@ #include "../Math/Vector2.hpp" #include "../3rdparty/GLee/GLee.h" #include "Color.h" + namespace jin { namespace graphics @@ -18,7 +19,7 @@ namespace graphics static Bitmap* createBitmap(int w, int h, Color color = Color::BLACK); static Bitmap* clone(const Bitmap* bitmap); - ~Bitmap(); + virtual ~Bitmap(); /* init pixels */ void bind(Color* pixels, int w, int h); void resetPixels(const Color* pixels, int w, int h); @@ -32,8 +33,9 @@ namespace graphics /* get width and height */ inline int getWidth() const { return width; } inline int getHeight() const { return height; } + inline math::Vector2<int> getSize() const { return math::Vector2<int>(width, height); } - private: + protected: Bitmap(); Bitmap(int w, int h); diff --git a/src/libjin/Graphics/Color.h b/src/libjin/Graphics/Color.h index 6f9e887..3de49dc 100644 --- a/src/libjin/Graphics/Color.h +++ b/src/libjin/Graphics/Color.h @@ -76,12 +76,6 @@ namespace graphics Channel r, g, b, a; - //#if LIBJIN_BYTEORDER == LIBJIN_BIG_ENDIAN - // unsigned char r, g, b, a; - //#else - // unsigned char a, b, g, r; - //#endif - }; } // render diff --git a/src/libjin/Graphics/Drawable.cpp b/src/libjin/Graphics/Drawable.cpp index 77c3750..4be1cc2 100644 --- a/src/libjin/Graphics/Drawable.cpp +++ b/src/libjin/Graphics/Drawable.cpp @@ -10,7 +10,7 @@ namespace jin { namespace graphics { - + Drawable::Drawable(int w, int h) : texture(0) , size(w, h) @@ -27,6 +27,33 @@ namespace graphics texture_coords[6] = 1; texture_coords[7] = 0; } + Drawable::Drawable(const Bitmap* bitmap) + : texture(0) + , anchor(0, 0) + { + unsigned int w = size.w = bitmap->getWidth(); + unsigned int h = size.h = bitmap->getHeight(); + + vertex_coords[0] = 0; vertex_coords[1] = 0; + vertex_coords[2] = 0; vertex_coords[3] = h; + vertex_coords[4] = w; vertex_coords[5] = h; + vertex_coords[6] = w; vertex_coords[7] = 0; + + texture_coords[0] = 0; texture_coords[1] = 0; + texture_coords[2] = 0; texture_coords[3] = 1; + texture_coords[4] = 1; texture_coords[5] = 1; + texture_coords[6] = 1; texture_coords[7] = 0; + + const Color* pixels = bitmap->getPixels(); + + texture = gl.genTexture(); + gl.bindTexture(texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl.texImage(GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + gl.bindTexture(0); + } + Drawable::~Drawable() { glDeleteTextures(1, &texture); @@ -53,6 +80,38 @@ namespace graphics gl.bindTexture(0); } + void Drawable::draw(const math::Quad& slice, int x, int y, float sx, float sy, float r, float ax, float ay) + { + float vertCoords[8] = { + 0, 0, + 0, slice.h, + slice.w, slice.h, + slice.w, 0 + }; + float slx = slice.x / size.w; + float sly = slice.y / size.h; + float slw = slice.w / size.w; + float slh = slice.h / size.h; + float texCoords[8] = { + slx, sly, + slx, sly + slh, + slx + slw, sly + slh, + slx + slw, sly + }; + + gl.ModelMatrix.setTransformation(x, y, r, sx, sy, ax, ay); + + Shader* shader = Shader::getCurrentShader(); + shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); + shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); + shader->bindVertexPointer(2, GL_FLOAT, 0, vertCoords); + shader->bindUVPointer(2, GL_FLOAT, 0, texCoords); + + gl.bindTexture(texture); + gl.drawArrays(GL_QUADS, 0, 4); + gl.bindTexture(0); + } + } // render } // jin diff --git a/src/libjin/Graphics/Drawable.h b/src/libjin/Graphics/Drawable.h index c77068c..0c4c3ef 100644 --- a/src/libjin/Graphics/Drawable.h +++ b/src/libjin/Graphics/Drawable.h @@ -3,8 +3,10 @@ #include "../jin_configuration.h" #if LIBJIN_MODULES_RENDER +#include "../math/Quad.h" #include "../math/Vector2.hpp" #include "OpenGL.h" +#include "Bitmap.h" namespace jin { @@ -15,10 +17,12 @@ namespace graphics { public: Drawable(int w = 0, int h = 0); + Drawable(const Bitmap* bitmap); virtual ~Drawable(); void setAnchor(int x, int y); - void draw(int x, int y, float sx, float sy, float r); + void draw(int x, int y, float sx = 1, float sy = 1, float r = 0); + void draw(const math::Quad& slice, int x, int y, float sx = 1, float sy = 1, float r = 0, float ax = 0, float ay = 0); inline int getWidth() const { return size.w; } inline int getHeight() const { return size.h; } inline GLuint getTexture() const { return texture; } diff --git a/src/libjin/Graphics/Font.cpp b/src/libjin/Graphics/Font.cpp deleted file mode 100644 index 9060961..0000000 --- a/src/libjin/Graphics/Font.cpp +++ /dev/null @@ -1,363 +0,0 @@ -#include "../jin_configuration.h" -#if LIBJIN_MODULES_RENDER - -#include "OpenGL.h" -#include "font.h" -#include <stdio.h> -#include "color.h" -#include "Shader.h" -#include "../Common/Array.hpp" - -namespace jin -{ -namespace graphics -{ - - #include "Shaders/font.shader.h" - - using namespace std; - using namespace jin::math; - - const int Font::TEXTURE_WIDTHS[] = { 128, 256, 256, 512, 512, 1024, 1024 }; - const int Font::TEXTURE_HEIGHTS[] = { 128, 128, 256, 256, 512, 512, 1024 }; - - /* utf8 byte string to unicode codepoint */ - static const char* utf8toCodepoint(const char *p, unsigned *res) { - unsigned x, mask, shift; - switch (*p & 0xf0) { - case 0xf0: mask = 0x07; shift = 18; break; - case 0xe0: mask = 0x0f; shift = 12; break; - case 0xc0: - case 0xd0: mask = 0x1f; shift = 6; break; - default: - *res = *p; - return p + 1; - } - x = (*p & mask) << shift; - do { - if (*(++p) == '\0') { - *res = x; - return p; - } - shift -= 6; - x |= (*p & 0x3f) << shift; - } while (shift); - *res = x; - return p + 1; - } - - /* little endian unicode */ - static const char* unicodeLittleEndian(const char* p, unsigned* res) - { - } - - /*static*/ Font* Font::createFont(FontData* fontData, unsigned int fontSzie) - { - Font* font; - try - { - font = new Font(fontData, fontSzie); - } - catch (...) - { - return nullptr; - } - return font; - } - - Font::Font(FontData* f, unsigned int fontSize) - : cursor(0, 0) - , font(f) - , fontsize(fontSize) - { - font->pushFontsize(fontsize); - font->getVMetrics(&baseline, &descent); - estimateSize(); - font->popFontsize(); - /* create a default texture */ - createAtlas(); - } - - /* estimate the size of atlas texture */ - void Font::estimateSize() - { - for (int level = 0; level <= TEXTURE_SIZE_LEVEL_MAX; ++level) - { - if (descent * (descent*0.8) * 96 <= TEXTURE_WIDTHS[level] * TEXTURE_HEIGHTS[level]) - { - textureWidth = TEXTURE_WIDTHS[level]; - textureHeight = TEXTURE_HEIGHTS[level]; - break; - } - } - } - - Font::~Font() - { - map<unsigned int, Glyph*>::iterator it = glyphs.begin(); - for (; it != glyphs.end(); ++it) - { - delete it->second; - } - } - - GLuint Font::createAtlas() - { - GLuint t; - gl.flushError(); - t = gl.genTexture(); - gl.bindTexture(t); - gl.setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl.setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl.texImage(GL_RGBA8, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE); - if (glGetError() != GL_NO_ERROR) - { - glDeleteTextures(1, &t); - gl.bindTexture(0); - return 0; - } - atlases.push_back(t); - gl.bindTexture(0); - return t; - } - - void Font::print(const char* t, int x, int y, int lineheight, int spacing) - { - Page* page = typeset(t, lineheight, spacing); - print(page, x, y); - delete page; - } - - Page* Font::typeset(const char* text, int lineheight, int spacing) - { - // typesetting, for reducing draw call - const char* t = text; - Page* page = new Page(); - vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - vector<GlyphVertex>& glyphvertices = page->glyphvertices; - Vector2<int> p(0, 0); - Codepoint c; - int texture = -1; - Glyph* glyph = nullptr; - GlyphVertex vertex; - for (int i = 0; *t != NULL; i += 4) - { - t = utf8toCodepoint(t, &c); - if (c == 0x0D) - { - i -= 4; - continue; - } - /* new line */ - if (c == 0x0A) - { - p.y += lineheight; - p.x = 0; - i -= 4; - continue; - } - glyph = findGlyph(c); - if (texture != glyph->atlas) - { - GlyphArrayDrawInfo info; - info.start = i; - info.count = 0; - info.texture = glyph->atlas; - texture = glyph->atlas; - glyphinfolist.push_back(info); - } - glyphinfolist[glyphinfolist.size() - 1].count += 4; - Glyph::Bbox& bbox = glyph->bbox; - // 1 - vertex.x = p.x; vertex.y = p.y; - vertex.u = bbox.x; vertex.v = bbox.y; - glyphvertices.push_back(vertex); - // 2 - vertex.x = p.x; vertex.y = p.y + glyph->height; - vertex.u = bbox.x; vertex.v = bbox.y + bbox.height; - glyphvertices.push_back(vertex); - // 3 - vertex.x = p.x + glyph->width; vertex.y = p.y + glyph->height; - vertex.u = bbox.x + bbox.width; vertex.v = bbox.y + bbox.height; - glyphvertices.push_back(vertex); - // 4 - vertex.x = p.x + glyph->width; vertex.y = p.y; - vertex.u = bbox.x + bbox.width; vertex.v = bbox.y; - glyphvertices.push_back(vertex); - - p.x += glyph->width + spacing; - } - getTextBox(text, &page->width, &page->height, lineheight, spacing); - return page; - } - - void Font::print(const Page* page, int x, int y) - { - Shader* shader = Shader::getCurrentShader(); - const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - const vector<GlyphVertex>& glyphvertices = page->glyphvertices; - gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); - shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); - shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); - for (int i = 0; i < glyphinfolist.size(); ++i) - { - const GlyphArrayDrawInfo& info = glyphinfolist[i]; - shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); - shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); - gl.bindTexture(info.texture); - gl.drawArrays(GL_QUADS, 0, info.count); - gl.bindTexture(0); - } - } - - int Font::getCharWidth(int c) - { - int adw, lsb; - font->pushFontsize(fontsize); - font->getHMetrics(c, &adw, &lsb); - font->popFontsize(); - return adw; - } - - int Font::getCharHeight(int c) - { - return descent; - } - - int Font::getTextWidth(const char* t, int spacing) - { - font->pushFontsize(fontsize); - int res = 0; - int tmp = 0; - const char *p = t; - while (*p) { - unsigned c; - p = utf8toCodepoint(p, &c); - if (*p == 0x0D) - continue; - if (*p == 0x0A) - { - tmp = 0; - continue; - } - tmp += getCharWidth(c) + spacing; - if (tmp > res) res = tmp; - } - font->popFontsize(); - return res; - } - - int Font::getTextHeight(const char* t, int lineheight) - { - font->pushFontsize(fontsize); - int res = 0; - bool newline = true; - while (*t) - { - unsigned c; - t = utf8toCodepoint(t, &c); - if (*t == 0x0A) - newline = true; - else if (*t == 0x0D); - else if (newline) - { - newline = false; - res += lineheight; - } - } - font->popFontsize(); - return res; - } - - void Font::getTextBox(const char* text, int* w, int* h, int lineheight, int spacing) - { - font->pushFontsize(fontsize); - *w = 0; - *h = 0; - int tmp = 0; - const char* p = text; - const char* pt = nullptr; - bool nl = true; - while (*p) { - unsigned c; - pt = p; - p = utf8toCodepoint(p, &c); - if (*pt == 0x0D) - continue; - if (*pt == 0x0A) - { - tmp = 0; - nl = true; - continue; - } - else if(nl) - { - nl = false; - *h += lineheight; - } - tmp += getCharWidth(c) + spacing; - if (tmp > *w) *w = tmp; - } - font->popFontsize(); - } - - Glyph* Font::bakeGlyph(unsigned int character) - { - Glyph* glyph = (Glyph*)malloc(sizeof(Glyph)); - int w, h, xoff, yoff; - font->pushFontsize(fontsize); - GLuint atlas = atlases.back(); - const Color* bitmap = font->getCodepointBitmap(character, &w, &h, &xoff, &yoff); - int adw, lsb; - { - font->getHMetrics(character, &adw, &lsb); - font->popFontsize(); - if (cursor.x + adw > textureWidth ) - { - cursor.x = 0; - cursor.y += descent; - if (cursor.y + descent * 2 > textureHeight) - { - /* create new atlas */ - atlas = createAtlas(); - cursor.y = 0; - } - } - gl.bindTexture(atlas); - gl.texSubImage(cursor.x + xoff, cursor.y + yoff + baseline, w, h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap); - gl.bindTexture(); - delete[] bitmap; - } - glyph->atlas = atlas; - glyph->bbox.x = cursor.x / (float)textureWidth; - glyph->bbox.y = cursor.y / (float)textureHeight; - glyph->bbox.width = adw / (float)textureWidth; - glyph->bbox.height = descent / (float)textureHeight; - glyph->width = adw; - glyph->height = descent; - glyphs.insert(std::pair<unsigned int, Glyph*>(character, glyph)); - - cursor.x += adw; - return glyph; - } - - Glyph* Font::findGlyph(unsigned int character) - { - map<unsigned int, Glyph*>::iterator it = glyphs.find(character); - if (it != glyphs.end()) - { - return it->second; - } - else - { - Glyph* glyph = bakeGlyph(character); - return glyph; - } - } - -} // graphics -} // jin - -#endif // LIBJIN_MODULES_RENDER
\ No newline at end of file diff --git a/src/libjin/Graphics/Font.h b/src/libjin/Graphics/Font.h deleted file mode 100644 index 0cb07de..0000000 --- a/src/libjin/Graphics/Font.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __LIBJIN_FONT_H -#define __LIBJIN_FONT_H -#include "../jin_configuration.h" -#if LIBJIN_MODULES_RENDER - -#include <vector> -#include <map> -#include "drawable.h" -#include "FontData.h" -#include "../math/quad.h" - -namespace jin -{ -namespace graphics -{ - - struct GlyphVertex - { - int x, y; // screen coordinates - float u, v; // texture uv - }; - - struct GlyphArrayDrawInfo - { - GLuint texture; // atlas - unsigned int start; // glyph vertex indecies - unsigned int count; // glyph vertex count - }; - - struct Glyph - { - GLuint atlas; - /* normalized coordinates */ - struct Bbox - { - float x, y; - float width, height; - } bbox; - /* glyph size in pixel */ - unsigned int width, height; - }; - - struct Page - { - std::vector<GlyphArrayDrawInfo> glyphinfolist; - std::vector<GlyphVertex> glyphvertices; - int width, height; - }; - - class Font - { - public: - typedef unsigned int Codepoint; - - static Font* createFont(FontData* fontData, unsigned int fontSzie); - - Page* typeset(const char* text, int lineheight, int spacing); - void print(const char* text, int x, int y, int lineheight, int spacing = 0); - void print(const Page* page, int x, int y); - //Bitmap* bake(const char* text); -#if defined(font_debug) - void drawAtlas(); -#endif - ~Font(); - - private: - static const int TEXTURE_SIZE_LEVELS_COUNT = 7; - static const int TEXTURE_SIZE_LEVEL_MAX = TEXTURE_SIZE_LEVELS_COUNT - 1; - static const int TEXTURE_WIDTHS[TEXTURE_SIZE_LEVELS_COUNT]; - static const int TEXTURE_HEIGHTS[TEXTURE_SIZE_LEVELS_COUNT]; - - Font(FontData* font, Codepoint fontSize); - - void estimateSize(); - GLuint createAtlas(); - Glyph* bakeGlyph(Codepoint character); - Glyph* findGlyph(Codepoint character); - - int getCharWidth(int c); - int getCharHeight(int c); - int getTextWidth(const char* text, int spacing = 0); - int getTextHeight(const char* text, int lineheight); - void getTextBox(const char* text, int* w, int* h, int lineheight, int spacing = 0); - - int textureWidth; - int textureHeight; - std::vector<GLuint> atlases; - /* map unicode codepoint to glyph */ - std::map<Codepoint, Glyph*> glyphs; - FontData* font; - const unsigned int fontsize; - int baseline; - int descent; - - /* cursor helped render to texture */ - math::Vector2<float> cursor; - - }; - -} // graphics -} // jin - -#endif // LIBJIN_MODULES_RENDER -#endif // __LIBJIN_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Decoder.cpp b/src/libjin/Graphics/Font/Decoder.cpp new file mode 100644 index 0000000..10927f0 --- /dev/null +++ b/src/libjin/Graphics/Font/Decoder.cpp @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <string.h> +#include "Decoder.h" + +namespace jin +{ +namespace graphics +{ + + /* utf8 byte string to unicode codepoint */ + static const char *utf8toCodepoint(const char *p, unsigned *res) { + return nullptr; + + } + + ///////////////////////////////////////////////////////////////////////////// + // decoders + ///////////////////////////////////////////////////////////////////////////// + + const void* Utf8::decode(const void* data, Codepoint* res) const + { + const char* p = (char*)data; + unsigned x, mask, shift; + switch (*p & 0xf0) { + case 0xf0: mask = 0x07; shift = 18; break; + case 0xe0: mask = 0x0f; shift = 12; break; + case 0xc0: + case 0xd0: mask = 0x1f; shift = 6; break; + default: + *res = *p; + return p + 1; + } + x = (*p & mask) << shift; + do { + if (*(++p) == '\0') { + *res = x; + return p; + } + shift -= 6; + x |= (*p & 0x3f) << shift; + } while (shift); + *res = x; + return p + 1; + } + + const void* Utf8::next(const void* data) const + { + const char* p = (char*)data; + unsigned x, mask, shift; + switch (*p & 0xf0) { + case 0xf0: mask = 0x07; shift = 18; break; + case 0xe0: mask = 0x0f; shift = 12; break; + case 0xc0: + case 0xd0: mask = 0x1f; shift = 6; break; + default: + return p + 1; + } + x = (*p & mask) << shift; + do { + if (*(++p) == '\0') { + return p; + } + shift -= 6; + x |= (*p & 0x3f) << shift; + } while (shift); + return p + 1; + } +/* + const void* Utf16::decode(const void* data, Codepoint* res) const + { + return nullptr; + } + + const void* Utf16::next(const void* data) const + { + return nullptr; + } +*/ + const void* Ascii::decode(const void* data, Codepoint* res) const + { + const char* p = (char*)data; + *res = *p; + return p + 1; + } + + const void* Ascii::next(const void* data) const + { + const char* p = (char*)data; + return p + 1; + } + +} // graphics +} // jin
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Decoder.h b/src/libjin/Graphics/Font/Decoder.h new file mode 100644 index 0000000..4568d65 --- /dev/null +++ b/src/libjin/Graphics/Font/Decoder.h @@ -0,0 +1,44 @@ +#ifndef __LIBJIN_UTF8_H +#define __LIBJIN_UTF8_H + +#include <vector> + +#include "Text.h" + +namespace jin +{ +namespace graphics +{ + + class Decoder + { + public: + virtual const void* decode(const void* data, Codepoint* c) const = 0 ; + virtual const void* next(const void* data) const = 0; + }; + + class Utf8 : public Decoder + { + public: + const void* decode(const void* data, Codepoint* c) const override; + const void* next(const void* data) const override; + }; +/* + class Utf16 : public Decoder + { + public: + const void* decode(const void* data, Codepoint* c) const override; + const void* next(const void* data) const override; + }; +*/ + class Ascii : public Decoder + { + public: + const void* decode(const void* data, Codepoint* c) const override; + const void* next(const void* data) const override; + }; + +} // graphics +} // jin + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Font.h b/src/libjin/Graphics/Font/Font.h new file mode 100644 index 0000000..424c324 --- /dev/null +++ b/src/libjin/Graphics/Font/Font.h @@ -0,0 +1,31 @@ +#ifndef __LIBJIN_FONT_H +#define __LIBJIN_FONT_H +#include <vector> +#include "Text.h" + +namespace jin +{ +namespace graphics +{ + + struct Page; + + class Font + { + public: + Font() {} + virtual ~Font() {}; + + virtual Page* typeset(const Text& text, int lineheight, int spacing = 0) = 0; + virtual Page* typeset(const Content& text, int lineheight, int spacing = 0) = 0; + + virtual void print(const Page* page, int x, int y) = 0; + virtual void print(const Content& text, int x, int y, int lineheight, int spacing = 0) = 0; + virtual void print(const Text& text, int x, int y, int lineheight, int spacing = 0) = 0; + + }; + +} // graphics +} // jin + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Page.h b/src/libjin/Graphics/Font/Page.h new file mode 100644 index 0000000..6e7cbdf --- /dev/null +++ b/src/libjin/Graphics/Font/Page.h @@ -0,0 +1,38 @@ +#ifndef __LIBJIN_PAGE_H +#define __LIBJIN_PAGE_H +#include "../../math/Vector2.hpp" +#include "Font.h" + +namespace jin +{ +namespace graphics +{ + + class Font; + + struct GlyphVertex + { + int x, y; // screen coordinates + float u, v; // texture uv + }; + + struct GlyphArrayDrawInfo + { + GLuint texture; // atlas + unsigned int start; // glyph vertex indecies + unsigned int count; // glyph vertex count + }; + + /* for reduce draw call */ + struct Page + { + Font* font; + std::vector<GlyphArrayDrawInfo> glyphinfolist; + std::vector<GlyphVertex> glyphvertices; + math::Vector2<int> size; + }; + +} +} + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/TTF.cpp b/src/libjin/Graphics/Font/TTF.cpp new file mode 100644 index 0000000..98e57dd --- /dev/null +++ b/src/libjin/Graphics/Font/TTF.cpp @@ -0,0 +1,463 @@ +#include "../../jin_configuration.h" +#if LIBJIN_MODULES_RENDER + +#include <stdio.h> + +#include "../../Common/Array.hpp" +#include "../OpenGL.h" +#include "../Color.h" +#include "../Shader.h" +#include "TTF.h" +#include "Page.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#include "../../3rdparty/stb/stb_truetype.h" + +namespace jin +{ +namespace graphics +{ + + /////////////////////////////////////////////////////////////////////////////////////////////// + // TTFData + /////////////////////////////////////////////////////////////////////////////////////////////// + + TTFData* TTFData::createTTFData(const unsigned char* data, unsigned int size) + { + TTFData* ttf = nullptr; + try + { + ttf = new TTFData(data, size); + return ttf; + } + catch (...) + { + return nullptr; + } + } + + TTFData::TTFData(const unsigned char* d, unsigned int s) + { + raw.size = s; + raw.data = (unsigned char*)malloc(s); + memcpy(raw.data, d, s); + if (!stbtt_InitFont(&info, (const unsigned char*)raw.data, 0)) + { + delete raw.data; + throw 0; + } + /* push default fontsize */ + pushTTFsize(FONT_SIZE); + } + + TTFData::~TTFData() + { + free(raw.data); + } + + /* + * (0, 0) + * +--------------+ ascent + * | +--------+ | + * | | | | + * | | bitmap | | + * +--|--------|--+ baseline + * | +--------+ | + * +--|-----------+ decent + * | | + * leftSideBearing | + * advanceWidth + */ + void TTFData::getVMetrics(int* baseline, int* descent) + { + float scale = scales.back(); + int ascent; + stbtt_GetFontVMetrics(&info, &ascent, descent, 0); + *baseline = (int)(ascent*scale) + 1; // slight adjustment + *descent = *baseline - (int)(*descent*scale) + 1; + } + + void TTFData::getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing) + { + float scale = scales.back(); + int adw, lsb; + stbtt_GetCodepointHMetrics(&info, codepoint, &adw, &lsb); + *advanceWidth = (int)(adw*scale); + *leftSideBearing = (int)(lsb*scale); + } + + void TTFData::pushTTFsize(unsigned int fs) + { + float sc = stbtt_ScaleForPixelHeight(&info, fs); + scales.push_back(sc); + } + + void TTFData::popTTFsize() + { + /* always keep default ttf size on the bottom of stack */ + if (scales.size() > 1) + scales.pop_back(); + } + + Channel* TTFData::getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const + { + float scale = scales.back(); + Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); + return bitmap; + } + + Color* TTFData::getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const + { + float scale = scales.back(); + Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); + int w = *width, h = *height; + //int xo = *xoff, yo = *yoff; + Color* bitmap32 = new Color[w*h]; + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + bitmap32[x + y * w].set(0xff, 0xff, 0xff, bitmap[x + y * w]); + } + } + free(bitmap); + return bitmap32; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // TTF + /////////////////////////////////////////////////////////////////////////////////////////////// + + #include "../Shaders/font.shader.h" + + using namespace std; + using namespace jin::math; + + const int TTF::TEXTURE_WIDTHS[] = { 128, 256, 256, 512, 512, 1024, 1024 }; + const int TTF::TEXTURE_HEIGHTS[] = { 128, 128, 256, 256, 512, 512, 1024 }; + + /* utf8 byte string to unicode codepoint */ + static const char* utf8toCodepoint(const char *p, Codepoint *res) { + unsigned x, mask, shift; + switch (*p & 0xf0) { + case 0xf0: mask = 0x07; shift = 18; break; + case 0xe0: mask = 0x0f; shift = 12; break; + case 0xc0: + case 0xd0: mask = 0x1f; shift = 6; break; + default: + *res = *p; + return p + 1; + } + x = (*p & mask) << shift; + do { + if (*(++p) == '\0') { + *res = x; + return p; + } + shift -= 6; + x |= (*p & 0x3f) << shift; + } while (shift); + *res = x; + return p + 1; + } + + /* little endian unicode */ + static const char* unicodeLittleEndian(const char* p, unsigned* res) + { + } + + /*static*/ TTF* TTF::createTTF(TTFData* fontData, unsigned int fontSzie) + { + TTF* ttf; + try + { + ttf = new TTF(fontData, fontSzie); + } + catch (...) + { + return nullptr; + } + return ttf; + } + + TTF::TTF(TTFData* f, unsigned int fontSize) + : cursor(0, 0) + , ttf(f) + , ttfsize(fontSize) + { + ttf->pushTTFsize(ttfsize); + ttf->getVMetrics(&baseline, &descent); + estimateSize(); + ttf->popTTFsize(); + /* create a default texture */ + createAtlas(); + } + + /* estimate the size of atlas texture */ + void TTF::estimateSize() + { + for (int level = 0; level <= TEXTURE_SIZE_LEVEL_MAX; ++level) + { + if (descent * (descent*0.8) * 96 <= TEXTURE_WIDTHS[level] * TEXTURE_HEIGHTS[level]) + { + textureWidth = TEXTURE_WIDTHS[level]; + textureHeight = TEXTURE_HEIGHTS[level]; + break; + } + } + } + + TTF::~TTF() + { + } + + GLuint TTF::createAtlas() + { + GLuint t; + gl.flushError(); + t = gl.genTexture(); + gl.bindTexture(t); + gl.setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl.setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.texImage(GL_RGBA8, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE); + if (glGetError() != GL_NO_ERROR) + { + glDeleteTextures(1, &t); + gl.bindTexture(0); + return 0; + } + atlases.push_back(t); + gl.bindTexture(0); + return t; + } + + void TTF::print(const Content& t, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(t, lineheight, spacing); + print(page, x, y); + delete page; + } + +#define glyphvertices_push(_x, _y, _u, _v) \ + vertex.x = _x; vertex.y = _y;\ + vertex.u = _u; vertex.v = _v;\ + glyphvertices.push_back(vertex); + +#define glyphlize(c)\ + do{\ + glyph = &findGlyph(c); \ + if (texture != glyph->atlas) \ + { \ + GlyphArrayDrawInfo info; \ + info.start = i; \ + info.count = 0; \ + info.texture = glyph->atlas; \ + texture = glyph->atlas; \ + glyphinfolist.push_back(info); \ + } \ + glyphinfolist[glyphinfolist.size() - 1].count += 4; \ + TTFGlyph::Bbox& bbox = glyph->bbox; \ + glyphvertices_push(p.x, p.y, bbox.x, bbox.y); \ + glyphvertices_push(p.x, p.y + glyph->height, bbox.x, bbox.y + bbox.h); \ + glyphvertices_push(p.x + glyph->width, p.y + glyph->height, bbox.x + bbox.w, bbox.y + bbox.h); \ + glyphvertices_push(p.x + glyph->width, p.y, bbox.x + bbox.w, bbox.y); \ + }while(0) + + Page* TTF::typeset(const Content& text, int lineheight, int spacing) + { + Page* page = new Page(); + page->font = this; + vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + vector<GlyphVertex>& glyphvertices = page->glyphvertices; + int texture = -1; + TTFGlyph* glyph = nullptr; + GlyphVertex vertex; + Vector2<int> p(0, 0); + int i = 0; + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + /* new line */ + p.y += lineheight; + p.x = 0; + continue; + } + glyphlize(c); + p.x += glyph->width + spacing; + i += 4; + } + getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); + return page; + } + + Page* TTF::typeset(const Text& text, int lineheight, int spacing) + { + return typeset(*text, lineheight, spacing); + } + + void TTF::print(const Page* page, int x, int y) + { + Shader* shader = Shader::getCurrentShader(); + const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + const vector<GlyphVertex>& glyphvertices = page->glyphvertices; + gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); + shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); + shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); + for (int i = 0; i < glyphinfolist.size(); ++i) + { + const GlyphArrayDrawInfo& info = glyphinfolist[i]; + shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); + shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); + gl.bindTexture(info.texture); + gl.drawArrays(GL_QUADS, 0, info.count); + gl.bindTexture(0); + } + } + + void TTF::print(const Text& text, int x, int y, int lineheight, int spacing /* = 0 */) + { + print(*text, x, y, lineheight, spacing); + } + + int TTF::getCharWidth(int c) + { + int adw, lsb; + ttf->pushTTFsize(ttfsize); + ttf->getHMetrics(c, &adw, &lsb); + ttf->popTTFsize(); + return adw; + } + + int TTF::getCharHeight(int c) + { + return descent; + } + + int TTF::getTextWidth(const Content& t, int spacing) + { + ttf->pushTTFsize(ttfsize); + int res = 0; + int tmp = 0; + for (Codepoint c : t) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + continue; + } + tmp += getCharWidth(c) + spacing; + if (tmp > res) + res = tmp; + } + ttf->popTTFsize(); + return res; + } + + int TTF::getTextHeight(const Content& t, int lineheight) + { + ttf->pushTTFsize(ttfsize); + int res = 0; + bool newline = true; + for (Codepoint c : t) + { + if (c == 0x0A) + newline = true; + else if (c == 0x0D); + else if (newline) + { + newline = false; + res += lineheight; + } + } + ttf->popTTFsize(); + return res; + } + + void TTF::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) + { + ttf->pushTTFsize(ttfsize); + *w = 0; + *h = 0; + int tmp = 0; + bool newline = true; + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + newline = true; + continue; + } + else if (newline) + { + newline = false; + *h += lineheight; + } + tmp += getCharWidth(c) + spacing; + if (tmp > *w) + *w = tmp; + } + ttf->popTTFsize(); + } + + TTF::TTFGlyph& TTF::bakeGlyph(unsigned int character) + { + int w, h, xoff, yoff; + ttf->pushTTFsize(ttfsize); + GLuint atlas = atlases.back(); + const Color* bitmap = ttf->getCodepointBitmap(character, &w, &h, &xoff, &yoff); + int adw, lsb; + { + ttf->getHMetrics(character, &adw, &lsb); + ttf->popTTFsize(); + if (cursor.x + adw > textureWidth ) + { + cursor.x = 0; + cursor.y += descent; + if (cursor.y + descent * 2 > textureHeight) + { + /* create new atlas */ + atlas = createAtlas(); + cursor.y = 0; + } + } + gl.bindTexture(atlas); + gl.texSubImage(cursor.x + xoff, cursor.y + yoff + baseline, w, h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap); + gl.bindTexture(); + delete[] bitmap; + } + TTFGlyph glyph; + glyph.atlas = atlas; + glyph.bbox.x = cursor.x / (float)textureWidth; + glyph.bbox.y = cursor.y / (float)textureHeight; + glyph.bbox.w = adw / (float)textureWidth; + glyph.bbox.h = descent / (float)textureHeight; + glyph.width = adw; + glyph.height = descent; + glyphs.insert(std::pair<unsigned int, TTFGlyph>(character, glyph)); + cursor.x += adw; + return glyphs[character]; + } + + TTF::TTFGlyph& TTF::findGlyph(unsigned int character) + { + map<unsigned int, TTFGlyph>::iterator it = glyphs.find(character); + if (it != glyphs.end()) + return it->second; + else + return bakeGlyph(character); + } + +} // graphics +} // jin + +#endif // LIBJIN_MODULES_RENDER
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/TTF.h b/src/libjin/Graphics/Font/TTF.h new file mode 100644 index 0000000..4f51138 --- /dev/null +++ b/src/libjin/Graphics/Font/TTF.h @@ -0,0 +1,127 @@ +#ifndef __LIBJINTTF_H +#define __LIBJIN_TTF_H +#include "../../jin_configuration.h" +#if LIBJIN_MODULES_RENDER + +#include <vector> +#include <map> + +#include "../../3rdparty/stb/stb_truetype.h" +#include "../../math/quad.h" +#include "../Color.h" +#include "../drawable.h" + +#include "Page.h" +#include "Font.h" +#include "Text.h" + +namespace jin +{ +namespace graphics +{ + + /** + * TTFData + * |- TTF + * |- TTF + * . + * . + * . + */ + class TTFData + { + public: + static TTFData* createTTFData(const unsigned char* data, unsigned int size); + + ~TTFData(); + + void pushTTFsize(unsigned int ttfsize); + void popTTFsize(); + + Channel* getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; + Color* getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; + + void getVMetrics(int* baseline, int* descent); + void getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing); + + private: + static const unsigned int FONT_SIZE = 12; + + TTFData(const unsigned char* data, unsigned int size); + + stbtt_fontinfo info; + struct + { + unsigned char* data; + unsigned int size; + } raw; + std::vector<float> scales; + + }; + + class TTF : public Font + { + public: + static TTF* createTTF(TTFData* ttfData, unsigned int ttfSzie); + + Page* typeset(const Text& text, int lineheight, int spacing = 0) override; + Page* typeset(const Content& text, int lineheight, int spacing = 0) override; + + void print(const Text& text, int x, int y, int lineheight, int spacing = 0) override; + void print(const Content& text, int x, int y, int lineheight, int spacing = 0) override; + void print(const Page* page, int x, int y) override; + + ~TTF(); + + private: + struct TTFGlyph + { + GLuint atlas; + /* normalized coordinates */ + struct Bbox + { + float x, y; + float w, h; + } bbox; + /* glyph size in pixel */ + unsigned int width, height; + }; + + static const int TEXTURE_SIZE_LEVELS_COUNT = 7; + static const int TEXTURE_SIZE_LEVEL_MAX = TEXTURE_SIZE_LEVELS_COUNT - 1; + static const int TEXTURE_WIDTHS[TEXTURE_SIZE_LEVELS_COUNT]; + static const int TEXTURE_HEIGHTS[TEXTURE_SIZE_LEVELS_COUNT]; + + TTF(TTFData* ttf, Codepoint ttfSize); + + void estimateSize(); + GLuint createAtlas(); + TTFGlyph& bakeGlyph(Codepoint character); + TTFGlyph& findGlyph(Codepoint character); + + int getCharWidth(int c); + int getCharHeight(int c); + + int getTextWidth(const Content& text, int spacing = 0); + int getTextHeight(const Content& text, int lineheight); + void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); + + int textureWidth; + int textureHeight; + std::vector<GLuint> atlases; + std::map<Codepoint, TTFGlyph> glyphs; + TTFData* ttf; + const unsigned int ttfsize; + int baseline; + int descent; + + /* cursor helped render to texture */ + math::Vector2<float> cursor; + + }; + +} // graphics +} // jin + +#endif // LIBJIN_MODULES_RENDER +#endif // __LIBJIN_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Text.cpp b/src/libjin/Graphics/Font/Text.cpp new file mode 100644 index 0000000..68601de --- /dev/null +++ b/src/libjin/Graphics/Font/Text.cpp @@ -0,0 +1,151 @@ +#include <cstring> + +#include "Text.h" +#include "Decoder.h" + +namespace jin +{ +namespace graphics +{ + + ///////////////////////////////////////////////////////////////////////////// + // iterator + ///////////////////////////////////////////////////////////////////////////// + + Text::Iterator::Iterator(const Iterator& itor) + : data(itor.data) + , p(itor.p) + , encode(itor.encode) + , length(itor.length) + { + switch (encode) + { + case Encode::UTF8: decoder = new Utf8(); break; + //case Encode::UTF16: decoder = new Utf16(); break; + case Encode::ASCII: decoder = new Ascii(); break; + } + } + + Text::Iterator::Iterator(const Encode& _encode, const void* _data, unsigned int _length) + : data(_data) + , p(_data) + , encode(_encode) + , length(_length) + { + switch (encode) + { + case Encode::UTF8: decoder = new Utf8(); break; + //case Encode::UTF16: decoder = new Utf16(); break; + case Encode::ASCII: decoder = new Ascii(); break; + } + } + + Text::Iterator::~Iterator() + { + delete decoder; + } + + Codepoint Text::Iterator::get() + { + Codepoint codepoint; + decoder->decode(p, &codepoint); + return codepoint; + } + + Codepoint Text::Iterator::operator*() + { + return get(); + } + + Text::Iterator Text::Iterator::begin() + { + Iterator itor(encode, data, length); + itor.toBegin(); + return itor; + } + + Text::Iterator Text::Iterator::end() + { + Iterator itor(encode, data, length); + itor.toEnd(); + return itor; + } + + void Text::Iterator::toBegin() + { + p = (const unsigned char*)data; + } + + void Text::Iterator::toEnd() + { + p = (const unsigned char*)data + length; + } + + Text::Iterator& Text::Iterator::operator ++() + { + p = decoder->next(p); + return *this; + } + + Text::Iterator Text::Iterator::operator ++(int) + { + p = decoder->next(p); + Iterator itor(encode, data, length); + itor.p = p; + return itor; + } + + bool Text::Iterator::operator !=(const Iterator& itor) + { + return !(data == itor.data + && p == itor.p + && length == itor.length + && encode == itor.encode); + } + + bool Text::Iterator::operator ==(const Iterator& itor) + { + return data == itor.data + && p == itor.p + && length == itor.length + && encode == itor.encode; + } + + ///////////////////////////////////////////////////////////////////////////// + // text + ///////////////////////////////////////////////////////////////////////////// + + Text::Text(Encode encode, const void* data) + { + Iterator it = Iterator(encode, data, strlen((const char*)data)); + for (; it != it.end(); ++it) + { + content.push_back(*it); + } + } + + Text::Text(Encode _encode, const void* _data, unsigned int _length) + { + Iterator it = Iterator(_encode, _data, _length); + for (; it != it.end(); ++it) + { + content.push_back(*it); + } + } + + Text::~Text() + { + } + + const Content& Text::getContent() const + { + return content; + } + + const Content& Text::operator*() const + { + return content; + } + +} // graphics +} // jin
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/Text.h b/src/libjin/Graphics/Font/Text.h new file mode 100644 index 0000000..3faabc0 --- /dev/null +++ b/src/libjin/Graphics/Font/Text.h @@ -0,0 +1,74 @@ +#ifndef __LIBJIN_TEXT_H +#define __LIBJIN_TEXT_H + +#include <vector> + +namespace jin +{ +namespace graphics +{ + + typedef unsigned int Codepoint; + + typedef std::vector<Codepoint> Content; + + class Text; + class Decoder; + + enum Encode + { + UTF8, // utf-8 + //UTF16, // utf-16 + ASCII, // ASCII + }; + + /* raw encoded text */ + class Text + { + public: + Text(Encode encode, const void* data); + Text(Encode encode, const void* data, unsigned int length); + ~Text(); + + const Content& getContent() const; + const Content& operator*() const; + + private: + class Iterator + { + public: + Iterator(const Iterator& itor); + Iterator(const Encode& encode, const void* data, unsigned int length); + ~Iterator(); + + Codepoint get(); + Iterator begin(); + Iterator end(); + void toBegin(); + void toEnd(); + Codepoint operator *(); + /* prefix ++ */ + Iterator& operator ++(); + /* postfix ++ */ + Iterator operator ++(int); + bool operator !=(const Iterator& itor); + bool operator ==(const Iterator& itor); + + private: + void operator = (const Iterator&); + + const Encode encode; + const Decoder* decoder; + const void* p; + const void* const data; + unsigned int length; + }; + + Content content; + + }; + +} // graphics +} // jin + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/TextureFont.cpp b/src/libjin/Graphics/Font/TextureFont.cpp new file mode 100644 index 0000000..4dde236 --- /dev/null +++ b/src/libjin/Graphics/Font/TextureFont.cpp @@ -0,0 +1,300 @@ +#include <vector> + +#include "../../Math/Vector2.hpp" +#include "../Shader.h" +#include "TextureFont.h" + +namespace jin +{ +namespace graphics +{ + + using namespace std; + using namespace math; + + TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, codepoints, cellw, cellh); + return tf; + } + + TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, int cellw, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, *codepoints, cellw, cellh); + return tf; + } + + TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, codepoints, mask, cellh); + return tf; + } + + TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, Color mask, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, *codepoints, mask, cellh); + return tf; + } + + TextureFont::~TextureFont() + { + } + + const TextureFont::TextureGlyph* TextureFont::findGlyph(Codepoint codepoint) const + { + auto it = glyphs.find(codepoint); + if (it != glyphs.end()) + { + return &it->second; + } + else + return nullptr; + } + + Page* TextureFont::typeset(const Content& text, int lineheight, int spacing) + { + Page* page = new Page(); + page->font = this; + vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + vector<GlyphVertex>& glyphvertices = page->glyphvertices; + int texture = -1; + const TextureGlyph* glyph = nullptr; + GlyphVertex vertex; + Vector2<int> p(0, 0); + int i = 0; + +#define glyphvertices_push(_x, _y, _u, _v) \ + vertex.x = _x; vertex.y = _y;\ + vertex.u = _u; vertex.v = _v;\ + glyphvertices.push_back(vertex);\ + + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + /* new line */ + p.y += lineheight; + p.x = 0; + continue; + } + glyph = findGlyph(c); + if (glyph == nullptr) + continue; + if (texture != this->texture) + { + texture = this->texture; + GlyphArrayDrawInfo info; + info.start = i; + info.count = 0; + info.texture = texture; + glyphinfolist.push_back(info); + } + glyphinfolist[glyphinfolist.size() - 1].count += 4; + // normalized + float nx = glyph->x / (float)size.w, ny = glyph->y / (float)size.h; + float nw = glyph->w / (float)size.w, nh = glyph->h / (float)size.h; + glyphvertices_push(p.x, p.y, nx, ny); + glyphvertices_push(p.x, p.y + glyph->h, nx, ny + nh); + glyphvertices_push(p.x + glyph->w, p.y + glyph->h, nx + nw, ny + nh); + glyphvertices_push(p.x + glyph->w, p.y, nx + nw, ny); + p.x += glyph->w + spacing; + i += 4; + } + getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); + return page; + } + + int TextureFont::getCharWidth(int c) + { + auto it = glyphs.find(c); + if (it != glyphs.end()) + { + return it->second.w; + } + return 0; + } + + int TextureFont::getCharHeight(int c) + { + auto it = glyphs.find(c); + if (it != glyphs.end()) + { + return it->second.h; + } + return 0; + } + + int TextureFont::getTextWidth(const Content& t, int spacing) + { + int res = 0; + int tmp = 0; + for (Codepoint c : t) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + continue; + } + tmp += getCharWidth(c) + spacing; + if (tmp > res) + res = tmp; + } + return res; + } + + int TextureFont::getTextHeight(const Content& t, int lineheight) + { + int res = 0; + bool newline = true; + for (Codepoint c : t) + { + if (c == 0x0A) + newline = true; + else if (c == 0x0D); + else if (newline) + { + newline = false; + res += lineheight; + } + } + return res; + } + + void TextureFont::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) + { + *w = 0; + *h = 0; + int tmp = 0; + bool newline = true; + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + newline = true; + continue; + } + else if (newline) + { + newline = false; + *h += lineheight; + } + tmp += getCharWidth(c) + spacing; + if (tmp > *w) + *w = tmp; + } + } + + Page* TextureFont::typeset(const Text& text, int lineheight, int spacing) + { + return typeset(*text, lineheight, spacing); + } + + void TextureFont::print(const Page* page, int x, int y) + { + Shader* shader = Shader::getCurrentShader(); + const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + const vector<GlyphVertex>& glyphvertices = page->glyphvertices; + gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); + shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); + shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); + for (int i = 0; i < glyphinfolist.size(); ++i) + { + const GlyphArrayDrawInfo& info = glyphinfolist[i]; + shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); + shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); + gl.bindTexture(info.texture); + gl.drawArrays(GL_QUADS, 0, info.count); + gl.bindTexture(0); + } + } + + void TextureFont::print(const Content& text, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(text, lineheight, spacing); + print(page, x, y); + delete page; + } + + void TextureFont::print(const Text& text, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(text, lineheight, spacing); + print(page, x, y); + delete page; + } + + TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) + : Drawable(bitmap) + { + TextureGlyph glyph; + Vector2<int> count(bitmap->getWidth() / cellw, bitmap->getHeight() / cellh); + glyph.w = cellw; + glyph.h = cellh; + for (int y = 0; y < count.row; ++y) + { + glyph.y = y * cellh; + for (int x = 0; x < count.colum; ++x) + { + glyph.x = x * cellw; + if (x + y * count.colum >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[x + y * count.colum], glyph)); + } + } + } + + TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) + : Drawable(bitmap) + { + TextureGlyph glyph; + glyph.h = cellh; + int w = bitmap->getWidth(); + int h = bitmap->getHeight(); + int i = 0; + for (int y = 0; y < h; y += cellh) + { + glyph.y = y; + bool newc = false; + for (int x = 0; x <= w; ++x) + { + if (x == w && newc) + { + glyph.w = x - glyph.x; + if (i >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); + ++i; + newc = false; + break; + } + Color c = bitmap->getPixels()[x + y * w]; + if (!newc && c != mask) + { + glyph.x = x; + newc = true; + } + else if (newc && c == mask) + { + glyph.w = x - glyph.x; + if (i >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); + if (codepoints[i] == 't') + { + int a = 10; + } + ++i; + newc = false; + } + } + } + } + +} +}
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/TextureFont.h b/src/libjin/Graphics/Font/TextureFont.h new file mode 100644 index 0000000..0d0d091 --- /dev/null +++ b/src/libjin/Graphics/Font/TextureFont.h @@ -0,0 +1,62 @@ +#ifndef __LIBJIN_TEXTURE_FONT_H +#define __LIBJIN_TEXTURE_FONT_H + +#include <map> +#include <vector> + +#include "../../Math/Vector4.hpp" +#include "../Drawable.h" +#include "../Bitmap.h" + +#include "Page.h" +#include "Font.h" +#include "Text.h" + +namespace jin +{ +namespace graphics +{ + + /* Texture font */ + class TextureFont : public Font + , public Drawable + { + public: + static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); + static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, int cellw, int cellh); + static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); + static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, Color mask, int cellh); + + ~TextureFont(); + + Page* typeset(const Text& text, int lineheight, int spacing = 0) override; + Page* typeset(const Content& text, int lineheight, int spacing = 0) override ; + + void print(const Page* page, int x, int y) override; + void print(const Content& text, int x, int y, int linehgiht, int spacing = 0) override; + void print(const Text& text, int x, int y, int lineheight, int spacing = 0)override; + + private: + struct TextureGlyph + { + float x, y, w, h; + }; + + TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); + TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); + + int getCharWidth(int c); + int getCharHeight(int c); + int getTextWidth(const Content& text, int spacing = 0); + int getTextHeight(const Content& text, int lineheight); + void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); + const TextureGlyph* findGlyph(Codepoint codepoint) const; + + std::map<Codepoint, TextureGlyph> glyphs; + + }; + +} +} + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/FontData.cpp b/src/libjin/Graphics/FontData.cpp deleted file mode 100644 index 1b66b12..0000000 --- a/src/libjin/Graphics/FontData.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "FontData.h" -#define STB_TRUETYPE_IMPLEMENTATION -#include "../3rdparty/stb/stb_truetype.h" -#include <stdio.h> - -namespace jin -{ -namespace graphics -{ - - FontData* FontData::createFontData(const unsigned char* data, unsigned int size) - { - FontData* font = nullptr; - try - { - font = new FontData(data, size); - return font; - } - catch (...) - { - return nullptr; - } - } - - FontData::FontData(const unsigned char* d, unsigned int s) - { - raw.size = s; - raw.data = (unsigned char*)malloc(s); - memcpy(raw.data, d, s); - if (!stbtt_InitFont(&info, (const unsigned char*)raw.data, 0)) - { - delete raw.data; - throw 0; - } - /* push default fontsize */ - pushFontsize(FONT_SIZE); - } - - FontData::~FontData() - { - free(raw.data); - } - - /* - * (0, 0) - * +--------------+ ascent - * | +--------+ | - * | | | | - * | | bitmap | | - * +--|--------|--+ baseline - * | +--------+ | - * +--|-----------+ decent - * | | - * leftSideBearing | - * | - * advanceWidth - */ - void FontData::getVMetrics(int* baseline, int* descent) - { - float scale = scales.back(); - int ascent; - stbtt_GetFontVMetrics(&info, &ascent, descent, 0); - *baseline = (int)(ascent*scale) + 1; // slight adjustment - *descent = *baseline - (int)(*descent*scale) + 1; - } - - void FontData::getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing) - { - float scale = scales.back(); - int adw, lsb; - stbtt_GetCodepointHMetrics(&info, codepoint, &adw, &lsb); - *advanceWidth = (int)(adw*scale); - *leftSideBearing = (int)(lsb*scale); - } - - void FontData::pushFontsize(unsigned int fs) - { - float sc = stbtt_ScaleForPixelHeight(&info, fs); - scales.push_back(sc); - } - - void FontData::popFontsize() - { - /* always keep default font size on the bottom of stack */ - if(scales.size() > 1) - scales.pop_back(); - } - - Channel* FontData::getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const - { - float scale = scales.back(); - Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); - return bitmap; - } - - Color* FontData::getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const - { - float scale = scales.back(); - Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); - int w = *width, h = *height; - //int xo = *xoff, yo = *yoff; - Color* bitmap32 = new Color[w*h]; - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - bitmap32[x + y * w].set(0xff, 0xff, 0xff, bitmap[x + y * w]); - } - } - free(bitmap); - return bitmap32; - } - -} -}
\ No newline at end of file diff --git a/src/libjin/Graphics/FontData.h b/src/libjin/Graphics/FontData.h deleted file mode 100644 index c75b9a1..0000000 --- a/src/libjin/Graphics/FontData.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __LIBJIN_FONTDATA_H -#define __LIBJIN_FONTDATA_H -#include "../3rdparty/stb/stb_truetype.h" -#include "Color.h" -#include <vector> - -namespace jin -{ -namespace graphics -{ - - class FontData - { - public: - static FontData* createFontData(const unsigned char* data, unsigned int size); - - ~FontData(); - - void pushFontsize(unsigned int fontsize); - void popFontsize(); - - Channel* getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; - Color* getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; - void getVMetrics(int* baseline, int* descent); - void getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing); - - private: - static const unsigned int FONT_SIZE = 12; - - FontData(const unsigned char* data, unsigned int size); - - stbtt_fontinfo info; - struct - { - unsigned char* data; - unsigned int size; - } raw; - std::vector<float> scales; - - }; - -} -} - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Graphics.h b/src/libjin/Graphics/Graphics.h index a4bf98b..54889f9 100644 --- a/src/libjin/Graphics/Graphics.h +++ b/src/libjin/Graphics/Graphics.h @@ -5,13 +5,15 @@ #include "canvas.h" #include "color.h" -#include "FontData.h" -#include "Font.h" #include "Shapes.h" #include "texture.h" #include "Shader.h" #include "window.h" #include "Bitmap.h" +#include "./Font/TTF.h" +#include "./Font/Text.h" +#include "./Font/TextureFont.h" + #endif // LIBJIN_MODULES_RENDER #endif // __LIBJIN_GRAPHICS_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Image.cpp b/src/libjin/Graphics/Image.cpp new file mode 100644 index 0000000..6203395 --- /dev/null +++ b/src/libjin/Graphics/Image.cpp @@ -0,0 +1,34 @@ +#include "../3rdparty/stb/stb_image.h" +#include "Image.h" + +namespace jin +{ +namespace graphics +{ + + /*static*/ Image* Image::createImage(const void* imgData, size_t size) + { + if (imgData == nullptr) + return nullptr; + int w, h; + void* data = stbi_load_from_memory((unsigned char *)imgData, size, &w, &h, NULL, STBI_rgb_alpha); + if (data == nullptr) + return nullptr; + Image* image = new Image(); + image->pixels = (Color*)data; + image->width = w; + image->height = h; + return image; + } + + Image::Image() + : Bitmap() + { + } + + Image::~Image() + { + } + +} +} diff --git a/src/libjin/Graphics/Image.h b/src/libjin/Graphics/Image.h new file mode 100644 index 0000000..5c426dc --- /dev/null +++ b/src/libjin/Graphics/Image.h @@ -0,0 +1,33 @@ +#ifndef __LIBJIN_IMAGE_H +#define __LIBJIN_IMAGE_H + +#include "Bitmap.h" + +namespace jin +{ +namespace graphics +{ + + /* just like bitmap but only from image file*/ + class Image : public Bitmap + { + public: + static Image* createImage(const void* imgData, size_t size); + ~Image(); + + private: + Image(); + + void bind(Color* pixels, int w, int h); + void resetPixels(const Color* pixels, int w, int h); + void resetPixels(const Color& pixels, int w, int h); + void setPixel(const Color& pixel, int x, int y); + void setPixels(Color pixels); + void setPixels(Color* pixels); + + }; + +} +} + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Particles/Particle.cpp b/src/libjin/Graphics/Particles/Particle.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/libjin/Graphics/Particles/Particle.cpp diff --git a/src/libjin/Graphics/Particles/Particle.h b/src/libjin/Graphics/Particles/Particle.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/libjin/Graphics/Particles/Particle.h diff --git a/src/libjin/Graphics/Shaders/base.shader.h b/src/libjin/Graphics/Shaders/base.shader.h index bf41c4f..45b63cd 100644 --- a/src/libjin/Graphics/Shaders/base.shader.h +++ b/src/libjin/Graphics/Shaders/base.shader.h @@ -1,31 +1,5 @@ -#ifndef LIBJIN_BASE_SHADER_H -#define LIBJIN_BASE_SHADER_H -/* - * https://stackoverflow.com/questions/10868958/what-does-sampler2d-store - * The sampler2D is bound to a texture unit. The glUniform call binds it to texture - * unit zero. The glActiveTexture call is only needed if you are going to use multiple - * texture units (because GL_TEXTURE0 is the default anyway). -*/ -/* -#VERTEX_SHADER - -vertex vert(vertex v) -{ - return v; -} - -#END_VERTEX_SHADER - -#FRAGMENT_SHADER - -vec4 frag(vec4 color, Texture tex, vertex v) -{ - return Texel(tex, v.uv); -} - -#END_FRAGMENT_SHADER - -*/ +#ifndef __LIBJIN_BASE_SHADER_H +#define __LIBJIN_BASE_SHADER_H static const char* base_shared = R"( #define Number float diff --git a/src/libjin/Graphics/Sprite.cpp b/src/libjin/Graphics/Sprite.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/libjin/Graphics/Sprite.cpp diff --git a/src/libjin/Graphics/Sprite.h b/src/libjin/Graphics/Sprite.h new file mode 100644 index 0000000..acb8264 --- /dev/null +++ b/src/libjin/Graphics/Sprite.h @@ -0,0 +1,18 @@ +#ifndef __LIBJIN_IMAGE_H +#define __LIBJIN_IMAGE_H + +namespace jin +{ +namespace graphics +{ + + /* just like texture but with x,y */ + class Sprite + { + + }; + +} +} + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Texture.cpp b/src/libjin/Graphics/Texture.cpp index 5a39f77..a42e796 100644 --- a/src/libjin/Graphics/Texture.cpp +++ b/src/libjin/Graphics/Texture.cpp @@ -20,18 +20,8 @@ namespace graphics } Texture::Texture(const Bitmap* bitmap) - : Drawable(bitmap->getWidth(), bitmap->getHeight()) + : Drawable(bitmap) { - unsigned int w = size.w; - unsigned int h = size.h; - const Color* pixels = bitmap->getPixels(); - - texture = gl.genTexture(); - gl.bindTexture(texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl.texImage(GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - gl.bindTexture(0); } Texture::~Texture() diff --git a/src/libjin/Graphics/Utf8.cpp b/src/libjin/Graphics/Utf8.cpp deleted file mode 100644 index 1a79d43..0000000 --- a/src/libjin/Graphics/Utf8.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include "Utf8.h" - -namespace jin -{ -namespace graphics -{ - - /* utf8 byte string to unicode codepoint */ - static const char *utf8toCodepoint(const char *p, unsigned *res) { - unsigned x, mask, shift; - switch (*p & 0xf0) { - case 0xf0: mask = 0x07; shift = 18; break; - case 0xe0: mask = 0x0f; shift = 12; break; - case 0xc0: - case 0xd0: mask = 0x1f; shift = 6; break; - default: - *res = *p; - return p + 1; - } - x = (*p & mask) << shift; - do { - if (*(++p) == '\0') { - *res = x; - return p; - } - shift -= 6; - x |= (*p & 0x3f) << shift; - } while (shift); - *res = x; - return p + 1; - } - - Utf8::Utf8(const char* raw, unsigned int length) - { - _length = length; - _raw = (char*)calloc(1, length); - memcpy(_raw, raw, length); - } - - Utf8::Iterator Utf8::getIterator() - { - return Iterator(*this); - } - - Utf8::~Utf8() - { - free(_raw); - _raw = nullptr; - _length = 0; - } - - Utf8::Iterator::Iterator(const Utf8& utf8) - : _utf8(utf8) - { - _p = utf8._raw; - } - - Codepoint Utf8::Iterator::get() - { - Codepoint c; - _p = utf8toCodepoint(_p, &c); - return c; - } - -} -}
\ No newline at end of file diff --git a/src/libjin/Graphics/Utf8.h b/src/libjin/Graphics/Utf8.h deleted file mode 100644 index d2d11fb..0000000 --- a/src/libjin/Graphics/Utf8.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __LIBJIN_UTF8_H -#define __LIBJIN_UTF8_H - -namespace jin -{ -namespace graphics -{ - - typedef unsigned int Codepoint; - - class Utf8 - { - public: - class Iterator - { - public: - /* unicode codepoint */ - Codepoint get(); - - private: - friend class Utf8; - Iterator(const Utf8&); - - const char* _p; - const Utf8& _utf8; - }; - - /* rawıսij */ - Utf8(const char* raw, unsigned int length); - Iterator getIterator(); - - private: - friend class Utf8::Iterator; - ~Utf8(); - - char* _raw; - unsigned int _length; - - }; - -} -} - -#endif
\ No newline at end of file diff --git a/src/libjin/Math/Vector2.hpp b/src/libjin/Math/Vector2.hpp index bee22f3..ddb8221 100644 --- a/src/libjin/Math/Vector2.hpp +++ b/src/libjin/Math/Vector2.hpp @@ -26,8 +26,9 @@ namespace math } T &x = data[0], &y = data[1]; // xy - T &w = data[0], &h = data[1]; // wh - + T &w = data[0], &h = data[1]; // wh + T &colum = data[0], &row = data[1]; // colum row + private: T data[2]; diff --git a/src/libjin/Math/Vector4.hpp b/src/libjin/Math/Vector4.hpp index c7dfaa8..da4110f 100644 --- a/src/libjin/Math/Vector4.hpp +++ b/src/libjin/Math/Vector4.hpp @@ -32,6 +32,7 @@ namespace math T &x = data[0], &y = data[1], &z = data[2], &t = data[3]; // xyzt T &w = data[2], &h = data[3]; // xywh T &r = data[0], &g = data[1], &b = data[2], &a = data[3]; // rgb + T &left = data[0], &right = data[1], &top = data[2], &bottom = data[3]; // lrtb private: T data[4]; |