Cogs.Core
Text3DSystem.cpp
1#include "Text3DSystem.h"
2#include "TransformSystem.h"
3
4#include "../../Context.h"
5#include "../../Components/Appearance/MaterialComponent.h"
6#include "../../Components/Core/MeshComponent.h"
7#include "../../Components/Core/MeshRenderComponent.h"
8#include "../../Resources/MaterialManager.h"
9#include "../../Resources/MeshManager.h"
10#include "../../Resources/FontManager.h"
11#include "../../Resources/Texture.h"
12
13#include "Rendering/ICapabilities.h"
14#include "Foundation/Geometry/IndicesGenerator.h"
15
17 Cogs::Core::FontManager* fontManager = context->fontManager;
18
19 for (const Text3DComponent& textComponent : pool) {
20 if (textComponent.isValid()) {
21 Font* font = textComponent.fontHandle.resolve();
22 MaterialComponent* material = textComponent.getComponent<MaterialComponent>();
23 MeshRenderComponent* meshRenderComp = textComponent.getComponent<MeshRenderComponent>();
24 MaterialInstance* materialInstance = nullptr;
25 bool materialChanged = false;
26
27 if (!font) {
28 font = fontManager->getHandle(fontManager->DefaultRegularFont).resolve();
29 }
30 if (material) {
31 if (material->diffuseMap != font->texture) {
32 materialChanged = true;
33 }
34 }
35 else {
36 materialInstance = meshRenderComp->material.resolve();
37
38 if (materialInstance && (materialInstance->getTextureProperty(materialInstance->material->getTextureKey("diffuseMap")).texture.handle != font->texture)) {
39 materialChanged = true;
40 }
41 }
42
43 if (font &&
44 font->isActive() &&
45 font->texture &&
46 font->texture->isActive() &&
47 (textComponent.hasChanged() || materialChanged)) {
48 MeshHandle meshHandle = context->meshManager->create();
49 Mesh* mesh = meshHandle.resolve();
50 std::vector<glm::vec3> vertices;
51 std::vector<glm::vec2> uvs;
52 std::vector<glm::vec4> colours;
53 size_t glyphCount = 0;
54
55 for (const std::string& t : textComponent.texts) {
56 glyphCount += t.size();
57 }
58 vertices.reserve(glyphCount * 4);
59 uvs.reserve(glyphCount * 4);
60 colours.reserve(glyphCount * 4);
61
62 for (size_t textIdx = 0, textCount = textComponent.texts.size(); textIdx < textCount; ++textIdx) {
63 const std::string& text = textComponent.texts[textIdx];
64 const glm::vec3& position = textComponent.positions[textIdx];
65 const glm::vec3& hAxis = textComponent.hAxes[textIdx];
66 const glm::vec3& vAxis = textComponent.vAxes[textIdx];
67 const glm::vec4& colour = textComponent.colors.empty() ? textComponent.defaultColor : textComponent.colors[textIdx];
68 const Alignment& alignment = textComponent.alignments.empty() ? textComponent.defaultAlignment : textComponent.alignments[textIdx];
69
70 generateText(vertices, uvs, fontManager, *font, text, position, hAxis, vAxis, alignment);
71 colours.insert(colours.end(), text.size() << 2, colour);
72 }
73
74 std::vector<uint32_t> indices;
75 constexpr float maxfloat = std::numeric_limits<float>::max();
76 glm::vec3 minbounds(maxfloat, maxfloat, maxfloat);
77 glm::vec3 maxbounds(-maxfloat, -maxfloat, -maxfloat);
78
79 for (glm::vec3& vert : vertices) {
80 minbounds = glm::min(minbounds, vert);
81 maxbounds = glm::max(maxbounds, vert);
82 }
83
84 Geometry::generateQuadIndices(indices, vertices.size() >> 2, 0, false);
85
86 mesh->setName(textComponent.getContainer()->getName());
87 mesh->setPositions(vertices);
88 mesh->setTexCoords(uvs);
89 mesh->setColors(colours);
90 mesh->setIndexData(std::move(indices));
91 mesh->setBounds({minbounds, maxbounds});
92
93 textComponent.getComponent<MeshComponent>()->meshHandle = meshHandle;
94 textComponent.getComponent<MeshComponent>()->setChanged();
95
96 if (material) {
97 material->diffuseMap = font->texture;
98 material->setChanged();
99 }
100 else if (materialInstance) {
101 materialInstance->setTextureProperty("diffuseMap", font->texture);
102 materialInstance->setTransparent();
103 materialInstance->options.blendMode = Cogs::Core::BlendMode::Blend;
104 materialInstance->setVariant("Textured", true);
105 }
106 }
107 }
108 }
109}
110
111float Cogs::Core::Text3DSystem::calcTextWidth(const FontManager* fontManager, const Font& font, const std::string& text) {
113 float width = 0.0f;
114
115 for (auto c : text) {
116 float x = 0.0f;
117 float y = 0.0f;
118
119 fontManager->getBakedCharacter(&font, c, x, y, bc);
120 width += bc.x1;
121 }
122 return width;
123}
124
125void Cogs::Core::Text3DSystem::generateText(std::vector<glm::vec3>& vertices,
126 std::vector<glm::vec2>& uvs,
127 const FontManager* fontManager,
128 const Font& font,
129 const std::string& text,
130 glm::vec3 position,
131 glm::vec3 hAxis,
132 glm::vec3 vAxis,
133 Alignment alignment) {
134 float height = glm::length(vAxis);
135 float verticalScale = height / font.size;
136 float horizontalScale = verticalScale * glm::length(hAxis);
137 float textwidth = calcTextWidth(fontManager, font, text) * horizontalScale;
138
139 hAxis /= glm::length(hAxis);
140 vAxis /= height;
141
142 switch (alignment & Alignment::Horizontal) {
143 case Alignment::Center: position -= hAxis * (textwidth * 0.5f); break;
144 case Alignment::Right: position -= hAxis * textwidth; break;
145 default: break;
146 }
147 switch (alignment & Alignment::Vertical) {
148 case Alignment::Middle: position += vAxis * (font.size * verticalScale * 0.5f); break;
149 case Alignment::Bottom: position += vAxis * (font.size * verticalScale); break;
150 default: break;
151 }
152
153 position -= vAxis * (font.ascent * verticalScale);
154
155 for (size_t ii = 0; ii < text.size(); ++ii) {
156 Font::BakedCharacter bc;
157 float x = 0.0f;
158 float y = 0.0f;
159
160 fontManager->getBakedCharacter(&font, text[ii], x, y, bc);
161
162 glm::vec3 left = hAxis * (bc.x0 * horizontalScale);
163 glm::vec3 right = hAxis * (bc.x1 * horizontalScale);
164 glm::vec3 up = vAxis * (bc.y0 * verticalScale);
165 glm::vec3 down = vAxis * (bc.y1 * verticalScale);
166
167 vertices.push_back(position - up + left);
168 vertices.push_back(position - down + left);
169 vertices.push_back(position - up + right);
170 vertices.push_back(position - down + right);
171
172 uvs.push_back({bc.s0, bc.t0});
173 uvs.push_back({bc.s0, bc.t1});
174 uvs.push_back({bc.s1, bc.t0});
175 uvs.push_back({bc.s1, bc.t1});
176
177 position += right;
178 }
179}
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< Text3DComponent > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Font manager responsible for loading, processing and lifetime of Font resources.
Definition: FontManager.h:40
ResourceId DefaultRegularFont
Id of the default font.
Definition: FontManager.h:101
void getBakedCharacter(const Font *font, int characterIndex, float &x, float &y, Font::BakedCharacter &bakedCharacter) const
Retrieve baked character information for rendering.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
Renders the contents of a MeshComponent using the given materials.
ResourceHandle getHandle(const ResourceId id) const
Get a resource handle to the resource with the given id.
Renders the given text(s) as 3D mesh data.
@ Blend
Render with regular alpha blending.
COGSFOUNDATION_API void generateQuadIndices(std::vector< uint32_t > &dest, size_t quadCount, uint32_t vertexNumber, bool sharedVertices)
Generate indices for rendering the specified number of quads from four vertices starting from the giv...
void setChanged(Cogs::Core::Context *context, Cogs::ComponentModel::Component *component, Reflection::FieldId fieldId)
Must be Called after changing a Component field. Mark field changed. Request engine update.
Definition: FieldSetter.h:25
Defines a quad with locations in screen space defined by [x0, y0] and [x1, y1].
Definition: Font.h:48
Font resources are used to render text with a specific font and size.
Definition: Font.h:22
Exposes material properties for legacy entities and code.
Material instances represent a specialized Material combined with state for all its buffers and prope...
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void setTexCoords(std::span< const glm::vec2 > texCoords)
Set the texture coordinate data of the Mesh.
Definition: Mesh.h:504
void setIndexData(const uint32_t *data, size_t count)
Convenience method for setting index data from a raw pointer to data and count number of elements.
Definition: Mesh.h:705
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
Definition: Mesh.h:298
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
Definition: Mesh.h:315
void setName(const StringView &name)
Set the user friendly name of the resource.
Definition: ResourceBase.h:298
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.