diff options
Diffstat (limited to 'Runtime/GUI/TextMesh.cpp')
-rw-r--r-- | Runtime/GUI/TextMesh.cpp | 104 |
1 files changed, 90 insertions, 14 deletions
diff --git a/Runtime/GUI/TextMesh.cpp b/Runtime/GUI/TextMesh.cpp index 6f3b3d6..de9a195 100644 --- a/Runtime/GUI/TextMesh.cpp +++ b/Runtime/GUI/TextMesh.cpp @@ -3,8 +3,11 @@ #include "../Math/Math.h" #include "../Graphics/Color.h" #include "TextMesh.h" +#include "../Graphics/DefaultVertexLayout.h" +#include "Runtime/Debug/Log.h" #include <vector> #include <unordered_map> +#include "Runtime/Graphics/GfxDevice.h" using namespace std; @@ -20,6 +23,7 @@ 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 { @@ -39,33 +43,36 @@ InitializeStaticVariables([]() { s_VertexPerText = 4; s_SizePerVertex = sizeof(TextMeshVBOLayout); + + s_IndicesPerText = 6; + s_SizePerIndex = VertexLayout::GetDefaultIndexSize(); + s_SizePerText = sizeof(TextMeshVBOLayout) * 4; - s_IndicesPerText = 6; }); TextMesh::TextMesh(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 index = ch->atlas; + unsigned int atlasIndex = ch->atlas; TextInfo info; info.ch = ch; info.offset = offset; - auto list = s_TextInfos.find(index); + auto list = s_TextInfos.find(atlasIndex); if (list == s_TextInfos.end()) - { - s_TextInfos.insert(std::pair<unsigned int, vector<TextInfo>>(index, vector<TextInfo>())); - list = s_TextInfos.find(index); - } - vector<TextInfo>& v = list->second; + 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; @@ -74,17 +81,86 @@ TextMesh::TextMesh(const UnicodeString& str, Font* font,int pixelSize, ETextAnch if (s_TextInfos.size() == 0) return; + // 填充VBO和IBO for (auto iter : s_TextInfos) { - unsigned int index = iter.first; + unsigned int atlasIndex = iter.first; // atlas atlasIndex vector<TextInfo>& texts = iter.second; - int count = texts.size(); - - VertexBuffer* vb = new VertexBuffer(count * s_SizePerText, count * s_IndicesPerText, VertexBuffer::VertexBufferType_Static); - + 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, text.ch->bearing.y - text.ch->position.height, // bottom-left + text.offset + text.ch->bearing.x + text.ch->position.width, text.ch->bearing.y - text.ch->position.height, // bottom-right + text.offset + text.ch->bearing.x + text.ch->position.width, text.ch->bearing.y, // top-right + text.offset + text.ch->bearing.x, text.ch->bearing.y, // top-left + }; + // 左上角为UV原点,所以在shader里采样的时候要镜像y + 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 TextMesh::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(); + } } |