neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
text_mesh.hpp
Go to the documentation of this file.
1// text_mesh.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2015, 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19#pragma once
20
21#include <neogfx/neogfx.hpp>
27#include <neogfx/gfx/shapes.hpp>
31#include <neogfx/game/font.hpp>
33
34namespace neogfx::game
35{
36 struct text_mesh
37 {
38 string text;
48
50 {
51 static const neolib::uuid& id()
52 {
53 static const neolib::uuid sId = { 0x6f45d8be, 0xba9c, 0x4a32, 0xa99e,{ 0x37, 0xd3, 0xf2, 0xb4, 0xe7, 0x53 } };
54 return sId;
55 }
56 static const i_string& name()
57 {
58 static const string sName = "Text Mesh";
59 return sName;
60 }
61 static uint32_t field_count()
62 {
63 return 10;
64 }
65 static component_data_field_type field_type(uint32_t aFieldIndex)
66 {
67 switch (aFieldIndex)
68 {
69 case 0:
70 return component_data_field_type::String;
71 case 1:
72 return component_data_field_type::Vec2;
73 case 2:
74 return component_data_field_type::Scalar;
75 case 3:
76 return component_data_field_type::Vec4;
77 case 4:
78 return component_data_field_type::Enum | component_data_field_type::Uint32;
79 case 5:
80 return component_data_field_type::ComponentData | component_data_field_type::Shared;
81 case 6:
82 return component_data_field_type::ComponentData;
83 case 7:
84 return component_data_field_type::Enum | component_data_field_type::Uint32;
85 case 8:
86 return component_data_field_type::ComponentData;
87 case 9:
88 return component_data_field_type::Scalar;
89 default:
90 throw invalid_field_index();
91 }
92 }
93 static neolib::uuid field_type_id(uint32_t aFieldIndex)
94 {
95 switch (aFieldIndex)
96 {
97 case 0:
98 case 1:
99 case 2:
100 case 3:
101 case 4:
102 case 7:
103 case 9:
104 return neolib::uuid{};
105 case 5:
106 return font::meta::id();
107 case 6:
108 case 8:
109 return material::meta::id();
110 default:
111 throw invalid_field_index();
112 }
113 }
114 static const i_string& field_name(uint32_t aFieldIndex)
115 {
116 static const string sFieldNames[] =
117 {
118 "Text",
119 "Extents",
120 "Border",
121 "Padding",
122 "Alignment",
123 "Font",
124 "Ink",
125 "Text Effect",
126 "Text Effect Material",
127 "Text Effect Width"
128 };
129 return sFieldNames[aFieldIndex];
130 }
131 static constexpr bool has_updater = true;
132 static void update(const text_mesh& aData, i_ecs& aEcs, i_graphics_context const& aGc, entity_id aEntity)
133 {
134 auto& mf = aEcs.component<mesh_filter>().has_entity_record(aEntity) ?
135 aEcs.component<mesh_filter>().entity_record(aEntity) :
136 aEcs.component<mesh_filter>().populate(aEntity, mesh_filter{});
137 auto& mr = aEcs.component<mesh_renderer>().has_entity_record(aEntity) ?
138 aEcs.component<mesh_renderer>().entity_record(aEntity) :
139 aEcs.component<mesh_renderer>().populate(aEntity, mesh_renderer{});
140 mf.mesh = mesh{};
141 mr.patches = patches{};
142 auto multilineGlyphText = aGc.to_multiline_glyph_text(aData.text, service<i_font_manager>().font_from_id(aData.font.ptr->id.cookie()), aData.extents.x, aData.alignment);
143 for (auto const& line : multilineGlyphText.lines)
144 {
145 auto mesh_line = [&](const vec3& aOffset, const material& aMaterial)
146 {
147 auto const glyphs = std::ranges::subrange(std::next(multilineGlyphText.glyphText.cbegin(), line.begin), std::next(multilineGlyphText.glyphText.cbegin(), line.end));
148 auto const pos = aOffset + line.bbox[0] - vec3{ glyphs.begin()->cell[0] };
149 for (auto const& glyphChar : glyphs)
150 {
151 if (!is_whitespace(glyphChar))
152 {
153 auto const& glyphTexture = multilineGlyphText.glyphText.glyph(glyphChar);
154 add_patch(*mf.mesh, mr, pos + vec3{ glyphChar.cell[0] } + quad{ glyphChar.shape[0], glyphChar.shape[1], glyphChar.shape[2], glyphChar.shape[3] }, glyphTexture.texture());
155 mr.patches.back().material = material{ aMaterial.color, aMaterial.gradient, aMaterial.sharedTexture, mr.patches.back().material.texture, aMaterial.shaderEffect };
156 }
157 }
158 };
159 switch(aData.textEffect)
160 {
162 for (scalar oy = -aData.textEffectWidth; oy <= aData.textEffectWidth; ++oy)
163 for (scalar ox = -aData.textEffectWidth; ox <= aData.textEffectWidth; ++ox)
164 mesh_line(vec2{ ox, oy }, aData.textEffectMaterial);
165 break;
166 default:
167 // todo
168 break;
169 }
170 mesh_line(vec2{}, aData.ink);
171 }
172 }
173 };
174 };
175
176 namespace shape
177 {
178 class text : public entity
179 {
180 public:
182 {
184 static const renderable_entity_archetype sArchetype
185 {
186 { 0xe3115152, 0x90ad, 0x4f7a, 0x83b0, { 0x7a, 0x59, 0xce, 0xea, 0x47, 0xb } },
187 "Text Mesh",
189 };
190 return sArchetype;
191 }
192 public:
193 text(i_ecs& aEcs, i_graphics_context const& aGc, std::string const& aText, const neogfx::font& aFont, const neogfx::text_format& aTextFormat, neogfx::alignment aAlignment = alignment::Left);
194 text(const text& aOther);
195 };
196 }
197}
static const entity_archetype & archetype()
text(const text &aOther)
text(i_ecs &aEcs, i_graphics_context const &aGc, std::string const &aText, const neogfx::font &aFont, const neogfx::text_format &aTextFormat, neogfx::alignment aAlignment=alignment::Left)
virtual multiline_glyph_text to_multiline_glyph_text(std::string const &aText, dimension aMaxWidth, alignment aAlignment=alignment::Left) const =0
virtual const i_component & component(component_id aComponentId) const =0
const_iterator begin() const
std::vector< patch > patches
Definition patch.hpp:88
void add_patch(game::mesh &aMesh, game::mesh_renderer &aMeshRenderer, const quad &aQuad, const neogfx::i_texture &aTexture, const mat33 &aTextureTransform=mat33::identity())
bool is_whitespace(glyph_char const &g)
basic_line< coordinate > line
id_t entity_id
Definition ecs_ids.hpp:51
std::array< vec3, 4 > quad
double scalar
Definition numerical.hpp:63
it_type next(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:89
static const neolib::uuid & id()
Definition font.hpp:42
static const neolib::uuid & id()
Definition material.hpp:47
std::optional< color > color
Definition material.hpp:38
static const neolib::uuid & id()
Definition mesh.hpp:39
static uint32_t field_count()
Definition text_mesh.hpp:61
static const i_string & name()
Definition text_mesh.hpp:56
static component_data_field_type field_type(uint32_t aFieldIndex)
Definition text_mesh.hpp:65
static neolib::uuid field_type_id(uint32_t aFieldIndex)
Definition text_mesh.hpp:93
static void update(const text_mesh &aData, i_ecs &aEcs, i_graphics_context const &aGc, entity_id aEntity)
static const neolib::uuid & id()
Definition text_mesh.hpp:51
static constexpr bool has_updater
static const i_string & field_name(uint32_t aFieldIndex)
neogfx::alignment alignment
Definition text_mesh.hpp:42
text_effect_type textEffect
Definition text_mesh.hpp:45
shared< font > font
Definition text_mesh.hpp:43