Progress untangle

This commit is contained in:
2023-06-14 21:14:52 -07:00
parent 29bb22b5d0
commit e978ae6e66
10 changed files with 191 additions and 106 deletions

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "scene/SceneItemComponent.hpp" #include "scene/SceneItemComponent.hpp"
#include "scene/components/ui/text/UILabelNew.hpp" #include "scene/components/ui/text/UILabel.hpp"
#include "input/InputManager.hpp" #include "input/InputManager.hpp"
#define VN_TEXTBOX_SPEED 25.0f #define VN_TEXTBOX_SPEED 25.0f
@ -15,7 +15,7 @@ namespace Dawn {
class VNTextboxScroller : public SceneItemComponent { class VNTextboxScroller : public SceneItemComponent {
public: public:
// @optional // @optional
StateProperty<UILabelNew*> label; StateProperty<UILabel*> label;
StateEvent<> eventReadyToClose; StateEvent<> eventReadyToClose;
StateEvent<> eventCharacterRevealed; StateEvent<> eventCharacterRevealed;

View File

@ -4,13 +4,13 @@
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "scene/components/ui/text/UILabelNew.hpp" #include "scene/components/ui/text/UILabel.hpp"
namespace Dawn { namespace Dawn {
class FPSLabelComponent : public SceneItemComponent { class FPSLabelComponent : public SceneItemComponent {
public: public:
/* @optional */ /* @optional */
UILabelNew *label = nullptr; UILabel *label = nullptr;
FPSLabelComponent(SceneItem *item); FPSLabelComponent(SceneItem *item);
void onStart() override; void onStart() override;

View File

@ -40,7 +40,7 @@ namespace Dawn {
/** /**
* Internal method to update the alignment of this item. * Internal method to update the alignment of this item.
*/ */
void updateAlignment(); virtual void updateAlignment();
public: public:
StateProperty<bool_t> alignmentNeedsUpdating; StateProperty<bool_t> alignmentNeedsUpdating;

View File

@ -1,4 +1,4 @@
# Copyright (c) 2022 Dominic Masters # Copyright (c) 2023 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
@ -6,5 +6,6 @@
# Sources # Sources
target_sources(${DAWN_TARGET_NAME} target_sources(${DAWN_TARGET_NAME}
PRIVATE PRIVATE
UILabelNew.cpp UILabel.cpp
UIRichTextLabel.cpp
) )

View File

@ -3,83 +3,22 @@
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "UILabelNew.hpp" #include "UILabel.hpp"
#include "game/DawnGame.hpp" #include "game/DawnGame.hpp"
using namespace Dawn; using namespace Dawn;
UILabelNew::UILabelNew(SceneItem *item) : UILabel::UILabel(SceneItem *item) :
UIComponentRenderable(item) UIComponentRenderable(item)
{ {
} }
void UILabelNew::onStart() { void UILabel::onStart() {
this->shaderBuffer.init(); 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() { std::vector<struct ShaderPassItem> UILabel::getUIRenderPasses() {
// if(this->texts.size() == 0) return {}; // if(this->texts.size() == 0) return {};
auto canvas = this->getCanvas(); auto canvas = this->getCanvas();
@ -92,6 +31,8 @@ std::vector<struct ShaderPassItem> UILabelNew::getUIRenderPasses() {
item.parameterBuffers[shader->bufferUiCanvas] = &canvas->shaderBuffer; item.parameterBuffers[shader->bufferUiCanvas] = &canvas->shaderBuffer;
item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer; item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer;
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND; item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
item.start = quadStart * QUAD_VERTICE_COUNT;
item.count = quadCount == -1 ? -1 : quadCount * QUAD_VERTICE_COUNT;
// Map texture slots // Map texture slots
auto it = textureMap.begin(); auto it = textureMap.begin();
@ -126,23 +67,15 @@ std::vector<struct ShaderPassItem> UILabelNew::getUIRenderPasses() {
return { item }; return { item };
} }
float_t UILabelNew::getWidth() { float_t UILabel::getContentWidth() {
return 0; return 0;
} }
float_t UILabelNew::getHeight() { float_t UILabel::getContentHeight() {
return 0; return 0;
} }
float_t UILabelNew::getContentWidth() { void UILabel::rebufferQuads(std::vector<struct UILabelText> newTexts) {
return 0;
}
float_t UILabelNew::getContentHeight() {
return 0;
}
void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
auto oldTexts = this->texts; auto oldTexts = this->texts;
textureMap.clear(); textureMap.clear();
@ -150,13 +83,13 @@ void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
struct FontShaderBufferData fontData; struct FontShaderBufferData fontData;
int32_t quadIndex = 0; int32_t quadIndex = 0;
int32_t partIndex = 0; int32_t partIndex = 0;
int32_t quadCount = 0; quadCountTotal = 0;
int32_t nextTexture = 0; int32_t nextTexture = 0;
// Determine how many quads there are, and the texture indexes. // Determine how many quads there are, and the texture indexes.
auto itText = texts.begin(); auto itText = newTexts.begin();
while(itText != texts.end()) { while(itText != newTexts.end()) {
quadCount += itText->text.length(); quadCountTotal += itText->text.length();
// Determine font and lock it. // Determine font and lock it.
assertNotNull(itText->style.font); assertNotNull(itText->style.font);
@ -172,9 +105,6 @@ void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
assertTrue(nextTexture < FONT_SHADER_TEXTURE_MAX); assertTrue(nextTexture < FONT_SHADER_TEXTURE_MAX);
textureMap[itText->texture] = nextTexture++; textureMap[itText->texture] = nextTexture++;
} }
// Set initial line height
position.y = mathMax<float_t>(itText->style.size, position.y);
++itText; ++itText;
} }
@ -190,17 +120,18 @@ void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
} }
// Update texts. // Update texts.
this->texts = texts; this->texts = newTexts;
// Create mesh // Create mesh
this->mesh.createBuffers( this->mesh.createBuffers(
QUAD_VERTICE_COUNT * quadCount, QUAD_VERTICE_COUNT * quadCountTotal,
QUAD_INDICE_COUNT * quadCount QUAD_INDICE_COUNT * quadCountTotal
); );
// Buffer the text quads // Buffer the text quads
itText = texts.begin(); itText = newTexts.begin();
while(itText != texts.end()) { while(itText != newTexts.end()) {
position.y += itText->style.size;
quadIndex += this->bufferQuads( quadIndex += this->bufferQuads(
*itText, *itText,
fontData, fontData,
@ -209,6 +140,7 @@ void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
quadIndex, quadIndex,
partIndex partIndex
); );
// position.y -= itText->style.size;
++partIndex; ++partIndex;
++itText; ++itText;
} }
@ -216,7 +148,7 @@ void UILabelNew::rebufferQuads(std::vector<struct UILabelText> texts) {
shaderBuffer.buffer(&fontData); shaderBuffer.buffer(&fontData);
} }
int32_t UILabelNew::bufferQuads( int32_t UILabel::bufferQuads(
struct UILabelText text, struct UILabelText text,
struct FontShaderBufferData &bufferData, struct FontShaderBufferData &bufferData,
std::map<NewTrueTypeFaceTexture*, int32_t> &textureMap, std::map<NewTrueTypeFaceTexture*, int32_t> &textureMap,
@ -233,17 +165,46 @@ int32_t UILabelNew::bufferQuads(
); );
// For each char // For each char
int32_t lastSpaceCharacter = -1;
for(int32_t i = 0; i < len; i++) { for(int32_t i = 0; i < len; i++) {
char ch = text.text[i]; char ch = text.text[i];
if(ch == '\n') {
position.x = 0;
position.y += text.style.size;
ch = ' ';
lastSpaceCharacter = i;
} else if(ch == ' ') {
lastSpaceCharacter = i;
}
// Invalid/Unsupported chars
assertTrue(ch >= NEW_TRUETYPE_CHAR_BEGIN && ch < NEW_TRUETYPE_CHAR_END);
assertTrue(ch != '\r');
assertTrue(ch != '\t');
int32_t j = quadStart + i; int32_t j = quadStart + i;
FT_ULong c = ch; FT_ULong c = ch;
auto charInfo = text.texture->getCharacterData(c); auto charInfo = text.texture->getCharacterData(c);
// Word wrapping
if(
lastSpaceCharacter != -1 &&
this->width > 0 &&
(position.x+charInfo.advanceX) > this->width
) {
text.text[lastSpaceCharacter] = '\n';
i = lastSpaceCharacter - 1;
lastSpaceCharacter = -1;
continue;
}
// Determine texture coordinates. // Determine texture coordinates.
glm::vec2 uv0 = glm::vec2(0.0f, charInfo.textureY) / wh; glm::vec2 uv0 = glm::vec2(0.0f, charInfo.textureY) / wh;
glm::vec2 uv1 = uv0 + (charInfo.bitmapSize / wh); glm::vec2 uv1 = uv0 + (charInfo.bitmapSize / wh);
// Buffer the quad. // Buffer the quad.
assertTrue(j < FONT_SHADER_QUADS_MAX);
QuadMesh::bufferQuadMeshWithZ(&this->mesh, QuadMesh::bufferQuadMeshWithZ(&this->mesh,
position + charInfo.bitmapPosition, uv0, position + charInfo.bitmapPosition, uv0,
position + charInfo.bitmapPosition + charInfo.bitmapSize, uv1, position + charInfo.bitmapPosition + charInfo.bitmapSize, uv1,

View File

@ -9,6 +9,8 @@
#include "asset/assets/NewTrueTypeAsset.hpp" #include "asset/assets/NewTrueTypeAsset.hpp"
#include "util/Xml.hpp" #include "util/Xml.hpp"
#define UI_LABEL_MAX_WIDTH_NONE -1
namespace Dawn { namespace Dawn {
struct UILabelStyle { struct UILabelStyle {
struct Color color = COLOR_WHITE; struct Color color = COLOR_WHITE;
@ -32,7 +34,7 @@ namespace Dawn {
struct NewTrueTypeFaceTexture *texture = nullptr; struct NewTrueTypeFaceTexture *texture = nullptr;
}; };
class UILabelNew : public UIComponentRenderable { class UILabel : public UIComponentRenderable {
private: private:
Mesh mesh; Mesh mesh;
FontShaderBuffer shaderBuffer; FontShaderBuffer shaderBuffer;
@ -60,19 +62,24 @@ namespace Dawn {
int32_t partIndex int32_t partIndex
); );
public: public:
std::string test; int32_t quadStart = 0;
int32_t quadCount = -1;
int32_t quadCountTotal = -1;
UILabelNew(SceneItem *item); UILabel(SceneItem *item);
void onStart() override; void onStart() override;
std::vector<struct ShaderPassItem> getUIRenderPasses() override; std::vector<struct ShaderPassItem> getUIRenderPasses() override;
float_t getWidth() override;
float_t getHeight() override;
float_t getContentWidth() override; float_t getContentWidth() override;
float_t getContentHeight() override; float_t getContentHeight() override;
/**
* Rebuffer the quads for this label. This method will perform all the
* necessary difference calculations from where the current state of this text is.
*
* @param texts Texts to buffer.
*/
void rebufferQuads(std::vector<struct UILabelText> texts); void rebufferQuads(std::vector<struct UILabelText> texts);
}; };
} }

View File

@ -0,0 +1,82 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIRichTextLabel.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
UIRichTextLabel::UIRichTextLabel(SceneItem *item) :
UILabel(item)
{
}
void UIRichTextLabel::onStart() {
UILabel::onStart();
useEffect([&]{
std::vector<struct UILabelStyle> styleStack;
struct UILabelStyle current;
styleStack.push_back(current);
std::vector<struct UILabelText> bufferTexts;
std::function<void(Xml*)> parseChildren = [&](Xml *node) {
if(node->children.empty()) {
struct UILabelText text;
text.style = current;
text.text = node->value;
bufferTexts.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>" + ((std::string)this->richText) + "</root>");
parseChildren(&root);
this->rebufferQuads(bufferTexts);
}, this->richText)();
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "UILabel.hpp"
namespace Dawn {
class UIRichTextLabel : public UILabel {
public:
StateProperty<std::string> richText;
UIRichTextLabel(SceneItem *item);
void onStart() override;
};
}

View File

@ -7,7 +7,7 @@
#include "scene/Scene.hpp" #include "scene/Scene.hpp"
#include "prefabs/SimpleSpinningCubePrefab.hpp" #include "prefabs/SimpleSpinningCubePrefab.hpp"
#include "scene/components/display/Camera.hpp" #include "scene/components/display/Camera.hpp"
#include "scene/components/ui/text/UILabelNew.hpp" #include "scene/components/ui/text/UIRichTextLabel.hpp"
namespace Dawn { namespace Dawn {
class HelloWorldScene : public Scene { class HelloWorldScene : public Scene {
@ -26,8 +26,24 @@ namespace Dawn {
auto newLabelItem = this->createSceneItem(); auto newLabelItem = this->createSceneItem();
newLabelItem->transform.setParent(canvas->transform); newLabelItem->transform.setParent(canvas->transform);
auto newLabel = newLabelItem->addComponent<UILabelNew>(); auto newLabel = newLabelItem->addComponent<UIRichTextLabel>();
newLabel->test = "<font font=\"font_arial\" size=\"32\" color=\"COLOR_BLUE\">Hello</font><font style=\"bold\" font=\"font_arial\" size=\"64\" color=\"COLOR_RED\">World</font>"; // newLabel->maxWidth = 300.0f;
newLabel->richText = std::string(
"<font font=\"font_arial\" size=\"16\" color=\"COLOR_BLUE\">"
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"</font>"
);
} }
std::vector<Asset*> getRequiredAssets() override { std::vector<Asset*> getRequiredAssets() override {

View File

@ -8,7 +8,7 @@
#include "util/macro.hpp" #include "util/macro.hpp"
#define FONT_SHADER_PARTS_MAX 4 #define FONT_SHADER_PARTS_MAX 4
#define FONT_SHADER_QUADS_MAX 32 #define FONT_SHADER_QUADS_MAX 1024
#define FONT_SHADER_TEXTURE_MAX 4 #define FONT_SHADER_TEXTURE_MAX 4
namespace Dawn { namespace Dawn {