diff options
author | chai <chaifix@163.com> | 2021-11-03 09:52:26 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-11-03 09:52:26 +0800 |
commit | c10e0d92f46e5eaf25a69e1fafe5f4dbd8eaab9d (patch) | |
tree | 2eb1a91339b35fea68f48b2774355f496519db83 /Runtime/GUI/UITextMesh.cpp | |
parent | 3898f2c648b1a731dead8337aad8912d2b8b80d7 (diff) |
*misc
Diffstat (limited to 'Runtime/GUI/UITextMesh.cpp')
-rw-r--r-- | Runtime/GUI/UITextMesh.cpp | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/Runtime/GUI/UITextMesh.cpp b/Runtime/GUI/UITextMesh.cpp new file mode 100644 index 0000000..6a10f88 --- /dev/null +++ b/Runtime/GUI/UITextMesh.cpp @@ -0,0 +1,175 @@ +#include "../Graphics/CustomVertexLayout.h" +#include "Runtime/Utilities/StaticInitiator.h" +#include "../Math/Math.h" +#include "../Graphics/Color.h" +#include "UITextMesh.h" +#include "../Graphics/DefaultVertexLayout.h" +#include "Runtime/Debug/Log.h" +#include <vector> +#include <unordered_map> +#include "Runtime/Graphics/GfxDevice.h" + +using namespace std; + +struct TextMeshVBOLayout +{ + Vector2 position; + Vector2 uv; + Color32 color; +}; + +static CustomVertexLayout s_TextMeshVBOLayout; + +static unsigned int s_VertexPerText; +static unsigned int s_SizePerVertex; +static unsigned int s_SizePerText; +static unsigned int s_SizePerIndex; +static unsigned int s_IndicesPerText; + +struct TextInfo { + const Character* ch; + float offset; +}; + +static unordered_map<unsigned int, vector<TextInfo>> s_TextInfos; + +InitializeStaticVariables([]() { + VertexAttributeDescriptor POSITION = VertexAttributeDescriptor(0, 2, VertexAttrFormat_Float, sizeof(TextMeshVBOLayout)); + VertexAttributeDescriptor UV = VertexAttributeDescriptor(sizeof(Vector2), 2, VertexAttrFormat_Float, sizeof(TextMeshVBOLayout)); + VertexAttributeDescriptor COLOR = VertexAttributeDescriptor(sizeof(Vector2)*2, 4, VertexAttrFormat_Unsigned_Byte, sizeof(TextMeshVBOLayout), true); + s_TextMeshVBOLayout.attributes.push_back(POSITION); + s_TextMeshVBOLayout.attributes.push_back(UV); + s_TextMeshVBOLayout.attributes.push_back(COLOR); + + s_VertexPerText = 4; + s_SizePerVertex = sizeof(TextMeshVBOLayout); + + s_IndicesPerText = 6; + s_SizePerIndex = VertexLayout::GetDefaultIndexSize(); + + s_SizePerText = sizeof(TextMeshVBOLayout) * 4; +}); + +// 一段文字里面的网格可能会来自不同的atlas,在生成UITextMesh时做好合批 + +// 需要支持 +// * 大小 +// * 锚点 +// * 对齐方式 +// * 换行 +// * 颜色 + +UITextMesh::UITextMesh(const UnicodeString& str, Font* font,int pixelSize, ETextAnchor anchor, ETextAlignment alignment) +{ + m_Font = font; + s_TextInfos.clear(); + const Vector2 atlasSize = font->GetAtlasSize(); + + // 按照不同的atlas分类到s_TextInfos + float offset = 0; + for (int i = 0; i < str.length; ++i) + { + character::Codepoint c = str.str[i]; + const Character* ch = font->GetCharacter(c, pixelSize); + unsigned int atlasIndex = ch->atlas; + + TextInfo info; + info.ch = ch; + info.offset = offset; + + auto list = s_TextInfos.find(atlasIndex); + if (list == s_TextInfos.end()) + s_TextInfos.insert(std::pair<unsigned int, vector<TextInfo>>(atlasIndex, vector<TextInfo>())); + + vector<TextInfo>& v = s_TextInfos[atlasIndex]; + v.push_back(info); + + offset += ch->advance; + } + + if (s_TextInfos.size() == 0) + return; + + // 填充VBO和IBO + for (auto iter : s_TextInfos) { + unsigned int atlasIndex = iter.first; // atlas atlasIndex + vector<TextInfo>& texts = iter.second; + int textCount = texts.size(); + + VertexBuffer* vb = new VertexBuffer(textCount * s_SizePerText, textCount * s_IndicesPerText * s_SizePerIndex, VertexBuffer::VertexBufferType_Static); + void* pVB; + uint16* pIB; + + vb->GetChunk(s_SizePerVertex, s_SizePerIndex, s_VertexPerText * textCount, s_IndicesPerText * textCount, EPrimitive::Primitive_Triangle, &pVB,(void**) &pIB); + + TextMeshVBOLayout* dst = (TextMeshVBOLayout*)pVB; + for (int i = 0; i < textCount; ++i) + { + TextInfo& text = texts[i]; + + int vOff = i * s_VertexPerText; + // 左上角是原点 + float pos[] = { + text.offset + text.ch->bearing.x, pixelSize - text.ch->bearing.y + text.ch->position.height, // bottom-left + text.offset + text.ch->bearing.x + text.ch->position.width, pixelSize - text.ch->bearing.y + text.ch->position.height, // bottom-right + text.offset + text.ch->bearing.x + text.ch->position.width, pixelSize - text.ch->bearing.y, // top-right + text.offset + text.ch->bearing.x, pixelSize - text.ch->bearing.y, // top-left + }; + Vector4 uvQuad = Vector4(text.ch->position.x / atlasSize.x, text.ch->position.y / atlasSize.y, text.ch->position.width / atlasSize.x, text.ch->position.height / atlasSize.y); + float uv[] = { + uvQuad.x, uvQuad.y + uvQuad.w, + uvQuad.x + uvQuad.z, uvQuad.y + uvQuad.w, + uvQuad.x + uvQuad.z, uvQuad.y, + uvQuad.x, uvQuad.y, + }; + for (int j = 0; j < s_VertexPerText; ++j) + { + dst[vOff + j].position.Set(pos[2 * j], pos[2 * j + 1]); + dst[vOff + j].uv.Set(uv[2 * j], uv[2 * j + 1]); + dst[vOff + j].color.Set(255 , 255, 255, 255); + } + + int iOff = i * s_IndicesPerText; + int indices[] = { + 0, 1, 3, // right-top + 1, 2, 3, // left-bottom + }; + for (int j = 0; j < s_IndicesPerText; ++j) + pIB[iOff + j] = vOff + indices[j]; + } + + vb->FlushChunk(s_VertexPerText * textCount, s_IndicesPerText * textCount); + + m_VBOs.insert(std::pair<int, VertexBuffer*>(atlasIndex, vb)); + } + + WipeGLError(); +} + +void UITextMesh::Draw() +{ + for (auto subText : m_VBOs) + { + int atlasIndex = subText.first; // atlasIndex of atlas + VertexBuffer* vbo = subText.second; + + const GlyphAtals* atlas = m_Font->GetGlyphAtlas(atlasIndex); + if (atlas == NULL) + { + log_error("Render text failed, no glyph atlas."); + continue; + } + + g_GfxDevice.SetUniformTexture("gamelab_main_tex", atlas->altas); + + CheckGLError( + throw GLException(error); + ); + vbo->Draw(s_TextMeshVBOLayout); + + CheckGLError( + throw GLException(error); + ); + g_GfxDevice.ResetUniformsState(); + } +} |