neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
ecs_helpers.hpp
Go to the documentation of this file.
1// ecs_helpers.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2018, 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
20#pragma once
21
22#include <neogfx/neogfx.hpp>
25#include <neogfx/gfx/shapes.hpp>
26#include <neogfx/game/i_ecs.hpp>
27#include <neogfx/game/mesh.hpp>
29#include <neogfx/game/color.hpp>
35
36namespace neogfx
37{
38 template <typename CoordinateType, logical_coordinate_system CoordinateSystem>
39 inline game::mesh const& to_ecs_component(game::mesh& aResult, const basic_rect<CoordinateType, CoordinateSystem>& aRect, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
40 {
41 auto const& rectVertices = rect_vertices(aRect, aMeshType, aTransformation);
42 aResult.vertices.assign(rectVertices.begin(), rectVertices.end());
43 aResult.uv = {
44 vec2{ 0.0, 1.0 }, vec2{ 1.0, 1.0 }, vec2{ 0.0, 0.0 },
45 vec2{ 1.0, 1.0 }, vec2{ 1.0, 0.0 }, vec2{ 0.0, 0.0 } };
46 aResult.faces = {
47 game::face{ aOffset + 0u, aOffset + 1u, aOffset + 2u },
48 game::face{ aOffset + 3u, aOffset + 4u, aOffset + 5u } };
49 return aResult;
50 }
51
52 template <typename CoordinateType, logical_coordinate_system CoordinateSystem>
53 inline game::mesh const& to_ecs_component(const basic_rect<CoordinateType, CoordinateSystem>& aRect, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
54 {
55 thread_local game::mesh result;
56 return to_ecs_component(result, aRect, aMeshType, aTransformation, aOffset);
57 }
58
59 template <typename T, std::size_t D>
60 inline std::array<basic_vector<T, D>, 4> center_quad(const std::array<basic_vector<T, D>, 4>& aQuad, basic_vector<T, D>& aCenteringTranslation)
61 {
62 // todo: this is a naive solution
63 std::optional<basic_vector<T, D>> min;
64 std::optional<basic_vector<T, D>> max;
65 for (auto const& v : aQuad)
66 {
67 if (!min)
68 min = v;
69 else
70 min = min->min(v);
71 if (!max)
72 max = v;
73 else
74 max = max->max(v);
75 }
76 aCenteringTranslation = basic_vector<T, D>{ -(max->x - min->x) / static_cast<T>(2.0), -(max->y - min->y) / static_cast<T>(2.0) };
77 std::array<basic_vector<T, D>, 4> result = aQuad;
78 for (auto& v : result)
79 v += aCenteringTranslation;
80 return result;
81 }
82
83 inline game::mesh const& to_ecs_component(game::mesh& aResult, const quad& aQuad, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
84 {
85 if (!aTransformation)
86 {
87 aResult.vertices = {
88 aQuad[0], aQuad[3], aQuad[2],
89 aQuad[0], aQuad[1], aQuad[2] };
90 }
91 else
92 {
93 vec3 centeringTranslation;
94 auto centeredQuad = center_quad(aQuad, centeringTranslation);
95 for (auto& v : centeredQuad)
96 v = *aTransformation * v + -centeringTranslation;
97 aResult.vertices = {
98 centeredQuad[0], centeredQuad[3], centeredQuad[2],
99 centeredQuad[0], centeredQuad[1], centeredQuad[2] };
100 }
101 aResult.uv = {
102 vec2{ 0.0, 0.0 }, vec2{ 0.0, 1.0 }, vec2{ 1.0, 1.0 },
103 vec2{ 0.0, 0.0 }, vec2{ 1.0, 0.0 }, vec2{ 1.0, 1.0 } };
104 aResult.faces = {
105 game::face{ aOffset + 0u, aOffset + 1u, aOffset + 2u },
106 game::face{ aOffset + 3u, aOffset + 4u, aOffset + 5u } };
107 return aResult;
108 }
109
110 inline game::mesh const& to_ecs_component(const quad& aQuad, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
111 {
112 thread_local game::mesh result;
113 return to_ecs_component(result, aQuad, aMeshType, aTransformation, aOffset);
114 }
115
116 inline game::mesh const& to_ecs_component(game::mesh& aResult, const quad_2d& aQuad, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
117 {
118 return to_ecs_component(aResult, quad{ aQuad[0], aQuad[1], aQuad[2], aQuad[3] }, aMeshType, aTransformation, aOffset);
119 }
120
121 inline game::mesh const& to_ecs_component(const quad_2d& aQuad, mesh_type aMeshType = mesh_type::Triangles, optional_mat44 const& aTransformation = {}, uint32_t aOffset = 0)
122 {
123 thread_local game::mesh result;
124 return to_ecs_component(result, aQuad, aMeshType, aTransformation, aOffset);
125 }
126
127 inline game::mesh to_ecs_component(const vertices& aVertices, mesh_type aSourceMeshType = mesh_type::TriangleFan, mesh_type aDestinationMeshType = mesh_type::Triangles)
128 {
129 // todo
130 return game::mesh{};
131 }
132
133 inline game::color to_ecs_component(const color& aColor)
134 {
135 return game::color{ aColor };
136 }
137
138 inline game::gradient to_ecs_component(const gradient& aGradient)
139 {
140 return game::gradient
141 {
142 neolib::cookie_ref_ptr{ service<i_gradient_manager>(), aGradient.id() },
143 aGradient.bounding_box() ? aGradient.bounding_box()->to_aabb_2d() : std::optional<aabb_2d>{}
144 };
145 }
146
148 {
149 if (std::holds_alternative<color>(aTextColor))
150 return game::material{ to_ecs_component(std::get<color>(aTextColor)) };
151 else if (std::holds_alternative<gradient>(aTextColor))
152 return game::material{ {}, to_ecs_component(std::get<gradient>(aTextColor)) };
153 else
154 return game::material{ game::color{} };
155 }
156
158 {
159 switch (aEffectType)
160 {
162 return shader_effect::None;
164 return shader_effect::None;
169 default:
170 return shader_effect::None;
171 }
172 }
173
175 {
176 if (std::holds_alternative<color>(aBrush))
177 return game::material{ to_ecs_component(std::get<color>(aBrush)) };
178 else if (std::holds_alternative<gradient>(aBrush))
179 return game::material{ {}, to_ecs_component(std::get<gradient>(aBrush)) };
180 else
181 return game::material{ game::color{} };
182 }
183
184 inline std::optional<game::filter> to_ecs_component(blurring_algorithm aAlgorithm, scalar aParameter1, scalar aParameter2)
185 {
186 switch (aAlgorithm)
187 {
189 return {};
191 return game::filter{ shader_filter::GaussianBlur, aParameter1, aParameter2 };
192 default:
193 return {};
194 }
195 }
196
198 {
199 return game::texture
200 {
201 neolib::cookie_ref_ptr{ service<i_texture_manager>(), aTexture.id() },
202 aTexture.type(),
203 aTexture.sampling(),
204 aTexture.dpi_scale_factor(),
205 aTexture.extents().to_vec2(),
207 };
208 }
209
210 inline game::texture to_ecs_component(const i_texture& aTexture, const rect& aTextureRect)
211 {
212 return game::texture
213 {
214 neolib::cookie_ref_ptr{ service<i_texture_manager>(), aTexture.id() },
215 aTexture.type(),
216 aTexture.sampling(),
217 aTexture.dpi_scale_factor(),
218 aTexture.extents().to_vec2(),
219 aTextureRect.to_aabb_2d()
220 };
221 }
222
224 {
225 texture newTexture{ aImage };
226 return game::texture
227 {
228 neolib::cookie_ref_ptr{ service<i_texture_manager>(), newTexture.id() },
229 newTexture.type(),
230 newTexture.sampling(),
231 newTexture.dpi_scale_factor(),
232 newTexture.extents().to_vec2(),
233 {}
234 };
235 }
236
237 inline game::texture to_ecs_component(const i_image& aImage, const rect& aTextureRect)
238 {
239 texture newTexture{ aImage };
240 return game::texture
241 {
242 neolib::cookie_ref_ptr{ service<i_texture_manager>(), newTexture.id() },
243 newTexture.type(),
244 newTexture.sampling(),
245 newTexture.dpi_scale_factor(),
246 newTexture.extents().to_vec2(),
247 aTextureRect.to_aabb_2d()
248 };
249 }
250
251 inline game::material image_to_material(game::i_ecs& aEcs, std::string const& aName, const neogfx::image& aImage)
252 {
253 return game::material{ {}, {}, aEcs.shared_component<game::texture>().populate(aName, to_ecs_component(aImage)) };
254 }
255
256 inline game::material image_to_material(game::i_ecs& aEcs, std::string const& aName, std::string const& aImageResource)
257 {
258 return image_to_material(aEcs, aName, neogfx::image{ aImageResource });
259 }
260
261 inline game::animation regular_sprite_sheet_to_animation(const vec2u32& aSpriteSheetExtents, const vec2u32& aCells, const vec2u32& aCellIndexTopLeft, const vec2u32& aCellIndexBottomRight, scalar aDefaultDuration = 0.0)
262 {
263 vec2 const uvCellExtents{ 1.0 / aCells.as<scalar>().x, 1.0 / aCells.as<scalar>().y };
264 game::animation results;
265 for (u32 y = aCellIndexTopLeft.y; y <= aCellIndexBottomRight.y; ++y)
266 {
267 for (u32 x = aCellIndexTopLeft.x; x <= aCellIndexBottomRight.x; ++x)
268 {
269 vec2 const uvOffset{ x * uvCellExtents.x, 1.0 - (y + 1) * uvCellExtents.y };
270 results.frames.push_back(
272 {
273 aDefaultDuration,
275 {
276 {},
278 {
279 { vec3{ -1.0, -1.0, 0.0 }, vec3{ 1.0, -1.0, 0.0 }, vec3{ 1.0, 1.0, 0.0 }, vec3{ -1.0, 1.0, 0.0 } },
280 { uvOffset, uvOffset + vec2{ uvCellExtents.x, 0.0 }, uvOffset + vec2{ uvCellExtents.x, uvCellExtents.y }, uvOffset + vec2{ 0.0, uvCellExtents.y } },
281 { game::face{ 3u, 2u, 0u }, game::face{ 2u, 1u, 0u } }
282 }
283 }
284 });
285 }
286 }
287 return results;
288 }
289
290 inline game::animation regular_sprite_sheet_to_animation(const vec2u32& aSpriteSheetExtents, const vec2u32& aCells, scalar aDefaultFrameDuration = 0.0)
291 {
292 return regular_sprite_sheet_to_animation(aSpriteSheetExtents, aCells, vec2u32{}, vec2u32{ aCells.x - 1u, aCells.y - 1u }, aDefaultFrameDuration);
293 }
294
295 inline game::animation regular_sprite_sheet_to_animation(const game::material& aSpriteSheet, const vec2u32& aCells, const vec2u32& aCellIndexTopLeft, const vec2u32& aCellIndexBottomRight, scalar aDefaultFrameDuration = 0.0)
296 {
298 aSpriteSheet.sharedTexture ? aSpriteSheet.sharedTexture->ptr->extents.as<u32>() : aSpriteSheet.texture->extents.as<u32>(),
299 aCells, aCellIndexTopLeft, aCellIndexBottomRight, aDefaultFrameDuration);
300 }
301
302 inline game::animation regular_sprite_sheet_to_animation(const game::material& aSpriteSheet, const vec2u32& aCells, scalar aDefaultFrameDuration = 0.0)
303 {
305 aSpriteSheet.sharedTexture ? aSpriteSheet.sharedTexture->ptr->extents.as<u32>() : aSpriteSheet.texture->extents.as<u32>(),
306 aCells, aDefaultFrameDuration);
307 }
308
314
315 inline renderable_animation regular_sprite_sheet_to_renderable_animation(game::i_ecs& aEcs, std::string const& aName, const neogfx::image& aSpriteSheet, const vec2u32& aCells, scalar aDefaultFrameDuration = 0.0)
316 {
318 result.material = image_to_material(aEcs, aName, aSpriteSheet);
319 result.filter = game::animation_filter{ aEcs.shared_component<game::animation>().populate(aName, regular_sprite_sheet_to_animation(result.material, aCells, aDefaultFrameDuration)) };
320 return result;
321 }
322
323 inline renderable_animation regular_sprite_sheet_to_renderable_animation(game::i_ecs& aEcs, std::string const& aName, std::string const& aSpriteSheetResource, const vec2u32& aCells, scalar aDefaultFrameDuration = 0.0)
324 {
325 return regular_sprite_sheet_to_renderable_animation(aEcs, aName, neogfx::image{ aSpriteSheetResource }, aCells, aDefaultFrameDuration);
326 }
327
328 inline void add_patch(game::mesh& aMesh, game::mesh_renderer& aMeshRenderer, const quad& aQuad, const neogfx::i_texture& aTexture, const mat33& aTextureTransform = mat33::identity())
329 {
330 thread_local game::mesh patchMesh;
331 to_ecs_component(patchMesh, aQuad, mesh_type::Triangles, std::nullopt, static_cast<uint32_t>(aMesh.vertices.size()));
332 aMesh.vertices.insert(aMesh.vertices.end(), patchMesh.vertices.begin(), patchMesh.vertices.end());
333 if (!aTextureTransform.is_identity())
334 for (auto& uv : patchMesh.uv)
335 uv = (aTextureTransform * vec3{ uv.x, uv.y, 1.0 }).xy;
336 aMesh.uv.insert(aMesh.uv.end(), patchMesh.uv.begin(), patchMesh.uv.end());
337 auto& patch = aMeshRenderer.patches.emplace_back();
338 patch.faces.insert(patch.faces.end(), patchMesh.faces.begin(), patchMesh.faces.end());
339 patch.material.texture = to_ecs_component(aTexture);
340 }
341
342 inline void add_patch(game::mesh& aMesh, game::mesh_renderer& aMeshRenderer, const quad_2d& aQuad, const neogfx::i_texture& aTexture, const mat33& aTextureTransform = mat33::identity())
343 {
344 thread_local game::mesh patchMesh;
345 to_ecs_component(patchMesh, aQuad, mesh_type::Triangles, std::nullopt, static_cast<uint32_t>(aMesh.vertices.size()));
346 aMesh.vertices.insert(aMesh.vertices.end(), patchMesh.vertices.begin(), patchMesh.vertices.end());
347 if (!aTextureTransform.is_identity())
348 for (auto& uv : patchMesh.uv)
349 uv = (aTextureTransform * vec3{ uv.x, uv.y, 1.0 }).xy;
350 aMesh.uv.insert(aMesh.uv.end(), patchMesh.uv.begin(), patchMesh.uv.end());
351 auto& patch = aMeshRenderer.patches.emplace_back();
352 patch.faces.insert(patch.faces.end(), patchMesh.faces.begin(), patchMesh.faces.end());
353 patch.material.texture = to_ecs_component(aTexture);
354 }
355
356 inline void add_patch(game::mesh& aMesh, game::mesh_renderer& aMeshRenderer, const rect& aRect, const neogfx::i_texture& aTexture, const mat33& aTextureTransform = mat33::identity())
357 {
358 thread_local game::mesh patchMesh;
359 to_ecs_component(patchMesh, aRect, mesh_type::Triangles, std::nullopt, static_cast<uint32_t>(aMesh.vertices.size()));
360 aMesh.vertices.insert(aMesh.vertices.end(), patchMesh.vertices.begin(), patchMesh.vertices.end());
361 if (!aTextureTransform.is_identity())
362 for (auto& uv : patchMesh.uv)
363 uv = (aTextureTransform * vec3{ uv.x, uv.y, 1.0 }).xy;
364 aMesh.uv.insert(aMesh.uv.end(), patchMesh.uv.begin(), patchMesh.uv.end());
365 auto& patch = aMeshRenderer.patches.emplace_back();
366 patch.faces.insert(patch.faces.end(), patchMesh.faces.begin(), patchMesh.faces.end());
367 patch.material.texture = to_ecs_component(aTexture);
368 }
369}
const optional_rect & bounding_box() const override
gradient_id id() const override
aabb_2d to_aabb_2d() const
basic_vector< dimension_type, 2 > to_vec2() const
virtual const rect & atlas_location() const =0
virtual const i_sub_texture & as_sub_texture() const =0
virtual texture_id id() const =0
virtual dimension dpi_scale_factor() const =0
virtual texture_type type() const =0
virtual texture_sampling sampling() const =0
virtual size extents() const =0
virtual const i_shared_component & shared_component(component_id aComponentId) const =0
basic_vector< T2, Size, Type > as() const
vec3u32 face
Definition i_ecs.hpp:35
void add_patch(game::mesh &aMesh, game::mesh_renderer &aMeshRenderer, const quad &aQuad, const neogfx::i_texture &aTexture, const mat33 &aTextureTransform=mat33::identity())
std::array< basic_vector< T, D >, 4 > center_quad(const std::array< basic_vector< T, D >, 4 > &aQuad, basic_vector< T, D > &aCenteringTranslation)
blurring_algorithm
renderable_animation regular_sprite_sheet_to_renderable_animation(game::i_ecs &aEcs, std::string const &aName, const neogfx::image &aSpriteSheet, const vec2u32 &aCells, scalar aDefaultFrameDuration=0.0)
game::mesh const & to_ecs_component(game::mesh &aResult, const basic_rect< CoordinateType, CoordinateSystem > &aRect, mesh_type aMeshType=mesh_type::Triangles, optional_mat44 const &aTransformation={}, uint32_t aOffset=0)
vec3_array< 8 > const & rect_vertices(const basic_rect< CoordinateType, CoordinateSystem > &aRect, mesh_type aType, const optional_mat44 &aTransformation={})
Definition shapes.hpp:76
game::animation regular_sprite_sheet_to_animation(const vec2u32 &aSpriteSheetExtents, const vec2u32 &aCells, const vec2u32 &aCellIndexTopLeft, const vec2u32 &aCellIndexBottomRight, scalar aDefaultDuration=0.0)
game::material image_to_material(game::i_ecs &aEcs, std::string const &aName, const neogfx::image &aImage)
mesh_type
Definition shapes.hpp:28
vec3_list vertices
std::array< vec2, 4 > quad_2d
matrix33 mat33
std::array< vec3, 4 > quad
vector2u32 vec2u32
double scalar
Definition numerical.hpp:63
uint32_t u32
basic_cookie_ref_ptr< cookie > cookie_ref_ptr
Definition jar.hpp:732
animation_frames frames
Definition animation.hpp:94
std::optional< texture > texture
Definition material.hpp:41
std::optional< shared< texture > > sharedTexture
Definition material.hpp:40
vertices_2d uv
Definition mesh.hpp:34
vertices vertices
Definition mesh.hpp:33
neolib::cookie_ref_ptr id
Definition texture.hpp:37
game::animation_filter filter