diff --git a/src/dawn/asset/assets/NewTrueTypeAsset.hpp b/src/dawn/asset/assets/NewTrueTypeAsset.hpp index efb958a3..e7b3201f 100644 --- a/src/dawn/asset/assets/NewTrueTypeAsset.hpp +++ b/src/dawn/asset/assets/NewTrueTypeAsset.hpp @@ -34,7 +34,6 @@ namespace Dawn { FT_Library fontLibrary; enum NewTrueTypeAssetState state = NEW_TRUE_TYPE_ASSET_STATE_INITIAL; std::vector assetStyles; - std::vector textures; std::map textureByLock; std::map textureByStyle; @@ -44,8 +43,28 @@ namespace Dawn { void updateSync() override; void updateAsync() override; + /** + * Create a lock for a specific style. Locks will ensure that the font is + * held loaded until it is no longer required. + * + * @param style Style to lock. + * @return A unique lock ID for this style. + */ usagelockid_t lock(struct NewTrueTypeFaceTextureStyle style); + + /** + * Get a texture by a previous lock ID. + * + * @param lock Lock to get the texture of. + * @return Matching texture by this ID. + */ NewTrueTypeFaceTexture * getTexture(usagelockid_t lock); + + /** + * Releases a previously held font lock. + * + * @param lock Lock to release/unlock. + */ void unlock(usagelockid_t lock); ~NewTrueTypeAsset(); diff --git a/src/dawn/scene/components/ui/UILabelNew.cpp b/src/dawn/scene/components/ui/UILabelNew.cpp index 33df66c6..edbf14f8 100644 --- a/src/dawn/scene/components/ui/UILabelNew.cpp +++ b/src/dawn/scene/components/ui/UILabelNew.cpp @@ -9,82 +9,147 @@ using namespace Dawn; UILabelNew::UILabelNew(SceneItem *item) : - UIComponentRenderable(item), - font(nullptr), - fontSize(16), - style(0) + UIComponentRenderable(item) { } -void UILabelNew::rebufferQuads() { +void UILabelNew::rebufferQuads(std::vector texts) { std::cout << "Rebuffering" << std::endl; - this->mesh.createBuffers(QUAD_VERTICE_COUNT * 128, QUAD_INDICE_COUNT * 128); + auto oldTexts = this->texts; + textureMap.clear(); glm::vec2 position(32, 32); - struct FontShaderBufferData fontData; - auto x = this->bufferQuads( - "Hello World", - fontData, - this->font->getTexture(this->fontLock), - position, - 0, - 0 + int32_t quadIndex = 0; + int32_t partIndex = 0; + int32_t quadCount = 0; + int32_t nextTexture = 0; + + // Determine how many quads there are, and the texture indexes. + auto itText = texts.begin(); + while(itText != texts.end()) { + quadCount += itText->text.length(); + + // Determine font and lock it. + assertNotNull(itText->font); + itText->lockId = itText->font->lock(NewTrueTypeFaceTextureStyle{ + itText->size, + itText->style + }); + assertTrue(itText->lockId != -1); + itText->texture = itText->font->getTexture(itText->lockId); + + // Check for existing texture, if not, map it. + if(textureMap.find(itText->texture) == textureMap.end()) { + assertTrue(nextTexture < FONT_SHADER_TEXTURE_MAX); + textureMap[itText->texture] = nextTexture++; + } + + ++itText; + } + + // Cleanup old texst, we do this second so we don't unlock, cleanup, and then + // lock the same font, causing it to have to re-load. + itText = oldTexts.begin(); + while(itText != oldTexts.end()) { + assertTrue(itText->lockId != -1); + assertNotNull(itText->font); + itText->font->unlock(itText->lockId); + ++itText; + } + + // Update texts. + this->texts = texts; + + // Create mesh + this->mesh.createBuffers( + QUAD_VERTICE_COUNT * quadCount, + QUAD_INDICE_COUNT * quadCount ); - fontData.colors[0] = COLOR_MAGENTA; - fontData.textures[0] = 0; - // fontData.colors[1] = COLOR_RED; - // fontData.textures[1] = 1; - // fontData.colors[2] = COLOR_GREEN; - // fontData.textures[2] = 2; + // Buffer the text quads + itText = texts.begin(); + while(itText != texts.end()) { + quadIndex += this->bufferQuads( + *itText, + fontData, + textureMap, + position, + quadIndex, + partIndex + ); + partIndex++; + ++itText; + } + shaderBuffer.buffer(&fontData); } void UILabelNew::onStart() { this->shaderBuffer.init(); - useEffect([&]{ - usagelockid_t newLock = -1; + auto font = this->getGame()->assetManager.get("font_arial"); - if(font != nullptr) { - newLock = font->lock(NewTrueTypeFaceTextureStyle{ - fontSize, - style - }); - } + std::vector texts; + texts.push_back({ + .text = "Hello", + .color = COLOR_RED, + .style = 0, + .size = 16, + .font = font + }); + texts.push_back({ + .text = " World", + .color = COLOR_BLUE, + .style = 1, + .size = 32, + .font = font + }); + this->rebufferQuads(texts); - if(fontLock != -1) { - font.previous->unlock(fontLock); - fontLock = -1; - } + // this->texts.clear(); - if(font == nullptr) return; + // useEffect([&]{ + // usagelockid_t newLock = -1; - fontLock = newLock; - this->rebufferQuads(); - }, font)(); + // if(font != nullptr) { + // newLock = font->lock(NewTrueTypeFaceTextureStyle{ + // fontSize, + // style + // }); + // } - useEffect([&]{ - if(font == nullptr) return; - auto newLock = font->lock(NewTrueTypeFaceTextureStyle{ - fontSize, - style - }); + // if(fontLock != -1) { + // font.previous->unlock(fontLock); + // fontLock = -1; + // } - if(fontLock != -1) { - font->unlock(fontLock); - fontLock = -1; - } + // if(font == nullptr) return; - fontLock = newLock; - this->rebufferQuads(); - }, { &fontSize, &style })(); + // fontLock = newLock; + // this->rebufferQuads(); + // }, font)(); + + // useEffect([&]{ + // if(font == nullptr) return; + // auto newLock = font->lock(NewTrueTypeFaceTextureStyle{ + // fontSize, + // style + // }); + + // if(fontLock != -1) { + // font->unlock(fontLock); + // fontLock = -1; + // } + + // fontLock = newLock; + // this->rebufferQuads(); + // }, { &fontSize, &style })(); } std::vector UILabelNew::getUIRenderPasses() { - if(this->fontLock == -1) return {}; + if(this->texts.size() == 0) return {}; auto canvas = this->getCanvas(); auto shader = getGame()->renderManager.fontShader; @@ -97,17 +162,40 @@ std::vector UILabelNew::getUIRenderPasses() { item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer; item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND; - item.textureSlots[0] = &this->font->getTexture(this->fontLock)->texture; - item.textureValues[shader->paramTexture0] = 0; - // item.textureSlots[1] = &defFaceItalics.texture; - // item.textureSlots[2] = &defFaceBold.texture; - // item.textureValues[shader->paramTexture1] = 1; - // item.textureValues[shader->paramTexture2] = 2; + // Map texture slots + auto it = textureMap.begin(); + while(it != textureMap.end()) { + item.textureSlots[it->second] = &it->first->texture; + + shaderparameter_t param = FONT_SHADER_TEXTURE_MAX; + switch(it->second) { + case 0: + param = shader->paramTexture0; + break; + + case 1: + param = shader->paramTexture1; + break; + + case 2: + param = shader->paramTexture2; + break; + + case 3: + param = shader->paramTexture3; + break; + + default: + break; + } + assertTrue(param >= 0 && param < FONT_SHADER_TEXTURE_MAX); + item.textureValues[param] = it->second; + ++it; + } return { item }; } - float_t UILabelNew::getWidth() { return 0; } @@ -125,24 +213,27 @@ float_t UILabelNew::getContentHeight() { } int32_t UILabelNew::bufferQuads( - std::string text, + struct UILabelText text, struct FontShaderBufferData &bufferData, - struct NewTrueTypeFaceTexture *texture, + std::map &textureMap, glm::vec2 &position, int32_t quadStart, int32_t partIndex ) { // Get string length - int32_t len = text.length(); + int32_t len = text.text.length(); - glm::vec2 wh = glm::vec2(texture->texture.getWidth(), texture->texture.getHeight()); + glm::vec2 wh = glm::vec2( + text.texture->texture.getWidth(), + text.texture->texture.getHeight() + ); // For each char for(int32_t i = 0; i < len; i++) { - char ch = text[i]; + char ch = text.text[i]; int32_t j = quadStart + i; FT_ULong c = ch; - auto charInfo = texture->getCharacterData(c); + auto charInfo = text.texture->getCharacterData(c); // Determine texture coordinates. glm::vec2 uv0 = glm::vec2(0.0f, charInfo.textureY) / wh; @@ -164,5 +255,12 @@ int32_t UILabelNew::bufferQuads( bufferData.fontQuadMappings[j] = partIndex; } + // Map texture level values + bufferData.colors[partIndex] = text.color; + + auto textureId = textureMap.find(text.texture); + assertTrue(textureId != textureMap.end()); + bufferData.textures[partIndex] = textureId->second; + return len; } \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UILabelNew.hpp b/src/dawn/scene/components/ui/UILabelNew.hpp index 6b5561c7..1d5f8032 100644 --- a/src/dawn/scene/components/ui/UILabelNew.hpp +++ b/src/dawn/scene/components/ui/UILabelNew.hpp @@ -9,54 +9,53 @@ #include "asset/assets/NewTrueTypeAsset.hpp" namespace Dawn { - struct UILabelStyle { - struct Color; - // UILabelFontDef *fontDef; + struct UILabelText { + std::string text; + struct Color color = COLOR_MAGENTA; + flag_t style = 0; + uint32_t size = 16; + NewTrueTypeAsset *font = nullptr; + + // Part index + // Quad start + // position + // size + // some kind of custom data e.g. wobble or shake? + + usagelockid_t lockId = -1; + struct NewTrueTypeFaceTexture *texture = nullptr; }; class UILabelNew : public UIComponentRenderable { private: Mesh mesh; FontShaderBuffer shaderBuffer; - - usagelockid_t fontLock = -1; - - // FT_Face face; - // FT_Face faceBold; - // FT_Face faceItalics; - - // struct UILabelFontDef defFace; - // struct UILabelFontDef defFaceBold; - // struct UILabelFontDef defFaceItalics; + std::vector texts; + std::map textureMap; /** * Buffers the quads for the given text and updates the progressing values * as the buffer process continues. * - * @param text Text to buffer. + * @param text Text information to buffer. * @param bufferData The output quad mappings for the text. - * @param texture The font texture definition to use. + * @param textureMap Texture map for the textures to map. * @param position The 2D position to buffer the quads at. * @param quadStart The starting quad index. * @param partIndex The part index to store for each quad buffered. * @return The number of quads buffered, not the string length. */ int32_t bufferQuads( - std::string text, + struct UILabelText text, struct FontShaderBufferData &bufferData, - struct NewTrueTypeFaceTexture *texture, + std::map &textureMap, glm::vec2 &position, int32_t quadStart, int32_t partIndex ); - void rebufferQuads(); public: - StateProperty font; - StateProperty fontSize; - StateProperty style; - UILabelNew(SceneItem *item); void onStart() override; @@ -65,5 +64,7 @@ namespace Dawn { float_t getHeight() override; float_t getContentWidth() override; float_t getContentHeight() override; + + void rebufferQuads(std::vector texts); }; } \ No newline at end of file diff --git a/src/dawnliminal/scenes/HelloWorldScene.hpp b/src/dawnliminal/scenes/HelloWorldScene.hpp index 3aa6cda5..61f86e93 100644 --- a/src/dawnliminal/scenes/HelloWorldScene.hpp +++ b/src/dawnliminal/scenes/HelloWorldScene.hpp @@ -27,10 +27,6 @@ namespace Dawn { auto newLabelItem = this->createSceneItem(); newLabelItem->transform.setParent(canvas->transform); auto newLabel = newLabelItem->addComponent(); - - auto font = this->game->assetManager.get("font_arial"); - newLabel->font = font; - newLabel->fontSize = 32; } std::vector getRequiredAssets() override { diff --git a/src/dawnopengl/display/shader/shaders/FontShader.cpp b/src/dawnopengl/display/shader/shaders/FontShader.cpp index 10148dc8..66b7b165 100644 --- a/src/dawnopengl/display/shader/shaders/FontShader.cpp +++ b/src/dawnopengl/display/shader/shaders/FontShader.cpp @@ -54,6 +54,7 @@ void FontShader::compile() { "uniform sampler2D u_Text0;\n" "uniform sampler2D u_Text1;\n" "uniform sampler2D u_Text2;\n" + "uniform sampler2D u_Text3;\n" "void main() {\n" "o_Color = o_VertColor;\n" @@ -62,8 +63,10 @@ void FontShader::compile() { "tColor = texture(u_Text0, o_TextCoord);\n" "} else if(o_TextIndex == 1) \n{" "tColor = texture(u_Text1, o_TextCoord);\n" - "} else {\n" + "} else if(o_TextIndex == 2) \n{" "tColor = texture(u_Text2, o_TextCoord);\n" + "} else {\n" + "tColor = texture(u_Text3, o_TextCoord);\n" "}\n" "o_Color.a *= tColor.r;\n" "}\n" @@ -78,4 +81,5 @@ void FontShader::compile() { this->paramTexture0 = this->getParameterByName("u_Text0"); this->paramTexture1 = this->getParameterByName("u_Text1"); this->paramTexture2 = this->getParameterByName("u_Text2"); + this->paramTexture3 = this->getParameterByName("u_Text3"); } \ No newline at end of file diff --git a/src/dawnopengl/display/shader/shaders/FontShader.hpp b/src/dawnopengl/display/shader/shaders/FontShader.hpp index 80628b05..7f7e439e 100644 --- a/src/dawnopengl/display/shader/shaders/FontShader.hpp +++ b/src/dawnopengl/display/shader/shaders/FontShader.hpp @@ -9,7 +9,7 @@ #define FONT_SHADER_PARTS_MAX 4 #define FONT_SHADER_QUADS_MAX 32 -#define FONT_SHADER_TEXTURE_MAX 8 +#define FONT_SHADER_TEXTURE_MAX 4 namespace Dawn { // #pragma pack(push, 4) @@ -30,6 +30,7 @@ namespace Dawn { shaderparameter_t paramTexture0; shaderparameter_t paramTexture1; shaderparameter_t paramTexture2; + shaderparameter_t paramTexture3; shaderbufferlocation_t bufferUiCanvas; shaderbufferlocation_t bufferFont;