Dawn/src/dawn/scene/components/ui/text/UILabelNew.cpp

269 lines
6.8 KiB
C++

// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UILabelNew.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
UILabelNew::UILabelNew(SceneItem *item) :
UIComponentRenderable(item)
{
}
void UILabelNew::onStart() {
this->shaderBuffer.init();
std::vector<struct UILabelStyle> styleStack;
struct UILabelStyle current;
styleStack.push_back(current);
std::vector<struct UILabelText> texts;
std::function<void(Xml*)> parseChildren = [&](Xml *node) {
if(node->children.empty()) {
struct UILabelText text;
text.style = current;
text.text = node->value;
texts.push_back(text);
} else {
auto itNode = node->children.begin();
while(itNode != node->children.end()) {
auto child = *itNode;
assertTrue(child->node == "font");
struct UILabelStyle style;
if(child->attributes.contains("font")) {
style.font = this->getGame()->assetManager.get<NewTrueTypeAsset>(child->attributes["font"]);
} else {
style.font = current.font;
}
if(child->attributes.contains("size")) {
style.size = std::stoi(child->attributes["size"]);
} else {
style.size = current.size;
}
if(child->attributes.contains("style")) {
std::string s = child->attributes["style"];
style.style = 0;
if(s.find("bold") != std::string::npos) style.style |= NEW_TRUETYPE_VARIANT_BOLD;
if(s.find("italic") != std::string::npos) style.style |= NEW_TRUETYPE_VARIANT_ITALICS;
} else {
style.style = current.style;
}
if(child->attributes.contains("color")) {
style.color = Color::fromString(child->attributes["color"]);
} else {
style.color = current.color;
}
styleStack.push_back(style);
current = style;
parseChildren(child);
styleStack.pop_back();
current = styleStack.back();
++itNode;
}
}
};
auto root = Xml::load("<root>" + this->test + "</root>");
parseChildren(&root);
this->rebufferQuads(texts);
}
std::vector<struct ShaderPassItem> UILabelNew::getUIRenderPasses() {
// if(this->texts.size() == 0) return {};
auto canvas = this->getCanvas();
auto shader = getGame()->renderManager.fontShader;
struct ShaderPassItem item;
item.shader = shader;
item.mesh = &this->mesh;
item.matrixValues[shader->paramModel] = transform->getWorldTransform();
item.parameterBuffers[shader->bufferUiCanvas] = &canvas->shaderBuffer;
item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer;
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
// Map texture slots
auto it = textureMap.begin();
while(it != textureMap.end()) {
shaderparameter_t param;
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:
assertUnreachable();
}
item.textureSlots[it->second] = &it->first->texture;
item.textureValues[param] = it->second;
++it;
}
return { item };
}
float_t UILabelNew::getWidth() {
return 0;
}
float_t UILabelNew::getHeight() {
return 0;
}
float_t UILabelNew::getContentWidth() {
return 0;
}
float_t UILabelNew::getContentHeight() {
return 0;
}
void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
auto oldTexts = this->texts;
textureMap.clear();
glm::vec2 position(0, 0);
struct FontShaderBufferData fontData;
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->style.font);
itText->lockId = itText->style.font->lock(NewTrueTypeFaceTextureStyle{
itText->style.size,
itText->style.style
});
assertTrue(itText->lockId != -1);
itText->texture = itText->style.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++;
}
// Set initial line height
position.y = mathMax<float_t>(itText->style.size, position.y);
++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->style.font);
itText->style.font->unlock(itText->lockId);
++itText;
}
// Update texts.
this->texts = texts;
// Create mesh
this->mesh.createBuffers(
QUAD_VERTICE_COUNT * quadCount,
QUAD_INDICE_COUNT * quadCount
);
// 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);
}
int32_t UILabelNew::bufferQuads(
struct UILabelText text,
struct FontShaderBufferData &bufferData,
std::map<NewTrueTypeFaceTexture*, int32_t> &textureMap,
glm::vec2 &position,
int32_t quadStart,
int32_t partIndex
) {
// Get string length
int32_t len = text.text.length();
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.text[i];
int32_t j = quadStart + i;
FT_ULong c = ch;
auto charInfo = text.texture->getCharacterData(c);
// Determine texture coordinates.
glm::vec2 uv0 = glm::vec2(0.0f, charInfo.textureY) / wh;
glm::vec2 uv1 = uv0 + (charInfo.bitmapSize / wh);
// Buffer the quad.
QuadMesh::bufferQuadMeshWithZ(&this->mesh,
position + charInfo.bitmapPosition, uv0,
position + charInfo.bitmapPosition + charInfo.bitmapSize, uv1,
0.0f,
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
);
// Move the current position along.
position.x += charInfo.advanceX;
position.y += charInfo.advanceY;
// Set the part index to the quad mappings
bufferData.fontQuadMappings[j] = partIndex;
}
// Map texture level values
auto textureId = textureMap.find(text.texture);
assertTrue(textureId != textureMap.end());
bufferData.textures[partIndex] = textureId->second;
bufferData.colors[partIndex] = text.style.color;
return len;
}