summaryrefslogtreecommitdiff
path: root/Runtime/GUI/UITextMesh.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-11-03 09:52:26 +0800
committerchai <chaifix@163.com>2021-11-03 09:52:26 +0800
commitc10e0d92f46e5eaf25a69e1fafe5f4dbd8eaab9d (patch)
tree2eb1a91339b35fea68f48b2774355f496519db83 /Runtime/GUI/UITextMesh.cpp
parent3898f2c648b1a731dead8337aad8912d2b8b80d7 (diff)
*misc
Diffstat (limited to 'Runtime/GUI/UITextMesh.cpp')
-rw-r--r--Runtime/GUI/UITextMesh.cpp175
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();
+ }
+}