Jackalope / jen (public) (License: GPLv3 or later version) (since 2018-10-24) (hash sha1)
----> ABOUT:

3D rendering and computing framework based on Vulkan API.

Libraries:
- simdcpp submodule (see my simdcpp repo)
- jmath submodule (see my jmath repo)
- mesh (constexpr generation of cubes, spheres, icosahedrons subdivisions)
- atlas (1D lines and 2D rectangles cutting)
- jlib submodule (see my jlib repo)
- jrf submodule (see my jrf repo)
- vkw (Vulkan API C++ wrapper)
Modules:
- compute (run compute shaders on gpu)
- graphics (draw models with clustered forward rendering and onscreen text)
- resource manager (load meshes, models, textures, scene data from
files and create related objects in graphics module)

----> INSTALLING:

To download all the parts of this framework it's enough to launch
git clone with recursive flag:

$ git clone —recursive ssh://rocketgit@ssh.rocketgit.com/user/Jackalope/jen

After this look at git tags:

$ git tag

It is recommended to use a tagged version instead of the latest commit,
because the first commit after the tagged one mostly includes incompatible
parts of future changes for the next version.

$ git checkout v0.1.0

----> DEPENDENCIES:

To use JEN as CMake subdirectory and successfully build programs with it
you need to make sure you have all of its dependencies:
- compiler: Clang or GCC, support for C++17. Clang 10+ or GCC 9+ is recommended,
compiling on Windows OS is tricky and requires something like MinGW with MSYS,
there are also some complications to go through to make dependencies work;
- GLFW3 library, supported version is 3.2.1;
- FreeType library, if graphics module will be used;
- Vulkan API headers, and optional validation layers to debug sneaky problems,
you also need Vulkan support in your graphics driver to run compiled programs;
- LibZip can be necessary, if JRF is used to read zip files;
- CMake, for obvious reasons;
- glslangValidator to compile shader for the graphics module.

CMake must be able to find GLFW3, Vulkan and FreeType (for graphics)
with find_package().

----> HOW TO USE IT:

To use JEN, you need to add it as a subdirectory:

add_subdirecroty(${PATH_TO_JEN})

There are several configuration options:
- JEN_MODULE_COMPUTE - turn compute module on for compiling and including;
- JEN_MODULE_GRAPHICS - turn graphics module on ...;
- JEN_MULTITHREADED_DRAW_FRAME - draw_frame function will use thread pool queue
instead of linear executing;
- JEN_MODULE_RESOURCE_MANAGER - resource manager module ON, if graphics is ON;
- JEN_VLK_VALIDATION - enable Vulkan Validation Layers to debug some errors
related to JEN. This will often produce false-positive,
as well as true-positive errors.

Look in CMakeLists.txt at JenExamples repo for details on how to use and
configure JEN automatically:

$ git clone ssh://rocketgit@ssh.rocketgit.com/user/Jackalope/JenExamples

Also I recommend to compile and run examples to make sure it works correctly.

----> SUPPORTED HARDWARE:

JEN has not been tested well, because it requires running it on large amount of
different hardware to do so. It must work with mesa driver and modern
Intel i965 GPUs as well as AMD GPUs.


----> DOCUMENTATION:

You can generate Doxygen documentation, to do so
turn on any of JEN_DOXYGEN_* options and run documentation target in cmake:

$ cmake -G %1 -DJEN_DOXYGEN_HTML=ON -DJEN_DOXYGEN_LATEX=ON
$ cmake —build —target documentation

Resource manager is not documented because it still requires large enhancements.
List of commits:
Subject Hash Author Date (UTC)
mesh library refactoring 4dd908c51d97035ed26cb1c413685c1a8ab15c77 Jackalope 2020-03-25 13:24:43
removed old unmaintained directory 75b147dd4dc5d3592da21a707ac301cd46eaaf3d Jackalope 2020-03-19 19:35:03
shader specialization constants support 932cd42ce93f89bd2c6b0a3a37eb9b74482f0d13 Jackalope 2020-03-09 04:58:58
compute module staging support 99a1a110c75a021e956b8ad5c481f269d693e078 Jackalope 2020-03-06 07:06:36
changed compute stage flag name (was wrong) 0e21df1430ac55c1dbc8a0f1969ffb1ec303b870 Jackalope 2020-03-06 06:59:38
changed compute interface to support reading after and writting before computing, staging is not supported yet 173f29331f5ebb5206f4086d58e93689eb85df96 Jackalope 2020-03-06 05:35:16
added staging allocation to Bindings b74e1cc5e8d80528e48e4f00ae215c547c685211 Jackalope 2020-03-06 05:34:04
Separate ComputeCmdUnit for cmds and syncs 9dc0a4a62e6fa68e60cfbd420eff61d8ee4334f0 Jackalope 2020-03-06 04:02:24
Compute descriptor set improvement, support for different descriptor types 5aad5ee0e4304b2035a652f4d4ca28e7a75bc93d Jackalope 2020-02-29 16:10:50
changed doxygen commentary style in DevMemUse description 9e9a548d6c50363a841af5d4897268aadba6ebed Jackalope 2020-02-29 16:08:33
make buffer functions const 24e343bc583629d08fad4d3dadb36a2fd72a4ca7 Jackalope 2020-02-29 16:08:04
added missing check in draw_drame cc6483e804d463fe4d1c41746692ec98bfbe53e8 Jackalope 2020-02-19 12:40:19
solved freee bug, draw data have pointer to user light data instead of applying every frame f60e7d3908651512a90488966141620306d54151 Jackalope 2020-02-19 10:50:22
solved lights flickefing issue c5cad408d3d9d908ac52760ebf1c42e7d578e61e Jackalope 2020-02-19 10:48:46
apply camera and frustum in single function ac6b09e32f0afa65eef918fb7bdb935cb99da2d8 Jackalope 2020-02-18 16:32:41
draw data wrong camera aspect fix 5d9270631a2ff3232c4928d811d55079ee30e6af Jackalope 2020-02-18 16:27:11
release macro fixed ebf6d8302ac06701d5fed4d4e153e0bc5c332990 Jackalope 2020-02-18 16:26:21
vkw memory barrier and buffer memory barrier 1df196563968fe2d0ab53f989b54b502500709e1 Jackalope 2020-02-17 18:31:15
removed forgotten redundand lines 24427796fde68c4d8a92b528ee876136da9ff365 Jackalope 2020-02-17 04:28:57
fix wrong cmd buffer begin flag f02a4272c22bfe918e4df881531699c723cf1156 Jackalope 2020-02-17 04:15:22
Commit 4dd908c51d97035ed26cb1c413685c1a8ab15c77 - mesh library refactoring
Author: Jackalope
Author date (UTC): 2020-03-25 13:24
Committer name: Jackalope
Committer date (UTC): 2020-03-25 13:24
Parent(s): 75b147dd4dc5d3592da21a707ac301cd46eaaf3d
Signer:
Signing key:
Signing status: N
Tree: 98604dee79b34550cc89dbebf7aa16f4340da8bf
File Lines added Lines deleted
libs/mesh/base.h 80 92
libs/mesh/cube.h 253 304
libs/mesh/plane.h 88 102
libs/mesh/polyhedron/icosahedron.h 131 144
libs/mesh/polyhedron/icosahedron_quad.h 172 176
libs/mesh/polyhedron/icosahedron_quad_tesselated.h 212 233
libs/mesh/polyhedron/icosahedron_quad_texture_coordinates.png 0 0
libs/mesh/polyhedron/icosahedron_tesselated.h 315 330
libs/mesh/sphere.h 189 193
File libs/mesh/base.h changed (mode: 100644) (index d92246c..54826b6)
4 4 #include <cmath> #include <cmath>
5 5
6 6 #include <jlib/rarray.h> #include <jlib/rarray.h>
7 #include <math/math.h>
7 #include <math/vector.h>
8 8
9 9 namespace mesh namespace mesh
10 10 { {
11 template<typename vec_t, typename index_t>
12 struct Mesh
13 {
14 using vector = vec_t;
15 using index = index_t;
16
17 static_assert(std::is_integral<index_t>::value);
18
19 jl::rarray<vec_t> vertexes;
20 jl::rarray<index_t> indexes;
21
22 [[nodiscard]] inline bool init(index_t vertex_count, index_t index_count);
23 inline void destroy();
24 };
25
26 template<typename vec_t, typename index_t>
27 [[nodiscard]] inline bool Mesh<vec_t, index_t>::init(index_t vertex_count, index_t index_count)
28 {
29 if (!vertexes.init(vertex_count))
30 return false;
31 if (!indexes.init(index_count))
32 {
33 vertexes.destroy();
34 return false;
35 }
36 return true;
37 }
38 template<typename vec_t, typename index_t>
39 inline void Mesh<vec_t, index_t>::destroy()
40 {
41 vertexes.destroy();
42 indexes.destroy();
43 }
44
45
46 template<bool texture, bool normals>
47 constexpr const unsigned int VEC_SIZE = 3 + texture * 2 + normals * 3;
48
49 template<bool texture>
50 constexpr const unsigned int N_OFFSET = 3 + texture * 2;
51
52 template<bool tex_coord, bool normals, typename floating_t, typename index_t>
53
54 using Mesh_T = Mesh<math::vector<VEC_SIZE<tex_coord, normals>, floating_t>, index_t>;
55
56 template<typename floating_t>
57 using PF_ModifyVertex = math::vec3<floating_t> (*)(const math::vec3<floating_t> &vec);
58
59 namespace modify_vertex
60 {
61 template<typename floating_t>
62 [[nodiscard]] constexpr inline math::vec3<floating_t> dummy(const math::vec3<floating_t>& vec)
63 {
64 return vec;
65 }
66
67 template<typename floating_t>
68 [[nodiscard]] constexpr inline math::vec3<floating_t> normalize(const math::vec3<floating_t>& vec)
69 {
70 return math::normalize(vec);
71 }
72
73 template<typename floating_t>
74 [[nodiscard]] constexpr inline math::vec3<floating_t> spheriy_vertex(const math::vec3<floating_t>& vec)
75 {
76 using namespace math;
77
78 vec3<floating_t> vec2 = vec * 2;
79 vec3<floating_t> squared = vec2 * vec2;
80 return vec2 * vec3<floating_t>
81 {
82 std::sqrt(1 - (squared.y + squared.z) / 2 + squared.y * squared.z / 3),
83 std::sqrt(1 - (squared.z + squared.x) / 2 + squared.z * squared.x / 3),
84 std::sqrt(1 - (squared.x + squared.y) / 2 + squared.x * squared.y / 3)
85 };
86 }
87 }
88
89 namespace __texture_coordinates
90 {
91 template<typename T>
92 [[nodiscard]] constexpr inline math::vec2<T> uv(math::vec3<T> vec)
93 {
94 if (vec[0] == 0)
95 return math::vec2<T>{ gcem::atan(math::zero<T>) / math::pi2<T>, - gcem::asin(vec[1]) / math::pi<T> }
96 + math::cast<T>(0.5L);
97
98 return math::vec2<T>{ gcem::atan(vec[2] / vec[0]) / math::pi2<T>, - gcem::asin(vec[1]) / math::pi<T> }
99 + math::cast<T>(0.5L);
100 }
101 }
11 template<typename vec_t, typename index_t>
12 struct Mesh
13 {
14 using vector = vec_t;
15 using index = index_t;
16
17 static_assert(std::is_integral<index_t>::value);
18
19 jl::rarray<vec_t> vertexes;
20 jl::rarray<index_t> indexes;
21
22 [[nodiscard]]
23 bool init(index_t vertex_count, index_t index_count);
24 void destroy();
25 };
26
27 template<typename vec_t, typename index_t> [[nodiscard]]
28 bool Mesh<vec_t, index_t>::init(index_t vertex_count, index_t index_count) {
29 if (!vertexes.init(vertex_count))
30 return false;
31 if (!indexes.init(index_count)) {
32 vertexes.destroy();
33 return false;
34 }
35 return true;
36 }
37 template<typename vec_t, typename index_t> inline
38 void Mesh<vec_t, index_t>::destroy()
39 {
40 vertexes.destroy();
41 indexes.destroy();
42 }
43
44 template<bool texture, bool normals>
45 constexpr const unsigned int VEC_SIZE = 3 + texture * 2 + normals * 3;
46 template<bool texture>
47 constexpr const unsigned int N_OFFSET = 3 + texture * 2;
48
49 template<bool tex_coord, bool normals, typename floating_t, typename index_t>
50 using Mesh_T = Mesh<math::vector<VEC_SIZE<tex_coord, normals>, floating_t>,
51 index_t>;
52 template<typename floating_t>
53 using PF_ModifyVertex =
54 math::vec3<floating_t>(*)(const math::vec3<floating_t> &vec);
55
56 namespace modify_vertex {
57 template<typename floating_t> [[nodiscard]] constexpr inline
58 math::vec3<floating_t> dummy(const math::vec3<floating_t>& vec) {
59 return vec;
60 }
61 template<typename floating_t> [[nodiscard]] constexpr inline
62 math::vec3<floating_t> normalize(const math::vec3<floating_t>& vec) {
63 return math::normalize(vec);
64 }
65 template<typename floating_t> [[nodiscard]] constexpr inline
66 math::vec3<floating_t> spheriy_vertex(const math::vec3<floating_t>& vec) {
67 math::vec3<floating_t> vec2 = vec * 2;
68 math::vec3<floating_t> squared = vec2 * vec2;
69 return vec2 * math::vec3<floating_t> {
70 std::sqrt(1 - (squared.y + squared.z) / 2 + squared.y * squared.z / 3),
71 std::sqrt(1 - (squared.z + squared.x) / 2 + squared.z * squared.x / 3),
72 std::sqrt(1 - (squared.x + squared.y) / 2 + squared.x * squared.y / 3)
73 };
74 }
75 }
76
77 namespace detail::texture_coordinates {
78 template<typename T> [[nodiscard]] constexpr inline
79 math::vec2<T> uv(math::vec3<T> vec) {
80 if (vec[0] == 0) {
81 return math::vec2<T>{ gcem::atan(math::zero<T>) / math::pi2<T>,
82 -gcem::asin(vec[1]) / math::pi<T> }
83 + math::cast<T>(0.5L);
84 }
85 return math::vec2<T>{ gcem::atan(vec[2] / vec[0]) / math::pi2<T>,
86 -gcem::asin(vec[1]) / math::pi<T> }
87 + math::cast<T>(0.5L);
88 }
89 }
102 90 } }
File libs/mesh/cube.h changed (mode: 100644) (index 6e5bc0d..ebaa994)
1 1 #pragma once #pragma once
2 2
3 3 #include "base.h" #include "base.h"
4 #include <math/math.h>
4 #include <math/vector.h>
5 #include <math/matrix.h>
5 6 #include <simd/simd.h> #include <simd/simd.h>
6 7 #include <limits> #include <limits>
7 8
 
12 13 #define ARGS CONDITION_ARGS, floating_t, index_t #define ARGS CONDITION_ARGS, floating_t, index_t
13 14 #define MESH_TEMPLATE Mesh_T<ARGS> #define MESH_TEMPLATE Mesh_T<ARGS>
14 15
15 namespace mesh
16 namespace mesh::cube
16 17 { {
17 namespace cube
18 {
19 enum Face : uint8_t
20 {
21 FACE1 = 0,
22 FACE2 = 1,
23 FACE3 = 2,
24 FACE4 = 3,
25 FACE5 = 4,
26 FACE6 = 5,
27
28 FACE_COUNT,
29
30 TOP = FACE1,
31 BOTTOM = FACE2,
32 NORTH = FACE3,
33 SOUTH = FACE4,
34 WEST = FACE5,
35 EAST = FACE6,
36 };
37
38 constexpr static const math::v3f NORMALS[Face::FACE_COUNT] =
39 {
40 { 0, 1, 0 },//TOP
41 { 0, -1, 0 },//BOTTOM
42 { 0, 0, 1 },//NORTH
43 { 0, 0, -1 },//SOUTH
44 { -1, 0, 0 },//WEST
45 { 1, 0, 0 },//EAST
46 };
47
48 template<typename float_t>
49 [[nodiscard]] constexpr inline math::vec3<float_t> face_coordinate_to_real(unsigned int face,
50 float_t x, float_t y);
51
52 template<typename float_t>
53 [[nodiscard]] constexpr inline Face real_coordinate_to_face(float_t x, float_t y, float_t z);
54
55 namespace build
56 {
57 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
58 [[nodiscard]] bool tesselated(index_t edge_cell_count, floating_t scale, MESH_TEMPLATE *p_mesh);
59
60
61 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
62 [[nodiscard]] bool tesselated_face(Face face, index_t edge_cell_count, floating_t scale,
63 MESH_TEMPLATE *p_mesh);
64 }
65
66 template<typename T>
67 struct rotations_t
68 {
69 constexpr rotations_t() = default;
70 math::matrix<3, 3, T> operator[](Face i) const { return _[i]; }
71 math::matrix<3, 3, T> _[FACE_COUNT];
72 };
73
74 template<typename T>
75 constexpr inline math::matrix<3, 3, T> rotation(Face face);
76
77 template<typename T>
78 constexpr inline rotations_t<T> create_rotations();
79
80 template<typename floating_t>
81 constexpr rotations_t rotations = create_rotations<floating_t>();
82 }
18 enum Face : uint8_t {
19 FACE1 = 0, FACE2 = 1, FACE3 = 2, FACE4 = 3, FACE5 = 4, FACE6 = 5,
20 FACE_COUNT,
21 TOP = FACE1, BOTTOM = FACE2,
22 NORTH = FACE3, SOUTH = FACE4,
23 WEST = FACE5, EAST = FACE6,
24 };
25
26 constexpr static const math::v3f NORMALS[Face::FACE_COUNT] = {
27 { 0, 1, 0 },//TOP
28 { 0, -1, 0 },//BOTTOM
29 { 0, 0, 1 },//NORTH
30 { 0, 0, -1 },//SOUTH
31 { -1, 0, 0 },//WEST
32 { 1, 0, 0 },//EAST
33 };
34
35 template<typename float_t> [[nodiscard]] constexpr inline
36 math::vec3<float_t>
37 face_coordinate_to_real(unsigned int face, float_t x, float_t y);
38
39 template<typename float_t> [[nodiscard]] constexpr inline
40 Face
41 real_coordinate_to_face(float_t x, float_t y, float_t z);
42
43 namespace build {
44 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
45 [[nodiscard]] bool
46 tesselated(index_t edge_cell_count, floating_t scale,
47 MESH_TEMPLATE *p_mesh);
48
49 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
50 [[nodiscard]] bool
51 tesselated_face(Face face, index_t edge_cell_count, floating_t scale,
52 MESH_TEMPLATE *p_mesh);
53 }
54
55 template<typename T>
56 struct rotations_t {
57 constexpr rotations_t() = default;
58 math::matrix<3, 3, T> operator[](Face i) const { return _[i]; }
59 math::matrix<3, 3, T> _[FACE_COUNT];
60 };
61
62 template<typename T> constexpr inline
63 math::matrix<3, 3, T> rotation(Face face);
64
65 template<typename T> constexpr inline
66 rotations_t<T> create_rotations();
67
68 template<typename floating_t> constexpr rotations_t
69 rotations = create_rotations<floating_t>();
83 70 } }
84 71
85 namespace mesh
72 namespace mesh::cube
86 73 { {
87 namespace cube
88 {
89 template<typename float_t>
90 [[nodiscard]] constexpr inline math::vec3<float_t> face_coordinate_to_real(Face face, float_t x, float_t y)
91 { using namespace math; using vec3 = vec3<float_t>;
92
93 switch (face)
94 {
95 case TOP : return vec3 { x, 1, y } - float_t(0.5);
96 case BOTTOM: return vec3 { y, 0, x } - float_t(0.5);
97 case NORTH : return vec3 { y, x, 1 } - float_t(0.5);
98 case SOUTH : return vec3 { x, y, 0 } - float_t(0.5);
99 case WEST : return vec3 { 0, x, y } - float_t(0.5);
100 case EAST :
101 default : return vec3 { 1, y, x } - float_t(0.5);
102 }
103 }
104
105 template<typename T>
106 [[nodiscard]] constexpr inline Face real_coordinate_to_face(T x, T y, T z)
107 {
108 const Face faceX = x >= 0 ? Face::EAST : Face::WEST;
109 const Face faceY = y >= 0 ? Face::TOP : Face::BOTTOM;
110 const Face faceZ = z >= 0 ? Face::NORTH : Face::SOUTH;
111
112 const auto abs_x = std::abs(x);
113 const auto abs_y = std::abs(y);
114 const auto abs_z = std::abs(z);
115 if (abs_x > abs_y)
116 return abs_z > abs_x ? faceZ : faceX;
117 else
118 return abs_z > abs_y ? faceZ : faceY;
119 }
120
121 template<simd::Level level>
122 [[nodiscard]] constexpr inline simd::pint_simd<level> real_coordinate_to_face_simd
123 (
124 simd::pint_simd<level> x,
125 simd::pint_simd<level> y,
126 simd::pint_simd<level> z
127 )
128 {
129 using pi = simd::pint_simd<level>;
130
131 const pi zero = 0;
132 const auto faceX = (x < zero).blendv(pi(EAST), pi(WEST));
133 const auto faceY = (y < zero).blendv(pi(TOP), pi(BOTTOM));
134 const auto faceZ = (z < zero).blendv(pi(NORTH), pi(SOUTH));
135
136 const auto abs_x = x.abs();
137 const auto abs_y = y.abs();
138 const auto abs_z = z.abs();
139
140 const auto faceZX = (abs_z > abs_x).blendv(faceX,faceZ);
141 const auto faceZY = (abs_z > abs_y).blendv(faceY,faceZ);
142 return (abs_x > abs_y).blendv(faceZY,faceZX);
143 }
144
145
146 template<typename T>
147 constexpr inline math::matrix<3, 3, T> rotation(Face face)
148 {
149 if (face == 0)
150 return math::scale<3>(1);
151
152
153 if (face == Face::BOTTOM)
154 {
155 constexpr auto faceN_vert = face_coordinate_to_real(Face::NORTH, T(0.5), T(0.5)) * 2;
156 return math::rotation(faceN_vert, math::radians(T(180)));
157 }
158
159 constexpr auto face0_vert = face_coordinate_to_real(Face(0), T(0.5), T(0.5)) * 2;
160 auto faceX_vert = face_coordinate_to_real(Face(face), T(0.5), T(0.5)) * 2;
161 return math::rotation(math::cross(face0_vert, faceX_vert), angle(face0_vert, faceX_vert));
162 }
163
164 template<typename T>
165 constexpr inline rotations_t<T> create_rotations()
166 {
167 rotations_t<T> r{};
168 for (Face i = Face(0); i < FACE_COUNT; i = Face(i + Face(1)))
169 r._[i] = rotation<T>(i);
170 return r;
171 }
172
173 namespace build
174 {
175 namespace __hiden
176 {
177 template<CONDITION_ARGSF, typename floating_t>
178 using SET_TEX_COORD = void(*)(Face, math::vector<VEC_SIZE<CONDITION_ARGS>, floating_t> &vec,
179 floating_t u, floating_t v);
180
181 namespace set_texture_coordinates
182 {
183 template<CONDITION_ARGSF, typename floating_t>
184 constexpr inline void x1(Face, math::vector<VEC_SIZE<CONDITION_ARGS>, floating_t> &vertex,
185 floating_t u, floating_t v)
186 {
187 if (texture_coord)
188 math::setSubVector<3,2>(vertex, math::vec2<floating_t>{ u, v });
189 }
190
191 template<CONDITION_ARGSF, typename floating_t>
192 constexpr inline void x6(Face face,
193 math::vector<VEC_SIZE<CONDITION_ARGS>, floating_t> &vertex,
194 floating_t u, floating_t v)
195 {
196 if (texture_coord)
197 math::setSubVector<3,2>(vertex, math::vec2<floating_t>(u, (face + v) / 6));
198 }
199 }
200
201
202 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY,
203 SET_TEX_COORD<CONDITION_ARGS, floating_t> set_tex_coord>
204
205 inline void fill_face
206 (
207 Face face,
208 index_t edge_cell_count,
209 floating_t scale,
210 index_t &vertex_index,
211 index_t &index_index,
212 index_t &vertex_indexNextRow,
213 MESH_TEMPLATE *p_mesh
214 )
215 { using namespace math;
216
217 for (index_t x = 0; x <= edge_cell_count; ++x)
218 {
219 floating_t x_ratio = floating_t(x) / edge_cell_count;
220 for (index_t y = 0; y <= edge_cell_count; ++y)
221 {
222 if (y != edge_cell_count && x != edge_cell_count)
223 {
224 p_mesh->indexes[ index_index] = vertex_index;
225 p_mesh->indexes[++index_index] = vertex_index + 1;
226 p_mesh->indexes[++index_index] = ++vertex_indexNextRow;
227 p_mesh->indexes[++index_index] = vertex_indexNextRow;
228 p_mesh->indexes[++index_index] = vertex_indexNextRow - 1;
229 p_mesh->indexes[++index_index] = vertex_index;
230 ++index_index;
231 }
232 else ++vertex_indexNextRow;
233
234 floating_t y_ratio = floating_t(y) / edge_cell_count;
235
236 auto pos = MODIFY(face_coordinate_to_real(face, x_ratio, y_ratio));
237
238 setSubVector<0,3>(p_mesh->vertexes[vertex_index], pos * scale);
239 set_tex_coord(face, p_mesh->vertexes[vertex_index], x_ratio, y_ratio);
240 if (normals)
241 setSubVector<N_OFFSET<texture_coord>,3>(p_mesh->vertexes[vertex_index], NORMALS[face]);
242 ++vertex_index;
243 }
244 }
245 }
246 }
247
248
249
250 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY>
251
252 [[nodiscard]] bool tesselated(index_t edge_cell_count, floating_t scale, MESH_TEMPLATE *p_mesh)
253 {
254 static_assert(std::is_floating_point<floating_t>::value);
74 template<typename float_t> [[nodiscard]] constexpr inline
75 math::vec3<float_t> face_coordinate_to_real(Face face, float_t x, float_t y) {
76 using vec3 = math::vec3<float_t>;
77 switch (face) {
78 case TOP : return vec3 { x, 1, y } - float_t(0.5);
79 case BOTTOM: return vec3 { y, 0, x } - float_t(0.5);
80 case NORTH : return vec3 { y, x, 1 } - float_t(0.5);
81 case SOUTH : return vec3 { x, y, 0 } - float_t(0.5);
82 case WEST : return vec3 { 0, x, y } - float_t(0.5);
83 case EAST :
84 default : return vec3 { 1, y, x } - float_t(0.5);
85 }
86 }
87
88 template<typename T>
89 [[nodiscard]] constexpr inline Face real_coordinate_to_face(T x, T y, T z) {
90 const Face faceX = x >= 0 ? Face::EAST : Face::WEST;
91 const Face faceY = y >= 0 ? Face::TOP : Face::BOTTOM;
92 const Face faceZ = z >= 0 ? Face::NORTH : Face::SOUTH;
93
94 const auto abs_x = std::abs(x);
95 const auto abs_y = std::abs(y);
96 const auto abs_z = std::abs(z);
97 if (abs_x > abs_y)
98 return abs_z > abs_x ? faceZ : faceX;
99 else
100 return abs_z > abs_y ? faceZ : faceY;
101 }
102
103 template<simd::Level level> [[nodiscard]] constexpr inline
104 simd::pint_simd<level> real_coordinate_to_face_simd(
105 simd::pint_simd<level> x,
106 simd::pint_simd<level> y,
107 simd::pint_simd<level> z)
108 {
109 using pi = simd::pint_simd<level>;
110
111 const pi zero = 0;
112
113 const auto faceX = (x < zero).blendv(pi(EAST), pi(WEST));
114 const auto faceY = (y < zero).blendv(pi(TOP), pi(BOTTOM));
115 const auto faceZ = (z < zero).blendv(pi(NORTH), pi(SOUTH));
116
117 const auto abs_x = x.abs();
118 const auto abs_y = y.abs();
119 const auto abs_z = z.abs();
120
121 const auto faceZX = (abs_z > abs_x).blendv(faceX,faceZ);
122 const auto faceZY = (abs_z > abs_y).blendv(faceY,faceZ);
123 return (abs_x > abs_y).blendv(faceZY,faceZX);
124 }
125
126 template<typename T> constexpr inline
127 math::matrix<3, 3, T> rotation(Face face) {
128 if (face == 0)
129 return math::scale<3>(1);
130
131 if (face == Face::BOTTOM) {
132 constexpr auto faceN_vert =
133 face_coordinate_to_real(Face::NORTH, T(0.5), T(0.5)) * 2;
134 return math::rotation(faceN_vert, math::radians(T(180)));
135 }
136
137 constexpr auto face0_vert =
138 face_coordinate_to_real(Face(0), T(0.5), T(0.5)) * 2;
139 auto faceX_vert = face_coordinate_to_real(Face(face), T(0.5), T(0.5)) * 2;
140 return math::rotation(math::cross(face0_vert, faceX_vert),
141 angle(face0_vert, faceX_vert));
142 }
143
144 template<typename T> constexpr inline
145 rotations_t<T> create_rotations() {
146 rotations_t<T> r{};
147 for (Face i = Face(0); i < FACE_COUNT; i = Face(i + Face(1)))
148 r._[i] = rotation<T>(i);
149 return r;
150 }
151 }
152 namespace mesh::cube::build::detail
153 {
154 template<CONDITION_ARGSF, typename floating_t>
155 using SET_TEX_COORD =
156 void(*)(Face, math::vector<VEC_SIZE<CONDITION_ARGS>,
157 floating_t> &vec, floating_t u, floating_t v);
158
159 namespace set_texture_coordinates {
160 template<CONDITION_ARGSF, typename floating_t> constexpr inline
161 void x1(Face, math::vector<VEC_SIZE<CONDITION_ARGS>, floating_t> &vertex,
162 floating_t u, floating_t v) {
163 if (texture_coord)
164 vertex.template part<4,2>() = math::vec2<floating_t>{ u, v };
165 }
166
167 template<CONDITION_ARGSF, typename floating_t> constexpr inline
168 void x6(Face face, math::vector<VEC_SIZE<CONDITION_ARGS>,
169 floating_t> &vertex, floating_t u, floating_t v) {
170 if (texture_coord)
171 vertex.template part<3,2>() = math::vec2<floating_t>(u, (face + v) / 6);
172 }
173 }
174
175
176 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY,
177 SET_TEX_COORD<CONDITION_ARGS, floating_t> set_tex_coord>
178
179 inline
180 void fill_face(
181 Face face,
182 index_t edge_cell_count,
183 floating_t scale,
184 index_t &vertex_index,
185 index_t &index_index,
186 index_t &vertex_indexNextRow,
187 MESH_TEMPLATE *p_mesh)
188 {
189 using namespace math;
190
191 for (index_t x = 0; x <= edge_cell_count; ++x) {
192 floating_t x_ratio = floating_t(x) / edge_cell_count;
193 for (index_t y = 0; y <= edge_cell_count; ++y) {
194 if (y != edge_cell_count && x != edge_cell_count) {
195 p_mesh->indexes[ index_index] = vertex_index;
196 p_mesh->indexes[++index_index] = vertex_index + 1;
197 p_mesh->indexes[++index_index] = ++vertex_indexNextRow;
198 p_mesh->indexes[++index_index] = vertex_indexNextRow;
199 p_mesh->indexes[++index_index] = vertex_indexNextRow - 1;
200 p_mesh->indexes[++index_index] = vertex_index;
201 ++index_index;
202 }
203 else ++vertex_indexNextRow;
204
205 floating_t y_ratio = floating_t(y) / edge_cell_count;
206
207 auto pos = MODIFY(face_coordinate_to_real(face, x_ratio, y_ratio));
208
209 auto &ver = p_mesh->vertexes[vertex_index];
210 ver.template part<0,3> = pos * scale;
211 set_tex_coord(face, ver, x_ratio, y_ratio);
212 if (normals)
213 ver.template part<N_OFFSET<texture_coord>,3> = NORMALS[face];
214
215 ++vertex_index;
216 }
217 }
218 }
219 }
220 namespace mesh::cube::build
221 {
222 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY> [[nodiscard]]
223 bool tesselated(index_t edge_cell_count, floating_t scale,
224 MESH_TEMPLATE *p_mesh)
225 {
226 static_assert(std::is_floating_point<floating_t>::value);
255 227 #ifndef NDEBUG #ifndef NDEBUG
256 size_t _requested_size = size_t((edge_cell_count)) * edge_cell_count * FACE_COUNT * 6;
257 jassert(_requested_size >= std::numeric_limits<index_t>::max(), "index overflow");
228 {
229 size_t size = size_t((edge_cell_count)) * edge_cell_count * FACE_COUNT*6;
230 jassert(size >= std::numeric_limits<index_t>::max(), "index overflow");
231 }
258 232 #endif #endif
259 index_t vertex_count = (edge_cell_count+1) * (edge_cell_count+1) * FACE_COUNT;
260 index_t index_count = (edge_cell_count) * (edge_cell_count) * FACE_COUNT * 6;
261 if (not p_mesh->init(vertex_count, index_count))
262 return false;
263
264 index_t vertexIndex = 0,
265 vertexIndexNextRow = edge_cell_count + 1,
266 indexIndex = 0;
267
268 using namespace __hiden;
269
270 for (Face i = FACE1; i < FACE_COUNT; i = Face(i + 1))
271 {
272 fill_face<ARGS, MODIFY, set_texture_coordinates::x6<CONDITION_ARGS, floating_t>>
273 (
274 i,
275 edge_cell_count,
276 scale,
277 vertexIndex,
278 indexIndex,
279 vertexIndexNextRow,
280 p_mesh
281 );
282 }
283
284 return true;
285 }
286
287
288 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY>
289
290 [[nodiscard]] bool tesselated_face(Face face, index_t edge_cell_count, floating_t scale,
291 MESH_TEMPLATE *p_mesh)
292 {
293 static_assert(std::is_floating_point<floating_t>::value);
294 jassert(size_t((edge_cell_count)) * edge_cell_count * 6 < std::numeric_limits<index_t>::max(),
295 "index_t overflow");
296 jassert(face < FACE_COUNT, "incorrect face");
297
298 index_t vertex_count = (edge_cell_count+1) * (edge_cell_count+1);
299 index_t index_count = (edge_cell_count) * (edge_cell_count) * 6;
300 if (not p_mesh->init(vertex_count, index_count))
301 return false;
302
303 index_t vertexIndex = 0;
304 index_t vertexIndexNextRow = edge_cell_count + 1;
305 index_t indexIndex = 0;
306
307 using namespace __hiden;
308
309 fill_face<ARGS, MODIFY, set_texture_coordinates::x1<CONDITION_ARGS, floating_t>>
310 (
311 face,
312 edge_cell_count,
313 scale,
314 vertexIndex,
315 indexIndex,
316 vertexIndexNextRow,
317 p_mesh
318 );
319
320 return true;
321 }
322 }
323 }
233 index_t vcount = (edge_cell_count+1) * (edge_cell_count+1) * FACE_COUNT;
234 index_t icount = (edge_cell_count) * (edge_cell_count) * FACE_COUNT * 6;
235 if (not p_mesh->init(vcount, icount))
236 return false;
237
238 index_t vIndex = 0, vIndexNextRow = edge_cell_count + 1, iIndex = 0;
239
240 for (Face i = FACE1; i < FACE_COUNT; i = Face(i + 1)) {
241 detail::fill_face<ARGS, MODIFY,
242 detail::set_texture_coordinates::x6<CONDITION_ARGS, floating_t>>
243 (i, edge_cell_count, scale, vIndex, iIndex, vIndexNextRow, p_mesh);
244 }
245 return true;
246 }
247
248
249 template<ARGSF, PF_ModifyVertex<floating_t> MODIFY> [[nodiscard]]
250 bool tesselated_face(Face face, index_t edge_cell_count, floating_t scale,
251 MESH_TEMPLATE *p_mesh) {
252 static_assert(std::is_floating_point<floating_t>::value);
253 jassert(size_t((edge_cell_count)) * edge_cell_count * 6
254 < std::numeric_limits<index_t>::max(),
255 "index_t overflow");
256 jassert(face < FACE_COUNT, "incorrect face");
257
258 index_t vcount = (edge_cell_count+1) * (edge_cell_count+1);
259 index_t icount = (edge_cell_count) * (edge_cell_count) * 6;
260 if (not p_mesh->init(vcount, icount))
261 return false;
262
263 index_t vIndex = 0;
264 index_t vIndexNextRow = edge_cell_count + 1;
265 index_t iIndex = 0;
266
267 detail::fill_face<ARGS, MODIFY,
268 detail::set_texture_coordinates::x1<CONDITION_ARGS, floating_t>>
269 (face, edge_cell_count, scale, vIndex, iIndex, vIndexNextRow, p_mesh);
270
271 return true;
272 }
324 273 } }
325 274
326 275 #undef CONDITION_ARGS #undef CONDITION_ARGS
File libs/mesh/plane.h changed (mode: 100644) (index 27c742f..ad6d5d9)
6 6 #define ARGS texture_coord, normals, floating_t, index_t #define ARGS texture_coord, normals, floating_t, index_t
7 7 #define MESH_TEMPLATE Mesh_T<ARGS> #define MESH_TEMPLATE Mesh_T<ARGS>
8 8
9 namespace mesh
10 {
11 namespace plane
12 {
13 namespace build
14 {
15 TEMPLATE_ARGS
16 [[nodiscard]] bool common(floating_t width, floating_t length, MESH_TEMPLATE *p_mesh);
17
18 TEMPLATE_ARGS
19 [[nodiscard]] bool tesselated(floating_t width, floating_t length,
20 index_t width_cell_count, index_t length_cell_count,
21 MESH_TEMPLATE *p_mesh);
22 }
23 }
24 }
9 namespace mesh::plane::build {
10 TEMPLATE_ARGS [[nodiscard]]
11 bool
12 common(floating_t width, floating_t length, MESH_TEMPLATE *p_mesh);
25 13
14 TEMPLATE_ARGS [[nodiscard]]
15 bool
16 tesselated(floating_t width, floating_t length,
17 index_t width_cell_count, index_t length_cell_count,
18 MESH_TEMPLATE *p_mesh);
26 19
27 namespace mesh
28 {
29 namespace plane
30 {
31 namespace build
32 {
33 template<CONDITION_ARGS, typename floating_t>
34 void set_tex(math::vector<VEC_SIZE<texture_coord, normals>, floating_t> &vertex,
35 floating_t x, floating_t y)
36 {
37 if (texture_coord)
38 math::setSubVector<3,2>(vertex, math::vec2<floating_t>{ x, y });
39 }
20 template<CONDITION_ARGS, typename floating_t>
21 void
22 set_tex(math::vector<VEC_SIZE<texture_coord, normals>, floating_t> &vertex,
23 floating_t x, floating_t y) {
24 if (texture_coord)
25 vertex.template part<3,2>() = math::vec2<floating_t>{ x, y };
26 }
40 27
41 TEMPLATE_ARGS
42 [[nodiscard]] bool common(floating_t width, floating_t length, MESH_TEMPLATE *p_mesh)
43 {
44 static_assert (normals != true, "not implemented");
28 TEMPLATE_ARGS [[nodiscard]]
29 bool
30 common(floating_t width, floating_t length, MESH_TEMPLATE *p_mesh) {
31 static_assert (normals != true, "not implemented");
45 32
33 if (not p_mesh->init(4, 6))
34 return false;
46 35
47 if (not p_mesh->init(4, 6))
48 return false;
36 p_mesh->vertexes[3].template part<0,3>() = { 0, 0 , 0 };
37 p_mesh->vertexes[3].template part<0,3>() = { 0, length, 0 };
38 p_mesh->vertexes[3].template part<0,3>() = { width, 0, 0 };
39 p_mesh->vertexes[3].template part<0,3>() = { width, length, 0 };
49 40
50 math::setSubVector<0,3>(p_mesh->vertexes[0], { 0, 0 , 0 });
51 math::setSubVector<0,3>(p_mesh->vertexes[1], { 0, length, 0 });
52 math::setSubVector<0,3>(p_mesh->vertexes[2], { width, 0, 0 });
53 math::setSubVector<0,3>(p_mesh->vertexes[3], { width, length, 0 });
41 set_tex(p_mesh->vertexes[0], 0, 0);
42 set_tex(p_mesh->vertexes[1], 0, 1);
43 set_tex(p_mesh->vertexes[2], 1, 0);
44 set_tex(p_mesh->vertexes[3], 1, 1);
54 45
55 set_tex(p_mesh->vertexes[0], math::cast<floating_t>(0), math::cast<floating_t>(0));
56 set_tex(p_mesh->vertexes[1], math::cast<floating_t>(0), math::cast<floating_t>(1));
57 set_tex(p_mesh->vertexes[2], math::cast<floating_t>(1), math::cast<floating_t>(0));
58 set_tex(p_mesh->vertexes[3], math::cast<floating_t>(1), math::cast<floating_t>(1));
46 p_mesh->indexes[0] = 0;
47 p_mesh->indexes[1] = 1;
48 p_mesh->indexes[2] = 2;
49 p_mesh->indexes[3] = 3;
50 p_mesh->indexes[4] = 2;
51 p_mesh->indexes[5] = 1;
59 52
60 p_mesh->indexes[0] = 0;
61 p_mesh->indexes[1] = 1;
62 p_mesh->indexes[2] = 2;
63 p_mesh->indexes[3] = 3;
64 p_mesh->indexes[4] = 2;
65 p_mesh->indexes[5] = 1;
53 return true;
54 }
66 55
67 return true;
68 }
69 56 /* /*
70 template<bool tex_coord, typename floating_t, typename index_t> [[nodiscard]]
71 bool tesselated
72 (
73 Mesh_T<tex_coord, floating_t, index_t> &mesh,
74 floating_t width,
75 floating_t length,
76 index_t width_cell_count,
77 index_t length_cell_count
78 )
79 {
80 //TODO
57 template<bool tex_coord, typename floating_t, typename index_t> [[nodiscard]]
58 bool tesselated
59 (
60 Mesh_T<tex_coord, floating_t, index_t> &mesh,
61 floating_t width,
62 floating_t length,
63 index_t width_cell_count,
64 index_t length_cell_count
65 )
66 {
67 //TODO
81 68 #ifndef NDEBUG #ifndef NDEBUG
82 if (size_t(width_cell_count) * size_t(length_cell_count) * 6 >= std::numeric_limits<index_t>::max())
83 error_output("mesh::sphere::build::uv - index_t overflow");
69 if (size_t(width_cell_count) * size_t(length_cell_count) * 6
70 >= std::numeric_limits<index_t>::max())
71 error_output("mesh::sphere::build::uv - index_t overflow");
84 72 #endif #endif
85 index_t vertex_count = (width_cell_count + 1) * (length_cell_count + 1);
86 index_t index_count = width_cell_count * length_cell_count * 6;
87 if (!mesh.init(vertex_count, index_count))
88 return false;
89
90 index_t indexIndex = 0, vertexIndex = 0;
91 index_t vertexIndexNextRow = width_cell_count + 1;
92 float xPos;
93 for(uint32_t x = 0; x < length_cell_count; ++x)
94 {
95 borders.min = math::v3f{} - (scale / 2);
96 borders.max = borders.max + scale;
97 xPos = float(x) / float(length_cell_count);
98 for (uint32_t y = 0; y < width_cell_count; ++y)
99 {
100 mesh.vertexes[vertexIndex] = {xPos, y / float(width_cell_count) };
101
102 mesh.indexes[indexIndex] = vertexIndex;
103 mesh.indexes[++indexIndex] = vertexIndex + 1;
104 mesh.indexes[++indexIndex] = ++vertexIndexNextRow;
105 mesh.indexes[++indexIndex] = vertexIndexNextRow;
106 mesh.indexes[++indexIndex] = vertexIndexNextRow - 1;
107 mesh.indexes[++indexIndex] = vertexIndex;
108 ++indexIndex;
109 ++vertexIndex;
110 }
111 mesh.vertexes[vertexIndex++] = { x / float(length_cell_count), 1 };
112 ++vertexIndexNextRow;
113 }
114 for (uint32_t y = 0; y < width_cell_count; ++y)
115 mesh.vertexes[vertexIndex++] = { 1, y / float(width_cell_count) };
116
117 mesh.vertexes[vertexIndex] = { 1, 1 };
118
119 return true;
120 }*/
121 }
122 }
73 index_t vertex_count = (width_cell_count + 1) * (length_cell_count + 1);
74 index_t index_count = width_cell_count * length_cell_count * 6;
75 if (!mesh.init(vertex_count, index_count))
76 return false;
77
78 index_t indexIndex = 0, vertexIndex = 0;
79 index_t vertexIndexNextRow = width_cell_count + 1;
80 float xPos;
81 for(uint32_t x = 0; x < length_cell_count; ++x)
82 {
83 borders.min = math::v3f{} - (scale / 2);
84 borders.max = borders.max + scale;
85 xPos = float(x) / float(length_cell_count);
86 for (uint32_t y = 0; y < width_cell_count; ++y)
87 {
88 mesh.vertexes[vertexIndex] = {xPos, y / float(width_cell_count) };
89
90 mesh.indexes[indexIndex] = vertexIndex;
91 mesh.indexes[++indexIndex] = vertexIndex + 1;
92 mesh.indexes[++indexIndex] = ++vertexIndexNextRow;
93 mesh.indexes[++indexIndex] = vertexIndexNextRow;
94 mesh.indexes[++indexIndex] = vertexIndexNextRow - 1;
95 mesh.indexes[++indexIndex] = vertexIndex;
96 ++indexIndex;
97 ++vertexIndex;
98 }
99 mesh.vertexes[vertexIndex++] = { x / float(length_cell_count), 1 };
100 ++vertexIndexNextRow;
101 }
102 for (uint32_t y = 0; y < width_cell_count; ++y)
103 mesh.vertexes[vertexIndex++] = { 1, y / float(width_cell_count) };
104
105 mesh.vertexes[vertexIndex] = { 1, 1 };
106
107 return true;
108 }*/
123 109 } }
124 110 #undef CONDITION_ARGS #undef CONDITION_ARGS
125 111 #undef ARGS #undef ARGS
File libs/mesh/polyhedron/icosahedron.h changed (mode: 100644) (index dcbd839..0e80865)
6 6 #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t> #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t>
7 7 #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t> #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t>
8 8
9 namespace mesh
10 {
11 namespace icosahedron
12 {
13 namespace build
14 {
15 TEMPLATE_ARGS
16 [[nodiscard]] inline bool icosahedron(MESH_TEMPLATE *p_mesh);
17 }
18
19 constexpr static const unsigned int FACE_COUNT = 20;
20 constexpr static const unsigned int VERTEX_COUNT = 12;
21 constexpr static const unsigned int INDEX_COUNT = FACE_COUNT * 3;
22
23 TEMPLATE_ARGS
24 struct Icosahedron
25 {
26 constexpr Icosahedron() {}
27
28 constexpr static const floating_t GOLDEN_RATIO = (1 + gcem::sqrt<floating_t>(5)) / 2;
29 constexpr static const floating_t RADIUS_RATIO = floating_t(1.9021130326L);
30 constexpr static const auto VECTOR_SIZE = VEC_SIZE<texture_coord, normals>;
31
32 constexpr static const floating_t ANGLE_NEIGHBOUR_VERTICES = angle({ -1, GOLDEN_RATIO, 0 },
33 { 1, GOLDEN_RATIO, 0 });
34
35 using vertex = math::vector<VECTOR_SIZE, floating_t>;
36
37 struct vertices
38 {
39 constexpr vertices() = default;
40 constexpr static index_t COUNT = VERTEX_COUNT;
41
42 vertex operator[](index_t i) const { return _[i]; }
43 vertex _[COUNT];
44 };
45
46 constexpr static vertices create_vertices()
47 {
48 struct vertices result{};
49 constexpr math::vec3<floating_t> array[vertices::COUNT] =
50 {
51 math::vec3<floating_t> { -1, GOLDEN_RATIO, 0 }.normalize(),
52 math::vec3<floating_t> { 1, GOLDEN_RATIO, 0 }.normalize(),
53 math::vec3<floating_t> { -1, -GOLDEN_RATIO, 0 }.normalize(),
54 math::vec3<floating_t> { 1, -GOLDEN_RATIO, 0 }.normalize(),
55
56 math::vec3<floating_t> { 0, -1, GOLDEN_RATIO }.normalize(),
57 math::vec3<floating_t> { 0, 1, GOLDEN_RATIO }.normalize(),
58 math::vec3<floating_t> { 0, -1, -GOLDEN_RATIO }.normalize(),
59 math::vec3<floating_t> { 0, 1, -GOLDEN_RATIO }.normalize(),
60
61 math::vec3<floating_t> { GOLDEN_RATIO, 0, -1 }.normalize(),
62 math::vec3<floating_t> { GOLDEN_RATIO, 0, 1 }.normalize(),
63 math::vec3<floating_t> { -GOLDEN_RATIO, 0, -1 }.normalize(),
64 math::vec3<floating_t> { -GOLDEN_RATIO, 0, 1 }.normalize()
65 };
66 for (uint_fast8_t i = 0; i < vertices::COUNT; ++i)
67 {
68 math::setSubVector<0,3>(result._[i], array[i]);
69 if (texture_coord)
70 math::setSubVector<3,2>(result._[i], __texture_coordinates::uv(array[i]));
71 if (normals)
72 math::setSubVector<N_OFFSET<texture_coord>,3>(result._[i], array[i]);
73 }
74 return result;
75 }
76 static_assert (vertices()._[0][0] != -1);
77
78 struct indices
79 {
80 constexpr indices() = default;
81 constexpr static index_t COUNT = INDEX_COUNT;
82
83 index_t operator[](index_t i) const { return _[i]; }
84
85 index_t _[COUNT];
86 };
87 constexpr static indices create_indices()
88 {
89 struct indices result{};
90 index_t array[indices::COUNT] =
91 {
92 0, 11, 5,
93 0, 5, 1,
94 0, 1, 7,
95 0, 7, 10,
96 0, 10, 11,
97
98 1, 5, 9,
99 5, 11, 4,
100 11, 10, 2,
101 10, 7, 6,
102 7, 1, 8,
103
104 3, 9, 4,
105 3, 4, 2,
106 3, 2, 6,
107 3, 6, 8,
108 3, 8, 9,
109
110 4, 9, 5,
111 2, 4, 11,
112 6, 2, 10,
113 8, 6, 7,
114 9, 8, 1
115 };
116 for (uint_fast8_t i = 0; i < indices::COUNT; ++i)
117 result._[i] = array[i];
118 return result;
119 }
120
121 constexpr static vertices vertice = create_vertices();
122 constexpr static indices indice = create_indices();
123 };
124
125 TEMPLATE_ARGS
126 constexpr static const Icosahedron<texture_coord, normals, floating_t, index_t> pre_compiled{};
127
128 namespace build
129 {
130 TEMPLATE_ARGS
131 [[nodiscard]] inline bool icosahedron(MESH_TEMPLATE *p_mesh)
132 {
133 using Icosahedron = Icosahedron<texture_coord, normals, floating_t, index_t>;
134
135 if (not p_mesh->init(Icosahedron::vertices::COUNT, Icosahedron::indices::COUNT))
136 return false;
137
138 constexpr Icosahedron icosahedron_data{};
139
140 index_t size = Icosahedron::vertices::COUNT * sizeof (Icosahedron::vector);
141
142 memcpy(p_mesh->vertexes.p_array, &icosahedron_data.vertices, size);
143
144
145 size = Icosahedron::indices::COUNT * sizeof (index_t);
146
147 memcpy(p_mesh->indexes.p_array, &icosahedron_data.indices, size);
148
149 return true;
150 }
151 }
152 }
9 namespace mesh::icosahedron::build {
10 TEMPLATE_ARGS
11 [[nodiscard]] inline bool icosahedron(MESH_TEMPLATE *p_mesh);
12 }
13 namespace mesh::icosahedron {
14 constexpr static const unsigned int FACE_COUNT = 20;
15 constexpr static const unsigned int VERTEX_COUNT = 12;
16 constexpr static const unsigned int INDEX_COUNT = FACE_COUNT * 3;
17
18 TEMPLATE_ARGS
19 struct Icosahedron
20 {
21 constexpr Icosahedron() {}
22
23 constexpr static const
24 floating_t GOLDEN_RATIO = (1 + gcem::sqrt<floating_t>(5)) / 2;
25 constexpr static const
26 floating_t RADIUS_RATIO = floating_t(1.9021130326L);
27 constexpr static const
28 auto VECTOR_SIZE = VEC_SIZE<texture_coord, normals>;
29
30 constexpr static const
31 floating_t ANGLE_NEIGHBOUR_VERTICES =
32 angle({ -1, GOLDEN_RATIO, 0 }, { 1, GOLDEN_RATIO, 0 });
33
34 using vertex = math::vector<VECTOR_SIZE, floating_t>;
35
36 struct vertices {
37 constexpr vertices() = default;
38 constexpr static index_t COUNT = VERTEX_COUNT;
39
40 vertex operator[](index_t i) const { return _[i]; }
41 vertex _[COUNT];
42 };
43
44 constexpr static vertices create_vertices()
45 {
46 struct vertices result{};
47 constexpr math::vec3<floating_t> array[vertices::COUNT] =
48 {
49 math::vec3<floating_t> { -1, GOLDEN_RATIO, 0 }.normalize(),
50 math::vec3<floating_t> { 1, GOLDEN_RATIO, 0 }.normalize(),
51 math::vec3<floating_t> { -1, -GOLDEN_RATIO, 0 }.normalize(),
52 math::vec3<floating_t> { 1, -GOLDEN_RATIO, 0 }.normalize(),
53
54 math::vec3<floating_t> { 0, -1, GOLDEN_RATIO }.normalize(),
55 math::vec3<floating_t> { 0, 1, GOLDEN_RATIO }.normalize(),
56 math::vec3<floating_t> { 0, -1, -GOLDEN_RATIO }.normalize(),
57 math::vec3<floating_t> { 0, 1, -GOLDEN_RATIO }.normalize(),
58
59 math::vec3<floating_t> { GOLDEN_RATIO, 0, -1 }.normalize(),
60 math::vec3<floating_t> { GOLDEN_RATIO, 0, 1 }.normalize(),
61 math::vec3<floating_t> { -GOLDEN_RATIO, 0, -1 }.normalize(),
62 math::vec3<floating_t> { -GOLDEN_RATIO, 0, 1 }.normalize()
63 };
64 for (uint_fast8_t i = 0; i < vertices::COUNT; ++i) {
65 result._[i].template part<0,3>() = array[i];
66 if (texture_coord)
67 result._[i].template part<3,2>() =
68 detail::texture_coordinates::uv(array[i]);
69 if (normals)
70 result._[i].template part<N_OFFSET<texture_coord>,3>() = array[i];
71 }
72 return result;
73 }
74 static_assert (vertices()._[0][0] != -1);
75
76 struct indices {
77 constexpr indices() = default;
78 constexpr static index_t COUNT = INDEX_COUNT;
79
80 index_t operator[](index_t i) const { return _[i]; }
81
82 index_t _[COUNT];
83 };
84 constexpr static indices create_indices() {
85 struct indices result{};
86 index_t array[indices::COUNT] =
87 {
88 0, 11, 5,
89 0, 5, 1,
90 0, 1, 7,
91 0, 7, 10,
92 0, 10, 11,
93
94 1, 5, 9,
95 5, 11, 4,
96 11, 10, 2,
97 10, 7, 6,
98 7, 1, 8,
99
100 3, 9, 4,
101 3, 4, 2,
102 3, 2, 6,
103 3, 6, 8,
104 3, 8, 9,
105
106 4, 9, 5,
107 2, 4, 11,
108 6, 2, 10,
109 8, 6, 7,
110 9, 8, 1
111 };
112 for (uint_fast8_t i = 0; i < indices::COUNT; ++i)
113 result._[i] = array[i];
114 return result;
115 }
116
117 constexpr static vertices vertice = create_vertices();
118 constexpr static indices indice = create_indices();
119 };
120
121 TEMPLATE_ARGS
122 constexpr static const
123 Icosahedron<texture_coord, normals, floating_t, index_t> pre_compiled{};
124 }
125 namespace mesh::icosahedron::build {
126 TEMPLATE_ARGS
127 [[nodiscard]] inline bool icosahedron(MESH_TEMPLATE *p_mesh) {
128 using IH = Icosahedron<texture_coord,normals, floating_t, index_t>;
129
130 if (not p_mesh->init(IH::vertices::COUNT, IH::indices::COUNT))
131 return false;
132
133 constexpr IH icosahedron_data{};
134 index_t size = IH::vertices::COUNT * sizeof (IH::vector);
135 memcpy(p_mesh->vertexes.p_array, &icosahedron_data.vertices, size);
136 size = IH::indices::COUNT * sizeof (index_t);
137 memcpy(p_mesh->indexes.p_array, &icosahedron_data.indices, size);
138 return true;
139 }
153 140 } }
154 141
155 142 #undef TEMPLATE_ARGS #undef TEMPLATE_ARGS
File libs/mesh/polyhedron/icosahedron_quad.h changed (mode: 100644) (index a008c42..71e6f6a)
6 6 #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t> #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t>
7 7 #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t> #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t>
8 8
9 namespace mesh
9 namespace mesh::icosahedron_quad
10 10 { {
11 namespace icosahedron_quad
12 {
13 constexpr static const unsigned int COUNT = 10;
14
15 template<typename floating_t = float, typename index_t = uint16_t>
16 struct Quad
17 {
18 constexpr static const floating_t phi = math::golden_ratio<floating_t>;
19
20 constexpr static const index_t VERTEX_COUNT = 4;
21 constexpr static const index_t INDEX_COUNT = 6;
22
23 constexpr static const floating_t ANGLE_NEIGHBOUR_VERTICES = math::angle<floating_t>({ -1, phi, 0 },
24 { 1, phi, 0 });
25 constexpr static const floating_t EDGE_LENGTH = gcem::sin(math::pi2<floating_t> / floating_t(5));
26
27 math::vec3<floating_t> vertices[VERTEX_COUNT];
28 index_t indices[INDEX_COUNT];
29
30 constexpr static const math::vec2<floating_t> TEXTURE_COORDINATES[VERTEX_COUNT] = { {0, 0}, {1, 0},
31 {0, 1}, {1, 1} };
32 };
33
34 template<typename floating_t>
35
36 constexpr static const math::vec3<floating_t> vertices[12] =
37 {
38 math::vec3<floating_t> { -1, Quad<floating_t>::phi, 0 }.normalize(),
39 math::vec3<floating_t> { 1, Quad<floating_t>::phi, 0 }.normalize(),
40 math::vec3<floating_t> { -1, -Quad<floating_t>::phi, 0 }.normalize(),
41 math::vec3<floating_t> { 1, -Quad<floating_t>::phi, 0 }.normalize(),
42
43 math::vec3<floating_t> { 0, -1, Quad<floating_t>::phi }.normalize(),
44 math::vec3<floating_t> { 0, 1, Quad<floating_t>::phi }.normalize(),
45 math::vec3<floating_t> { 0, -1, -Quad<floating_t>::phi }.normalize(),
46 math::vec3<floating_t> { 0, 1, -Quad<floating_t>::phi }.normalize(),
47
48 math::vec3<floating_t> { Quad<floating_t>::phi, 0, -1 }.normalize(),
49 math::vec3<floating_t> { Quad<floating_t>::phi, 0, 1 }.normalize(),
50 math::vec3<floating_t> { -Quad<floating_t>::phi, 0, -1 }.normalize(),
51 math::vec3<floating_t> { -Quad<floating_t>::phi, 0, 1 }.normalize(),
52 };
53 template<typename index_t>
54 constexpr static const index_t indices[Quad<>::INDEX_COUNT] = { 0, 1, 2, 2, 1, 3 };
11 constexpr static const unsigned int COUNT = 10;
12
13 template<typename floating_t = float, typename index_t = uint16_t>
14 struct Quad
15 {
16 constexpr static const floating_t phi = math::golden_ratio<floating_t>;
17
18 constexpr static const index_t VERTEX_COUNT = 4;
19 constexpr static const index_t INDEX_COUNT = 6;
20
21 constexpr static const
22 floating_t ANGLE_NEIGHBOUR_VERTICES = math::angle<floating_t>(
23 { -1, phi, 0 }, { 1, phi, 0 }
24 );
25 constexpr static const
26 floating_t EDGE_LENGTH = gcem::sin(math::pi2<floating_t> / floating_t(5));
27
28 math::vec3<floating_t> vertices[VERTEX_COUNT];
29 index_t indices[INDEX_COUNT];
30
31 constexpr static const
32 math::vec2<floating_t> TEXTURE_COORDINATES[VERTEX_COUNT] = {
33 {0, 0}, {1, 0}, {0, 1}, {1, 1}
34 };
35 };
36
37 template<typename floating_t>
38 constexpr static const math::vec3<floating_t> vertices[12] = {
39 math::vec3<floating_t> { -1, Quad<floating_t>::phi, 0 }.normalize(),
40 math::vec3<floating_t> { 1, Quad<floating_t>::phi, 0 }.normalize(),
41 math::vec3<floating_t> { -1, -Quad<floating_t>::phi, 0 }.normalize(),
42 math::vec3<floating_t> { 1, -Quad<floating_t>::phi, 0 }.normalize(),
43
44 math::vec3<floating_t> { 0, -1, Quad<floating_t>::phi }.normalize(),
45 math::vec3<floating_t> { 0, 1, Quad<floating_t>::phi }.normalize(),
46 math::vec3<floating_t> { 0, -1, -Quad<floating_t>::phi }.normalize(),
47 math::vec3<floating_t> { 0, 1, -Quad<floating_t>::phi }.normalize(),
48
49 math::vec3<floating_t> { Quad<floating_t>::phi, 0, -1 }.normalize(),
50 math::vec3<floating_t> { Quad<floating_t>::phi, 0, 1 }.normalize(),
51 math::vec3<floating_t> { -Quad<floating_t>::phi, 0, -1 }.normalize(),
52 math::vec3<floating_t> { -Quad<floating_t>::phi, 0, 1 }.normalize(),
53 };
54
55 template<typename index_t>
56 constexpr static const
57 index_t indices[Quad<>::INDEX_COUNT] = { 0, 1, 2, 2, 1, 3 };
55 58
56 59
57 60 #define VERTICES(i1,i2,i3,i4) { vertices<floating_t>[i1], vertices<floating_t>[i2], \ #define VERTICES(i1,i2,i3,i4) { vertices<floating_t>[i1], vertices<floating_t>[i2], \
 
... ... namespace mesh
61 64 indices<index_t>[2], indices<index_t>[3], \ indices<index_t>[2], indices<index_t>[3], \
62 65 indices<index_t>[4], indices<index_t>[5] } indices<index_t>[4], indices<index_t>[5] }
63 66
64 template<typename floating_t, typename index_t = uint16_t>
65 constexpr static const Quad<floating_t, index_t> quads[COUNT] =
66 {
67
68 { .vertices = VERTICES(0, 11, 5, 4), .indices = INDICES }, //0
69 { .vertices = VERTICES(0, 5, 1, 9), .indices = INDICES },
70 { .vertices = VERTICES(0, 1, 7, 8), .indices = INDICES }, //2
71 { .vertices = VERTICES(0, 7, 10, 6), .indices = INDICES },
72 { .vertices = VERTICES(0, 10, 11, 2), .indices = INDICES }, //4
73 { .vertices = VERTICES(5, 4, 9, 3), .indices = INDICES },
74 { .vertices = VERTICES(1, 9, 8, 3), .indices = INDICES }, //6
75 { .vertices = VERTICES(7, 8, 6, 3), .indices = INDICES },
76 { .vertices = VERTICES(10, 6, 2, 3), .indices = INDICES }, //8
77 { .vertices = VERTICES(11, 2, 4, 3), .indices = INDICES }
78 };
67 template<typename floating_t, typename index_t = uint16_t>
68 constexpr static const Quad<floating_t, index_t> quads[COUNT] = {
69 { .vertices = VERTICES(0, 11, 5, 4), .indices = INDICES }, //0
70 { .vertices = VERTICES(0, 5, 1, 9), .indices = INDICES },
71 { .vertices = VERTICES(0, 1, 7, 8), .indices = INDICES }, //2
72 { .vertices = VERTICES(0, 7, 10, 6), .indices = INDICES },
73 { .vertices = VERTICES(0, 10, 11, 2), .indices = INDICES }, //4
74 { .vertices = VERTICES(5, 4, 9, 3), .indices = INDICES },
75 { .vertices = VERTICES(1, 9, 8, 3), .indices = INDICES }, //6
76 { .vertices = VERTICES(7, 8, 6, 3), .indices = INDICES },
77 { .vertices = VERTICES(10, 6, 2, 3), .indices = INDICES }, //8
78 { .vertices = VERTICES(11, 2, 4, 3), .indices = INDICES }
79 };
79 80
80 81 #undef VERTICES #undef VERTICES
81 82 #undef INDICES #undef INDICES
82 83
83 84 #define VERTICE(quad_i, ver_i) quads<floating_t>[quad_i].vertices[ver_i] #define VERTICE(quad_i, ver_i) quads<floating_t>[quad_i].vertices[ver_i]
84 85
85 template<typename floating_t>
86 constexpr static const math::vec3<floating_t> quads_diagonal[COUNT] =
87 {
88 VERTICE(0,3) - VERTICE(0,0),
89 VERTICE(1,3) - VERTICE(1,0),
90 VERTICE(2,3) - VERTICE(2,0),
91 VERTICE(3,3) - VERTICE(3,0),
92 VERTICE(4,3) - VERTICE(4,0),
93 VERTICE(5,3) - VERTICE(5,0),
94 VERTICE(6,3) - VERTICE(6,0),
95 VERTICE(7,3) - VERTICE(7,0),
96 VERTICE(8,3) - VERTICE(8,0),
97 VERTICE(9,3) - VERTICE(9,0),
98 };
99
100 template<typename floating_t>
101 constexpr static const math::vec3<floating_t> quads_horizontal[COUNT] =
102 {
103 VERTICE(0,2) - VERTICE(0,1),
104 VERTICE(1,2) - VERTICE(1,1),
105 VERTICE(2,2) - VERTICE(2,1),
106 VERTICE(3,2) - VERTICE(3,1),
107 VERTICE(4,2) - VERTICE(4,1),
108 VERTICE(5,2) - VERTICE(5,1),
109 VERTICE(6,2) - VERTICE(6,1),
110 VERTICE(7,2) - VERTICE(7,1),
111 VERTICE(8,2) - VERTICE(8,1),
112 VERTICE(9,2) - VERTICE(9,1),
113 };
114
115 template<typename floating_t>
116 constexpr static const math::vec3<floating_t> quads_height[COUNT] = //vector - diff between top and bottom
117 {
118 medium(VERTICE(0,1), VERTICE(0,2)) - medium(VERTICE(0,0), VERTICE(0,3)),
119 medium(VERTICE(1,1), VERTICE(1,2)) - medium(VERTICE(1,0), VERTICE(1,3)),
120 medium(VERTICE(2,1), VERTICE(2,2)) - medium(VERTICE(2,0), VERTICE(2,3)),
121 medium(VERTICE(3,1), VERTICE(3,2)) - medium(VERTICE(3,0), VERTICE(3,3)),
122 medium(VERTICE(4,1), VERTICE(4,2)) - medium(VERTICE(4,0), VERTICE(4,3)),
123 medium(VERTICE(5,1), VERTICE(5,2)) - medium(VERTICE(5,0), VERTICE(5,3)),
124 medium(VERTICE(6,1), VERTICE(6,2)) - medium(VERTICE(6,0), VERTICE(6,3)),
125 medium(VERTICE(7,1), VERTICE(7,2)) - medium(VERTICE(7,0), VERTICE(7,3)),
126 medium(VERTICE(8,1), VERTICE(8,2)) - medium(VERTICE(8,0), VERTICE(8,3)),
127 medium(VERTICE(9,1), VERTICE(9,2)) - medium(VERTICE(9,0), VERTICE(9,3))
128 };
129
130 namespace build
131 {
132 TEMPLATE_ARGS
133
134 [[nodiscard]] bool quad(unsigned int quad_index, MESH_TEMPLATE *p_mesh)
135 {
136 using namespace math;
137 using quad = icosahedron_quad::Quad<floating_t, index_t>;
138 auto &quads_ = quads<floating_t, index_t>;
139
140 if (not p_mesh->init(quad::VERTEX_COUNT, quad::INDEX_COUNT))
141 return false;
142
143 auto &vertices = quads_[quad_index].vertices;
144 for (index_t i = 0; i < quad::VERTEX_COUNT; ++i)
145 {
146 setSubVector<0,3>(p_mesh->vertexes[i], vertices[i]);
147 if (texture_coord)
148 setSubVector<3,2>(p_mesh->vertexes[i], quad::TEXTURE_COORDINATES[i]);
149 if (normals)
150 setSubVector<N_OFFSET<texture_coord>,3>(p_mesh->vertexes[i], vertices[i]);
151 }
152 memcpy(p_mesh->indexes.p_array, quads_[quad_index].indices, sizeof (index_t) * quad::INDEX_COUNT);
153
154 return true;
155 }
156 }
157
158 template<typename T>
159 struct rotations_t
160 {
161 constexpr rotations_t() = default;
162 math::matrix<3, 3, T> operator[](unsigned int i) const { return _[i]; }
163 math::matrix<3, 3, T> _[COUNT];
164 };
165
166 template<typename T>
167 constexpr math::matrix<3, 3, T> rotation(unsigned int quad_index)
168 {
169 using namespace math;
170
171 constexpr auto HALF_OF_COUNT = COUNT / 2;
172 constexpr T single_angle = pi2<T> / T(HALF_OF_COUNT);
173 if (quad_index < HALF_OF_COUNT)
174 {
175 T angle = - T(quad_index) * single_angle;
176 return rotation(vertices<T>[0], angle);
177 }
178 else
179 {
180 constexpr auto& t = quads<T>[0].vertices[3];
181 constexpr auto& b = quads<T>[5].vertices[3];
182 constexpr T second_half_angle = angle(t,b);
183 constexpr auto unit = cross(b,t).normalize();
184
185 T angle = single_angle * (T(HALF_OF_COUNT-1 - quad_index) - half<T>);
186 return rotation(vertices<T>[0], angle) * rotation(unit, second_half_angle);
187 }
188 }
189
190 template<typename T> constexpr
191 rotations_t<T> create_rotations()
192 {
193 rotations_t<T> r{};
194 for (unsigned int i = 0; i < COUNT; ++i)
195 r._[i] = rotation<T>(i);
196 return r;
197 }
198 template<typename floating_t>
199 constexpr rotations_t rotations = create_rotations<floating_t>();
200 }
86 template<typename floating_t>
87 constexpr static const math::vec3<floating_t> quads_diagonal[COUNT] =
88 {
89 VERTICE(0,3) - VERTICE(0,0),
90 VERTICE(1,3) - VERTICE(1,0),
91 VERTICE(2,3) - VERTICE(2,0),
92 VERTICE(3,3) - VERTICE(3,0),
93 VERTICE(4,3) - VERTICE(4,0),
94 VERTICE(5,3) - VERTICE(5,0),
95 VERTICE(6,3) - VERTICE(6,0),
96 VERTICE(7,3) - VERTICE(7,0),
97 VERTICE(8,3) - VERTICE(8,0),
98 VERTICE(9,3) - VERTICE(9,0),
99 };
100
101 template<typename floating_t>
102 constexpr static const math::vec3<floating_t> quads_horizontal[COUNT] =
103 {
104 VERTICE(0,2) - VERTICE(0,1),
105 VERTICE(1,2) - VERTICE(1,1),
106 VERTICE(2,2) - VERTICE(2,1),
107 VERTICE(3,2) - VERTICE(3,1),
108 VERTICE(4,2) - VERTICE(4,1),
109 VERTICE(5,2) - VERTICE(5,1),
110 VERTICE(6,2) - VERTICE(6,1),
111 VERTICE(7,2) - VERTICE(7,1),
112 VERTICE(8,2) - VERTICE(8,1),
113 VERTICE(9,2) - VERTICE(9,1),
114 };
115
116 template<typename floating_t>
117 //vector - diff between top and bottom
118 constexpr static const math::vec3<floating_t> quads_height[COUNT] = {
119 medium(VERTICE(0,1), VERTICE(0,2)) - medium(VERTICE(0,0), VERTICE(0,3)),
120 medium(VERTICE(1,1), VERTICE(1,2)) - medium(VERTICE(1,0), VERTICE(1,3)),
121 medium(VERTICE(2,1), VERTICE(2,2)) - medium(VERTICE(2,0), VERTICE(2,3)),
122 medium(VERTICE(3,1), VERTICE(3,2)) - medium(VERTICE(3,0), VERTICE(3,3)),
123 medium(VERTICE(4,1), VERTICE(4,2)) - medium(VERTICE(4,0), VERTICE(4,3)),
124 medium(VERTICE(5,1), VERTICE(5,2)) - medium(VERTICE(5,0), VERTICE(5,3)),
125 medium(VERTICE(6,1), VERTICE(6,2)) - medium(VERTICE(6,0), VERTICE(6,3)),
126 medium(VERTICE(7,1), VERTICE(7,2)) - medium(VERTICE(7,0), VERTICE(7,3)),
127 medium(VERTICE(8,1), VERTICE(8,2)) - medium(VERTICE(8,0), VERTICE(8,3)),
128 medium(VERTICE(9,1), VERTICE(9,2)) - medium(VERTICE(9,0), VERTICE(9,3))
129 };
130 }
131 namespace mesh::icosahedron_quad::build
132 {
133 TEMPLATE_ARGS [[nodiscard]]
134 bool
135 quad(unsigned int quad_index, MESH_TEMPLATE *p_mesh) {
136 using quad = icosahedron_quad::Quad<floating_t, index_t>;
137 auto &quads_ = quads<floating_t, index_t>;
138
139 if (not p_mesh->init(quad::VERTEX_COUNT, quad::INDEX_COUNT))
140 return false;
141
142 auto &vertices = quads_[quad_index].vertices;
143 for (index_t i = 0; i < quad::VERTEX_COUNT; ++i) {
144 p_mesh->vertexes[i].template part<0,3>() = vertices[i];
145 if (texture_coord)
146 p_mesh->vertexes[i].template part<3,2>() = quad::TEXTURE_COORDINATES[i];
147 if (normals)
148 p_mesh->vertexes[i].template part<N_OFFSET<texture_coord>,3>()
149 = vertices[i];
150 }
151 memcpy(p_mesh->indexes.p_array, quads_[quad_index].indices,
152 sizeof(index_t) * quad::INDEX_COUNT);
153 return true;
154 }
155 }
156 namespace mesh::icosahedron_quad
157 {
158 template<typename T> struct rotations_t {
159 constexpr rotations_t() = default;
160 math::matrix<3, 3, T> operator[](unsigned int i) const { return _[i]; }
161 math::matrix<3, 3, T> _[COUNT];
162 };
163
164 template<typename T> constexpr
165 math::matrix<3, 3, T>
166 rotation(unsigned int quad_index) {
167 constexpr auto HALF_OF_COUNT = COUNT / 2;
168 constexpr T single_angle = math::pi2<T> / T(HALF_OF_COUNT);
169 if (quad_index < HALF_OF_COUNT) {
170 T angle = - T(quad_index) * single_angle;
171 return rotation(vertices<T>[0], angle);
172 }
173 else {
174 constexpr auto& t = quads<T>[0].vertices[3];
175 constexpr auto& b = quads<T>[5].vertices[3];
176 constexpr T second_half_angle = angle(t,b);
177 constexpr auto unit = cross(b,t).normalize();
178
179 T angle = single_angle
180 * (T(HALF_OF_COUNT-1 - quad_index) - math::half<T>);
181 return rotation(vertices<T>[0], angle)
182 * rotation(unit, second_half_angle);
183 }
184 }
185
186 template<typename T> constexpr
187 rotations_t<T>
188 create_rotations() {
189 rotations_t<T> r{};
190 for (unsigned int i = 0; i < COUNT; ++i)
191 r._[i] = rotation<T>(i);
192 return r;
193 }
194
195 template<typename floating_t> constexpr
196 rotations_t rotations = create_rotations<floating_t>();
201 197 } }
202 198
203 199 #undef TEMPLATE_ARGS #undef TEMPLATE_ARGS
File libs/mesh/polyhedron/icosahedron_quad_tesselated.h changed (mode: 100644) (index 4adb861..0a2bf24)
1 1 #pragma once #pragma once
2 2 #include "icosahedron_quad.h" #include "icosahedron_quad.h"
3 3
4 #include "../../simd/simd.h"
4 #include <simd/simd.h>
5 #include <templates/tree/red_black_key.h>
5 6
6 7 #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t> #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t>
7 8 #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t> #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t>
8 9
9 namespace mesh
10 namespace mesh::icosahedron_quad::QuadTesselated
10 11 { {
11 namespace icosahedron_quad
12 {
13 namespace QuadTesselated
14 {
15 constexpr static const unsigned int SUBDIVISIONS_MAX = 6;
16
17 template<typename index_t>
18 constexpr static index_t index_count(unsigned int subdivision_count)
19 {
20 index_t index_count = 6;
21 for (unsigned int i = 0; i < subdivision_count; ++i)
22 index_count *= 4;
23 return index_count;
24 };
25
26 template<typename index_t>
27 constexpr static const index_t VERTEX_COUNT[SUBDIVISIONS_MAX+1]
28 {
29 4, 9, 25, 81, 289, 1089, 4225
30 };
31 }
32
33 template<typename T>
34 using floating_check = typename std::enable_if<std::is_floating_point<T>::value, math::vec3<T>>::type;
35
36
37 template<typename T>
38 [[nodiscard]] constexpr inline floating_check<T> quad_coordinate_to_real
39 (
40 unsigned int quad_i,
41
42 T u,
43 T v
44 )
45 { using namespace math;
46
47 T diagonal_ratio_2 = (u + v);
48 T horizontal_ratio = (v - u) / two<T>;
49
50 T up_ratio = diagonal_ratio_2 > one<T>
51 ? 2 - diagonal_ratio_2
52 : up_ratio = diagonal_ratio_2;
53
54 auto dH = quads_horizontal<T>[quad_i] * horizontal_ratio;
55 auto dD = quads_diagonal <T>[quad_i] * diagonal_ratio_2 / two<T>;
56 auto dUP = quads_height <T>[quad_i] * up_ratio;
57 return normalize(quads<T>[quad_i].vertices[0] + dH + dD + dUP);
58 }
59
60
61 template<simd::Level l>
62 [[nodiscard]] inline math::vec3<simd::pfloat_simd<l>>
63 quad_coordinate_to_real
64 (
65 unsigned int quad_i,
66
67 simd::pfloat_simd<l> u,
68 simd::pfloat_simd<l> v
69 )
70 { using namespace math; using namespace simd; using pf = simd::pfloat_simd<l>;
71
72 pf diagonal_ratio_x2 = (u + v);
73 pf horizontal_ratio = (v - u) / pf(2.f);
74
75 pf up_ratio = (pf(1.f) < diagonal_ratio_x2).blendv(diagonal_ratio_x2, pf(2.f) - diagonal_ratio_x2);
76
77 auto horizontal = quads_horizontal<float>[quad_i];
78 auto diagonal = quads_diagonal <float>[quad_i];
79 auto up = quads_height <float>[quad_i];
80 auto main = quads <float>[quad_i].vertices[0];
81
82 pf diagonal_ratio = diagonal_ratio_x2 / pf(2.f);
83
84 pf x = pf(main.x) + pf(up.x) * up_ratio
85 + pf(diagonal.x) * diagonal_ratio
86 + pf(horizontal.x) * horizontal_ratio;
87
88 pf y = pf(main.y) + pf(up.y) * up_ratio
89 + pf(diagonal.y) * diagonal_ratio
90 + pf(horizontal.y) * horizontal_ratio;
91
92 pf z = pf(main.z) + pf(up.z) * up_ratio
93 + pf(diagonal.z) * diagonal_ratio
94 + pf(horizontal.z) * horizontal_ratio;
95
96 pf rsqrtdot = (x * x + y * y + z * z).rsqrt();
97 return vec3<pf>{x * rsqrtdot,y * rsqrtdot,z * rsqrtdot};
98 }
99
100 namespace build
101 {
102 namespace __hiden
103 {
104 template<unsigned int vec_size, typename floating_t>
105 [[nodiscard]] constexpr inline math::vector<vec_size, floating_t> middle_vertex
106 (
107 math::vector<vec_size, floating_t> vertex1,
108 math::vector<vec_size, floating_t> vertex2
109 )
110 { using namespace math;
111
112 auto result = medium(vertex1, vertex2);
113
114 setSubVector<0,3>(result, normalize(subVector<0,3>(result)));
115
116 return result;
117 }
118 }
119
120 TEMPLATE_ARGS
121 [[nodiscard]] bool quad_tesselated(unsigned int quad_index, unsigned int subdivision_count,
122 MESH_TEMPLATE *p_mesh)
123 {
124 using namespace math; using namespace __hiden;
125 using quad = icosahedron_quad::Quad<floating_t, index_t>;
126 const auto &quads_ = quads<floating_t, index_t>;
127 void(*TREE_CB)(index_t, int) = [] (index_t, int) { jabort_release("duplicates must not exist"); };
128
129 jassert (subdivision_count <= QuadTesselated::SUBDIVISIONS_MAX, "incorrect subdivision value");
130 jassert (QuadTesselated::index_count<size_t>(subdivision_count) <= std::numeric_limits<index_t>::max(),
131 "index value overflow");
132
133 index_t vertex_count = QuadTesselated::VERTEX_COUNT<index_t>[subdivision_count];
134 index_t index_count = QuadTesselated::index_count<index_t>(subdivision_count);
135
136
137 if (not p_mesh->init(vertex_count, index_count))
138 return false;
139
140 index_t *p_indices_src, *p_indices_dst = p_mesh->indexes.p_array;
141 if (not allocate(p_indices_src, index_count))
142 {
143 p_mesh->destroy();
144 return false;
145 }
146
147 memcpy(p_indices_dst, quads_[quad_index].indices, sizeof (index_t) * quad::INDEX_COUNT);
148
149 auto &vertices = quads_[quad_index].vertices;
150 for (index_t i = 0; i < quad::VERTEX_COUNT; ++i)
151 {
152 setSubVector<0,3>(p_mesh->vertexes[i], vertices[i]);
153 if (texture_coord)
154 setSubVector<3,2>(p_mesh->vertexes[i], quad::TEXTURE_COORDINATES[i]);
155 if (normals)
156 setSubVector<N_OFFSET<texture_coord>,3>(p_mesh->vertexes[i], vertices[i]);
157 }
158 memcpy(p_mesh->indexes.p_array, quads_[quad_index].indices, sizeof (index_t) * quad::INDEX_COUNT);
159
160 //declarations
161 index_t ind_middle_12, ind_middle_23, ind_middle_13;
162 index_t index_i = quad::INDEX_COUNT;
163 index_t vertex_i = quad::VERTEX_COUNT - 1;
164
165
166 mtl::tree::red_black_keys<index_t, vec3<floating_t>> unique_vertices;
167 unique_vertices.init();
168
169 for (unsigned int i = 0; i < subdivision_count; ++i)
170 {
171 std::swap(p_indices_src, p_indices_dst);
172
173 index_t p_index_count = index_i;
174 index_i = 0;
175 for (index_t j = 0; j < p_index_count; j += 3)
176 {
177 auto vertex1 = p_mesh->vertexes[p_indices_src[j + 0]];
178 auto vertex2 = p_mesh->vertexes[p_indices_src[j + 1]];
179 auto vertex3 = p_mesh->vertexes[p_indices_src[j + 2]];
180
181 auto vec_middle_12 = middle_vertex(vertex1, vertex2);
182 auto vec_middle_23 = middle_vertex(vertex2, vertex3);
183 auto vec_middle_13 = middle_vertex(vertex1, vertex3);
184
185 if (not unique_vertices.find(subVector<0,3>(vec_middle_12), ind_middle_12))
186 {
187 p_mesh->vertexes[++vertex_i] = vec_middle_12;
188 ind_middle_12 = vertex_i;
189 if (not unique_vertices.insert(ind_middle_12, subVector<0,3>(vec_middle_12), TREE_CB, 0))
190 goto CANCEL;
191 }
192
193 if (not unique_vertices.find(subVector<0,3>(vec_middle_23), ind_middle_23))
194 {
195 p_mesh->vertexes[++vertex_i] = vec_middle_23;
196 ind_middle_23 = vertex_i;
197 if (not unique_vertices.insert(ind_middle_23, subVector<0,3>(vec_middle_23), TREE_CB, 0))
198 goto CANCEL;
199 }
200
201 if (not unique_vertices.find(subVector<0,3>(vec_middle_13), ind_middle_13))
202 {
203 p_mesh->vertexes[++vertex_i] = vec_middle_13;
204 ind_middle_13 = vertex_i;
205 if (not unique_vertices.insert(ind_middle_13, subVector<0,3>(vec_middle_13), TREE_CB, 0))
206 goto CANCEL;
207 }
208
209 p_indices_dst[ index_i] = p_indices_src[j];
210 p_indices_dst[++index_i] = ind_middle_12;
211 p_indices_dst[++index_i] = ind_middle_13;
212
213 p_indices_dst[++index_i] = ind_middle_12;
214 p_indices_dst[++index_i] = p_indices_src[j + 1];
215 p_indices_dst[++index_i] = ind_middle_23;
216
217 p_indices_dst[++index_i] = ind_middle_13;
218 p_indices_dst[++index_i] = ind_middle_23;
219 p_indices_dst[++index_i] = p_indices_src[j + 2];
220
221 p_indices_dst[++index_i] = ind_middle_12;
222 p_indices_dst[++index_i] = ind_middle_23;
223 p_indices_dst[++index_i] = ind_middle_13;
224 ++index_i;
225 }
226 }
227 jassert(index_i == index_count && vertex_i + 1 == vertex_count, "wrong result");
228
229 p_mesh->indexes.p_array = p_indices_dst;
230 jl::deallocate(&p_indices_src);
231 unique_vertices.destroy();
232
233 return true;
234
235 CANCEL: jl::deallocate(&p_indices_src);
236 p_mesh->destroy();
237 unique_vertices.destroy();
238 return false;
239 }
240 }
241 }
12 constexpr static const unsigned int SUBDIVISIONS_MAX = 6;
13
14 template<typename index_t> constexpr static
15 index_t index_count(unsigned int subdivision_count) {
16 index_t index_count = 6;
17 for (unsigned int i = 0; i < subdivision_count; ++i)
18 index_count *= 4;
19 return index_count;
20 };
21
22 template<typename index_t> constexpr static const
23 index_t VERTEX_COUNT[SUBDIVISIONS_MAX+1] { 4, 9, 25, 81, 289, 1089, 4225 };
24 }
25 namespace mesh::icosahedron_quad
26 {
27 template<typename T>
28 using floating_check = typename
29 std::enable_if<std::is_floating_point<T>::value, math::vec3<T>>::type;
30
31 template<typename T> [[nodiscard]] constexpr inline
32 floating_check<T> quad_coordinate_to_real(unsigned int quad_i, T u, T v)
33 {
34 using namespace math;
35
36 T diagonal_ratio_2 = (u + v);
37 T horizontal_ratio = (v - u) / two<T>;
38
39 T up_ratio = diagonal_ratio_2 > one<T>
40 ? 2 - diagonal_ratio_2
41 : up_ratio = diagonal_ratio_2;
42
43 auto dH = quads_horizontal<T>[quad_i] * horizontal_ratio;
44 auto dD = quads_diagonal <T>[quad_i] * diagonal_ratio_2 / two<T>;
45 auto dUP = quads_height <T>[quad_i] * up_ratio;
46 return normalize(quads<T>[quad_i].vertices[0] + dH + dD + dUP);
47 }
48
49 template<simd::Level l> [[nodiscard]] inline
50 math::vec3<simd::pfloat_simd<l>> quad_coordinate_to_real(
51 unsigned int quad_i, simd::pfloat_simd<l> u, simd::pfloat_simd<l> v)
52 {
53 using namespace math;
54 using namespace simd;
55 using pf = simd::pfloat_simd<l>;
56
57 pf diagonal_ratio_x2 = (u + v);
58 pf horizontal_ratio = (v - u) / pf(2.f);
59
60 pf up_ratio = (pf(1.f) < diagonal_ratio_x2)
61 .blendv(diagonal_ratio_x2, pf(2.f) - diagonal_ratio_x2);
62
63 auto horizontal = quads_horizontal<float>[quad_i];
64 auto diagonal = quads_diagonal <float>[quad_i];
65 auto up = quads_height <float>[quad_i];
66 auto main = quads <float>[quad_i].vertices[0];
67
68 pf diagonal_ratio = diagonal_ratio_x2 / pf(2.f);
69
70 pf x = pf(main.x) + pf(up.x) * up_ratio
71 + pf(diagonal.x) * diagonal_ratio
72 + pf(horizontal.x) * horizontal_ratio;
73
74 pf y = pf(main.y) + pf(up.y) * up_ratio
75 + pf(diagonal.y) * diagonal_ratio
76 + pf(horizontal.y) * horizontal_ratio;
77
78 pf z = pf(main.z) + pf(up.z) * up_ratio
79 + pf(diagonal.z) * diagonal_ratio
80 + pf(horizontal.z) * horizontal_ratio;
81
82 pf rsqrtdot = (x * x + y * y + z * z).rsqrt();
83 return vec3<pf>{x * rsqrtdot,y * rsqrtdot,z * rsqrtdot};
84 }
85 }
86 namespace mesh::icosahedron_quad::build::detail
87 {
88 template<unsigned int vec_size, typename floating_t> [[nodiscard]] constexpr
89 inline
90 math::vector<vec_size, floating_t> middle_vertex(
91 math::vector<vec_size, floating_t> vertex1,
92 math::vector<vec_size, floating_t> vertex2) {
93 auto result = math::medium(vertex1, vertex2);
94 result.template part<0,3>().normalize();
95 return result;
96 }
97 }
98 namespace mesh::icosahedron_quad::build
99 {
100 TEMPLATE_ARGS [[nodiscard]]
101 bool quad_tesselated(unsigned int quad_index, unsigned int subdivision_count,
102 MESH_TEMPLATE *p_mesh)
103 {
104 using namespace math;
105 using namespace detail;
106 using quad = icosahedron_quad::Quad<floating_t, index_t>;
107 const auto &quads_ = quads<floating_t, index_t>;
108 void(*TREE_CB)(index_t, int) = [] (index_t, int) {
109 jabort_release("duplicates must not exist");
110 };
111
112 jassert (subdivision_count <= QuadTesselated::SUBDIVISIONS_MAX,
113 "incorrect subdivision value");
114 jassert (QuadTesselated::index_count<size_t>(subdivision_count)
115 <= std::numeric_limits<index_t>::max(),
116 "index value overflow");
117
118 index_t vcount = QuadTesselated::VERTEX_COUNT<index_t>[subdivision_count];
119 index_t icount = QuadTesselated::index_count<index_t>(subdivision_count);
120
121 if (not p_mesh->init(vcount, icount))
122 return false;
123 index_t *p_indices_src, *p_indices_dst = p_mesh->indexes.p_array;
124 if (not allocate(p_indices_src, icount)) {
125 p_mesh->destroy();
126 return false;
127 }
128
129 memcpy(p_indices_dst,
130 quads_[quad_index].indices,
131 sizeof (index_t) * quad::INDEX_COUNT);
132
133 auto &vertices = quads_[quad_index].vertices;
134 for (index_t i = 0; i < quad::VERTEX_COUNT; ++i) {
135 auto &v = p_mesh->vertexes[i];
136 v.template part<0,3>() = vertices[i];
137 if (texture_coord)
138 v.template part<3,2>() = quad::TEXTURE_COORDINATES[i];
139 if (normals)
140 v.template part<N_OFFSET<texture_coord>,3>() = vertices[i];
141 }
142 memcpy(p_mesh->indexes.p_array,
143 quads_[quad_index].indices,
144 sizeof (index_t) * quad::INDEX_COUNT);
145
146 index_t ind_middle_12, ind_middle_23, ind_middle_13;
147 index_t index_i = quad::INDEX_COUNT;
148 index_t vertex_i = quad::VERTEX_COUNT - 1;
149
150 mtl::tree::red_black_keys<index_t, vec3<floating_t>> unique_vertices;
151 unique_vertices.init();
152
153 for (unsigned int i = 0; i < subdivision_count; ++i) {
154 std::swap(p_indices_src, p_indices_dst);
155
156 index_t p_index_count = index_i;
157 index_i = 0;
158 for (index_t j = 0; j < p_index_count; j += 3)
159 {
160 auto vertex1 = p_mesh->vertexes[p_indices_src[j + 0]];
161 auto vertex2 = p_mesh->vertexes[p_indices_src[j + 1]];
162 auto vertex3 = p_mesh->vertexes[p_indices_src[j + 2]];
163
164 auto vec_middle_12 = middle_vertex(vertex1, vertex2);
165 auto vec_middle_23 = middle_vertex(vertex2, vertex3);
166 auto vec_middle_13 = middle_vertex(vertex1, vertex3);
167 auto &v12_pos = vec_middle_12.template part<0,3>();
168 auto &v23_pos = vec_middle_23.template part<0,3>();
169 auto &v13_pos = vec_middle_13.template part<0,3>();
170
171 if (not unique_vertices.find(v12_pos, ind_middle_12)) {
172 p_mesh->vertexes[++vertex_i] = vec_middle_12;
173 ind_middle_12 = vertex_i;
174 if (not unique_vertices.insert(ind_middle_12, v12_pos, TREE_CB, 0))
175 goto CANCEL;
176 }
177 if (not unique_vertices.find(v23_pos, ind_middle_23)) {
178 p_mesh->vertexes[++vertex_i] = vec_middle_23;
179 ind_middle_23 = vertex_i;
180 if (not unique_vertices.insert(ind_middle_23, v23_pos, TREE_CB, 0))
181 goto CANCEL;
182 }
183 if (not unique_vertices.find(v13_pos, ind_middle_13)) {
184 p_mesh->vertexes[++vertex_i] = vec_middle_13;
185 ind_middle_13 = vertex_i;
186 if (not unique_vertices.insert(ind_middle_13, v13_pos, TREE_CB, 0))
187 goto CANCEL;
188 }
189
190 p_indices_dst[index_i++] = p_indices_src[j];
191 p_indices_dst[index_i++] = ind_middle_12;
192 p_indices_dst[index_i++] = ind_middle_13;
193
194 p_indices_dst[index_i++] = ind_middle_12;
195 p_indices_dst[index_i++] = p_indices_src[j + 1];
196 p_indices_dst[index_i++] = ind_middle_23;
197
198 p_indices_dst[index_i++] = ind_middle_13;
199 p_indices_dst[index_i++] = ind_middle_23;
200 p_indices_dst[index_i++] = p_indices_src[j + 2];
201
202 p_indices_dst[index_i++] = ind_middle_12;
203 p_indices_dst[index_i++] = ind_middle_23;
204 p_indices_dst[index_i++] = ind_middle_13;
205 }
206 }
207 jassert(index_i == icount && vertex_i + 1 == vcount, "wrong result");
208
209 p_mesh->indexes.p_array = p_indices_dst;
210 jl::deallocate(&p_indices_src);
211 unique_vertices.destroy();
212
213 return true;
214
215 CANCEL:
216 jl::deallocate(&p_indices_src);
217 p_mesh->destroy();
218 unique_vertices.destroy();
219 return false;
220 }
242 221 } }
243 222
244 223 #undef TEMPLATE_ARGS #undef TEMPLATE_ARGS
File libs/mesh/polyhedron/icosahedron_quad_texture_coordinates.png deleted (index 01ebd64..0000000)
File libs/mesh/polyhedron/icosahedron_tesselated.h changed (mode: 100644) (index d025d88..931cb4d)
7 7 #define TEMPLATE_ARGS template<CONDITION_ARGS, typename floating_t, typename index_t> #define TEMPLATE_ARGS template<CONDITION_ARGS, typename floating_t, typename index_t>
8 8 #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t> #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t>
9 9
10 namespace mesh
10 namespace mesh::icosahedron_tesselated::build
11 11 { {
12 namespace icosahedron_tesselated
13 {
14 namespace build
15 {
16 template<CONDITION_ARGS, unsigned int subdivision_count,
17 typename floating_t, typename index_t, PF_ModifyVertex<floating_t>>
18
19 [[nodiscard]] inline bool icosahedron_tesselated_constexpr(MESH_TEMPLATE *p_mesh);
20
21
22 template<CONDITION_ARGS, typename floating_t, typename index_t>
23
24 [[nodiscard]] bool icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh);
25 }
26
27 namespace __hiden
28 {
29 template<unsigned int vec_size, typename floating_t>
30 [[nodiscard]] constexpr inline math::vector<vec_size, floating_t> middle_vector
31 (
32 math::vector<vec_size, floating_t> vertex1,
33 math::vector<vec_size, floating_t> vertex2
34 )
35 { using namespace math;
36
37 auto result = medium(vertex1, vertex2);
38
39 setSubVector<0,3>(result, normalize(subVector<0,3>(result)));
40 setSubVector<5,3>(result, subVector<0,3>(result));
41 if (vec_size > 3)
42 setSubVector<3,2>(result, __texture_coordinates::uv(subVector<0,3>(result)));
43 return result;
44 }
45 }
46
47 namespace icosahedron_tesselated
48 {
49 template<typename index_t> constexpr inline
50 index_t triangle_count(unsigned int subdivision_count)
51 {
52 index_t _scale = 1;
53 for (index_t i = 0; i < subdivision_count; ++i)
54 _scale *= 4;
55
56 return _scale * index_t(icosahedron::FACE_COUNT);
57 }
58
59 template<typename index_t> constexpr inline
60 index_t index_count(index_t triangle_count)
61 {
62 return triangle_count * index_t(3);
63 }
64
65 template<typename index_t> constexpr inline
66 index_t vertex_count(index_t triangle_count)
67 {
68 return triangle_count / index_t(2) + index_t(2);
69 }
70 }
71
72 namespace compile_time
73 {
74 template<CONDITION_ARGS, unsigned int subdivision_count, typename floating_t, typename index_t>
75 struct IcosahedronTesselated
76 {
77 using Icosahedron = icosahedron::Icosahedron<ARGS>;
78 using vertex = typename Icosahedron::vertex;
79
80 constexpr static size_t index_count_needed()
81 {
82 size_t _scale = 1;
83 for (index_t i = 0; i < subdivision_count; ++i)
84 _scale *= 4;
85 return _scale * size_t(icosahedron::FACE_COUNT) * 3;
86 }
87 static_assert(index_count_needed() <= std::numeric_limits<index_t>::max());
88
89 constexpr static index_t index_count = index_t(index_count_needed());
90 constexpr static index_t triangle_count = index_count / index_t(3);
91 constexpr static index_t vertex_count = triangle_count / index_t(2) + index_t(2);
92
93 vertex vertices[vertex_count];
94 index_t indices[ index_count];
95 };
96
97
98
99 template<CONDITION_ARGS, unsigned int subdivision_count, typename floating_t, typename index_t,
100 PF_ModifyVertex<floating_t> MODIFY>
101
102 [[nodiscard]] constexpr IcosahedronTesselated<texture_coord,normals,subdivision_count,floating_t,index_t>
103 icosahedron_tesselated_constexpr()
104 {
105 using namespace math;
106 using polyhedra = IcosahedronTesselated<texture_coord, normals, subdivision_count, floating_t, index_t>;
107 polyhedra result{};
108
109 //prepare swap-indices arrays
110 uint_fast8_t s_i = 0; //subdivision_index % 2
111 index_t indices[2][polyhedra::index_count]{};
112
113 //fill first indices
114 for (uint_fast8_t i = 0; i < polyhedra::icosahedron::indices::COUNT; ++i)
115 indices[0][i] = icosahedron::pre_compiled<ARGS>.indice._[i];
116
117 //fill first vertices
118 for (uint_fast8_t i = 0; i < polyhedra::icosahedron::vertices::COUNT; ++i)
119 result.vertices[i] = icosahedron::pre_compiled<ARGS>.vertice._[i];
120 index_t vertex_i = icosahedron::VERTEX_COUNT - 1;
121
122 //declarations
123 index_t ind_middle_12{}, ind_middle_23{}, ind_middle_13{};
124
125 using Value = index_t;
126 using Key = vec3<floating_t>;
127 using Index = index_t;
128 auto &Size = polyhedra::vertex_count;
129 mtl::compile_time::associative_array<Value, Key, Index, Size> unique_vertices{};
130
131 index_t index_i = icosahedron::INDEX_COUNT, p_index_count{};
132
133 for (unsigned int i = 0; i < subdivision_count; ++i)
134 {
135 using namespace __hiden;
136
137 p_index_count = index_i;
138 index_i = 0;
139 uint_fast8_t p_s_i = s_i; //previous s_i
140 s_i = (s_i + 1) % 2;
141 for (index_t j = 0; j < p_index_count; j += 3)
142 {
143 auto vertex1 = result.vertices[indices[p_s_i][j + 0]];
144 auto vertex2 = result.vertices[indices[p_s_i][j + 1]];
145 auto vertex3 = result.vertices[indices[p_s_i][j + 2]];
146
147 auto vec_middle_12 = middle_vector<MODIFY>(vertex1, vertex2);
148 auto vec_middle_23 = middle_vector<MODIFY>(vertex2, vertex3);
149 auto vec_middle_13 = middle_vector<MODIFY>(vertex1, vertex3);
150
151 if (not unique_vertices.find(subVector<0,3>(vec_middle_12), ind_middle_12))
152 {
153 result.vertices[++vertex_i] = vec_middle_12;
154 ind_middle_12 = vertex_i;
155 unique_vertices.insert(ind_middle_12, subVector<0,3>(vec_middle_12));
156 }
157
158 if (not unique_vertices.find(subVector<0,3>(vec_middle_23), ind_middle_23))
159 {
160 result.vertices[++vertex_i] = vec_middle_23;
161 ind_middle_23 = vertex_i;
162 unique_vertices.insert(ind_middle_23, subVector<0,3>(vec_middle_23));
163 }
164
165 if (not unique_vertices.find(subVector<0,3>(vec_middle_13), ind_middle_13))
166 {
167 result.vertices[++vertex_i] = vec_middle_13;
168 ind_middle_13 = vertex_i;
169 unique_vertices.insert(ind_middle_13, subVector<0,3>(vec_middle_13));
170 }//true==true;
171
172 indices[s_i][ index_i] = indices[p_s_i][j];
173 indices[s_i][++index_i] = ind_middle_12;
174 indices[s_i][++index_i] = ind_middle_13;
175
176 indices[s_i][++index_i] = ind_middle_12;
177 indices[s_i][++index_i] = indices[p_s_i][j + 1];
178 indices[s_i][++index_i] = ind_middle_23;
179
180 indices[s_i][++index_i] = ind_middle_13;
181 indices[s_i][++index_i] = ind_middle_23;
182 indices[s_i][++index_i] = indices[p_s_i][j + 2];
183
184 indices[s_i][++index_i] = ind_middle_12;
185 indices[s_i][++index_i] = ind_middle_23;
186 indices[s_i][++index_i] = ind_middle_13;
187 ++index_i;
188 }
189 }
190 if (index_i != polyhedra::index_count)
191 unique_vertices.error();
192
193 if (vertex_i + 1 != polyhedra::vertex_count)
194 unique_vertices.error();
195
196 for (index_t i = 0; i < index_i; ++i)
197 result.indices[i] = indices[s_i][i];
198
199 return result;
200 }
201 }
202 template<CONDITION_ARGS, unsigned int subdivision_count = 0,
203 typename floating_t = float, typename index_t = uint8_t,
204 PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
205
206 constexpr static const auto pre_compiled = compile_time::
207 icosahedron_tesselated_constexpr<texture_coord, normals, subdivision_count, floating_t, index_t, MODIFY>();
208
209 namespace build
210 {
211
212 template<CONDITION_ARGS, unsigned int subdivision_count,
213 typename floating_t, typename index_t, PF_ModifyVertex<floating_t> MODIFY>
214
215 [[nodiscard]] bool icosahedron_tesselated_constexpr(MESH_TEMPLATE *p_mesh)
216 {
217 auto &compiled = pre_compiled<texture_coord,normals, subdivision_count, floating_t, index_t, MODIFY>;
218 if (not p_mesh->init(compiled.vertex_count, compiled.index_count))
219 return false;
220
221 index_t size = compiled.vertex_count * sizeof (*p_mesh->vertexes.p_array);
222 memcpy(p_mesh->vertexes.p_array, &compiled.vertices, size);
223
224 size = compiled.index_count * sizeof (index_t);
225 memcpy(p_mesh->indexes.p_array, &compiled.indices, size);
226 return true;
227 }
228
229 template<CONDITION_ARGS, typename floating_t, typename index_t>
230 [[nodiscard]] bool icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh)
231 {
232 using namespace math; using namespace __hiden;
233 void(*TREE_CB)(index_t, int) = [] (index_t, int) { jabort_release("duplicates must not exist"); };
234 {
235 size_t __triangle_count = icosahedron_tesselated::triangle_count<size_t>(subdivision_count);
236 size_t __index_count = icosahedron_tesselated::index_count<size_t>(__triangle_count);
237 jassert(__index_count <= std::numeric_limits<index_t>::max(), "index value overflow");
238 }
239 index_t triangle_count = icosahedron_tesselated::triangle_count<index_t>(subdivision_count);
240 index_t vertex_count = icosahedron_tesselated::vertex_count <index_t>(triangle_count),
241 index_count = icosahedron_tesselated::index_count <index_t>(triangle_count);
242
243 if (not p_mesh->init(vertex_count, index_count))
244 return false;
245
246 //prepare swap-indices arrays
247 index_t *p_indices_src, *p_indices_dst = p_mesh->indexes.begin();
248 if (not jl::allocate(&p_indices_src, index_count))
249 {
250 p_mesh->destroy();
251 return false;
252 }
253
254 //fill first indices
255 for (uint_fast8_t i = 0; i < icosahedron::INDEX_COUNT; ++i)
256 p_indices_dst[i] = icosahedron::pre_compiled<ARGS>.indice._[i];
257
258 //fill first vertices
259 for (uint_fast8_t i = 0; i < icosahedron::VERTEX_COUNT; ++i)
260 p_mesh->vertexes[i] = icosahedron::pre_compiled<ARGS>.vertice._[i];
261
262 //declarations
263 index_t ind_middle_12, ind_middle_23, ind_middle_13;
264 index_t index_i = icosahedron::INDEX_COUNT;
265 index_t vertex_i = icosahedron::VERTEX_COUNT - 1;
266
267 mtl::tree::red_black_keys<index_t, vec3<floating_t>> unique_vertices; unique_vertices.init();
268
269 for (unsigned int i = 0; i < subdivision_count; ++i)
270 {
271 std::swap(p_indices_src, p_indices_dst);
272
273 index_t p_index_count = index_i;
274 index_i = 0;
275 for (index_t j = 0; j < p_index_count; j += 3)
276 {
277 auto vertex1 = p_mesh->vertexes[p_indices_src[j + 0]];
278 auto vertex2 = p_mesh->vertexes[p_indices_src[j + 1]];
279 auto vertex3 = p_mesh->vertexes[p_indices_src[j + 2]];
280
281 auto vec_middle_12 = middle_vector(vertex1, vertex2);
282 auto vec_middle_23 = middle_vector(vertex2, vertex3);
283 auto vec_middle_13 = middle_vector(vertex1, vertex3);
284
285 if (not unique_vertices.find(subVector<0,3>(vec_middle_12), ind_middle_12))
286 {
287 p_mesh->vertexes[++vertex_i] = vec_middle_12;
288 ind_middle_12 = vertex_i;
289 if (not unique_vertices.insert(ind_middle_12, subVector<0,3>(vec_middle_12), TREE_CB, 0))
290 goto CANCEL;
291 }
292
293 if (not unique_vertices.find(subVector<0,3>(vec_middle_23), ind_middle_23))
294 {
295 p_mesh->vertexes[++vertex_i] = vec_middle_23;
296 ind_middle_23 = vertex_i;
297 if (not unique_vertices.insert(ind_middle_23, subVector<0,3>(vec_middle_23), TREE_CB, 0))
298 goto CANCEL;
299 }
300
301 if (not unique_vertices.find(subVector<0,3>(vec_middle_13), ind_middle_13))
302 {
303 p_mesh->vertexes[++vertex_i] = vec_middle_13;
304 ind_middle_13 = vertex_i;
305 if (not unique_vertices.insert(ind_middle_13, subVector<0,3>(vec_middle_13), TREE_CB, 0))
306 goto CANCEL;
307 }
308
309 p_indices_dst[ index_i] = p_indices_src[j];
310 p_indices_dst[++index_i] = ind_middle_12;
311 p_indices_dst[++index_i] = ind_middle_13;
312
313 p_indices_dst[++index_i] = ind_middle_12;
314 p_indices_dst[++index_i] = p_indices_src[j + 1];
315 p_indices_dst[++index_i] = ind_middle_23;
316
317 p_indices_dst[++index_i] = ind_middle_13;
318 p_indices_dst[++index_i] = ind_middle_23;
319 p_indices_dst[++index_i] = p_indices_src[j + 2];
320
321 p_indices_dst[++index_i] = ind_middle_12;
322 p_indices_dst[++index_i] = ind_middle_23;
323 p_indices_dst[++index_i] = ind_middle_13;
324 ++index_i;
325 }
326 }
327 jassert(index_i == index_count && vertex_i + 1 == vertex_count, "wrong result");
328
329 jl::deallocate(&p_indices_src);
330
331 return true;
332
333 CANCEL: jl::deallocate(&p_indices_src);
334 jl::deallocate(&p_indices_dst);
335 p_mesh->vertexes.destroy();
336 unique_vertices.destroy();
337 return false;
338 }
339 }
340 }
12 template<CONDITION_ARGS, unsigned int subdivision_count,
13 typename floating_t, typename index_t, PF_ModifyVertex<floating_t>>
14 [[nodiscard]] inline
15 bool icosahedron_tesselated_constexpr(MESH_TEMPLATE *p_mesh);
16
17 template<CONDITION_ARGS, typename floating_t, typename index_t> [[nodiscard]]
18 bool icosahedron_tesselated(unsigned int subdivision_count,
19 MESH_TEMPLATE *p_mesh);
20 }
21 namespace mesh::icosahedron_tesselated::detail
22 {
23 template<unsigned int vec_size, typename floating_t>
24 [[nodiscard]] constexpr inline
25 math::vector<vec_size, floating_t> middle_vector(
26 math::vector<vec_size, floating_t> vertex1,
27 math::vector<vec_size, floating_t> vertex2)
28 {
29 auto result = medium(vertex1, vertex2);
30 result.template part<0,3>() = result.template part<0,3>.normalized();
31 result.template part<5,3>() = result.template part<0,3>(result);
32 if (vec_size > 3)
33 result.template part<3,2>() =
34 mesh::detail::texture_coordinates::uv(result.template part<0,3>());
35 return result;
36 }
37 }
38
39 namespace mesh::icosahedron_tesselated
40 {
41 template<typename index_t> constexpr inline
42 index_t triangle_count(unsigned int subdivision_count) {
43 index_t _scale = 1;
44 for (index_t i = 0; i < subdivision_count; ++i)
45 _scale *= 4;
46 return _scale * index_t(icosahedron::FACE_COUNT);
47 }
48 template<typename index_t> constexpr inline
49 index_t index_count(index_t triangle_count) {
50 return triangle_count * index_t(3);
51 }
52 template<typename index_t> constexpr inline
53 index_t vertex_count(index_t triangle_count) {
54 return triangle_count / index_t(2) + index_t(2);
55 }
56 }
57
58 namespace mesh::icosahedron_tesselated::compile_time
59 {
60 template<CONDITION_ARGS, unsigned int subdivision_count,
61 typename floating_t, typename index_t>
62 struct IcosahedronTesselated
63 {
64 using Icosahedron = icosahedron::Icosahedron<ARGS>;
65 using vertex = typename Icosahedron::vertex;
66
67 constexpr static size_t index_count_needed() {
68 size_t _scale = 1;
69 for (index_t i = 0; i < subdivision_count; ++i)
70 _scale *= 4;
71 return _scale * size_t(icosahedron::FACE_COUNT) * 3;
72 }
73 static_assert(index_count_needed() <= std::numeric_limits<index_t>::max());
74
75 constexpr static const
76 index_t index_count = index_t(index_count_needed());
77 constexpr static const
78 index_t triangle_count = index_count / index_t(3);
79 constexpr static const
80 index_t vertex_count = triangle_count / index_t(2) + index_t(2);
81
82 vertex vertices[vertex_count];
83 index_t indices[ index_count];
84 };
85
86 template<CONDITION_ARGS, unsigned int subdivision_count,
87 typename floating_t, typename index_t,
88 PF_ModifyVertex<floating_t> MODIFY>
89 [[nodiscard]] constexpr
90 IcosahedronTesselated<texture_coord,normals,subdivision_count,floating_t,index_t>
91 icosahedron_tesselated_constexpr() {
92 using namespace math;
93 using polyhedra = IcosahedronTesselated<texture_coord, normals, subdivision_count, floating_t, index_t>;
94 polyhedra result{};
95
96 //prepare swap-indices arrays
97 uint_fast8_t s_i = 0; //subdivision_index % 2
98 index_t indices[2][polyhedra::index_count]{};
99
100 //fill first indices
101 for (uint_fast8_t i = 0; i < polyhedra::icosahedron::indices::COUNT; ++i)
102 indices[0][i] = icosahedron::pre_compiled<ARGS>.indice._[i];
103
104 //fill first vertices
105 for (uint_fast8_t i = 0; i < polyhedra::icosahedron::vertices::COUNT; ++i)
106 result.vertices[i] = icosahedron::pre_compiled<ARGS>.vertice._[i];
107 index_t vertex_i = icosahedron::VERTEX_COUNT - 1;
108
109 //declarations
110 index_t ind_middle_12{}, ind_middle_23{}, ind_middle_13{};
111
112 using Value = index_t;
113 using Key = vec3<floating_t>;
114 using Index = index_t;
115 auto &Size = polyhedra::vertex_count;
116 mtl::compile_time::associative_array<Value, Key, Index, Size> unique_vertices{};
117
118 index_t index_i = icosahedron::INDEX_COUNT, p_index_count{};
119
120 for (unsigned int i = 0; i < subdivision_count; ++i)
121 {
122 using namespace detail;
123
124 p_index_count = index_i;
125 index_i = 0;
126 uint_fast8_t p_s_i = s_i; //previous s_i
127 s_i = (s_i + 1) % 2;
128 for (index_t j = 0; j < p_index_count; j += 3)
129 {
130 auto vertex1 = result.vertices[indices[p_s_i][j + 0]];
131 auto vertex2 = result.vertices[indices[p_s_i][j + 1]];
132 auto vertex3 = result.vertices[indices[p_s_i][j + 2]];
133
134 auto vec_middle_12 = middle_vector<MODIFY>(vertex1, vertex2);
135 auto vec_middle_23 = middle_vector<MODIFY>(vertex2, vertex3);
136 auto vec_middle_13 = middle_vector<MODIFY>(vertex1, vertex3);
137
138 auto &v12_pos = vec_middle_12.template part<0,3>();
139 if (not unique_vertices.find(v12_pos, ind_middle_12)) {
140 result.vertices[++vertex_i] = vec_middle_12;
141 ind_middle_12 = vertex_i;
142 unique_vertices.insert(ind_middle_12, v12_pos);
143 }
144 auto &v23_pos = vec_middle_23.template part<0,3>();
145 if (not unique_vertices.find(v23_pos, ind_middle_23)) {
146 result.vertices[++vertex_i] = vec_middle_23;
147 ind_middle_23 = vertex_i;
148 unique_vertices.insert(ind_middle_23, v23_pos);
149 }
150 auto &v13_pos = vec_middle_13.template part<0,3>();
151 if (not unique_vertices.find(v13_pos, ind_middle_13)) {
152 result.vertices[++vertex_i] = vec_middle_13;
153 ind_middle_13 = vertex_i;
154 unique_vertices.insert(ind_middle_13, v13_pos);
155 }
156
157 indices[s_i][index_i++] = indices[p_s_i][j];
158 indices[s_i][index_i++] = ind_middle_12;
159 indices[s_i][index_i++] = ind_middle_13;
160
161 indices[s_i][index_i++] = ind_middle_12;
162 indices[s_i][index_i++] = indices[p_s_i][j + 1];
163 indices[s_i][index_i++] = ind_middle_23;
164
165 indices[s_i][index_i++] = ind_middle_13;
166 indices[s_i][index_i++] = ind_middle_23;
167 indices[s_i][index_i++] = indices[p_s_i][j + 2];
168
169 indices[s_i][index_i++] = ind_middle_12;
170 indices[s_i][index_i++] = ind_middle_23;
171 indices[s_i][index_i++] = ind_middle_13;
172 }
173 }
174 if (index_i != polyhedra::index_count)
175 unique_vertices.error();
176 if (vertex_i + 1 != polyhedra::vertex_count)
177 unique_vertices.error();
178 for (index_t i = 0; i < index_i; ++i)
179 result.indices[i] = indices[s_i][i];
180 return result;
181 }
182 }
183 namespace mesh::icosahedron_tesselated {
184 template<CONDITION_ARGS, unsigned int subdivision_count = 0,
185 typename floating_t = float, typename index_t = uint8_t,
186 PF_ModifyVertex<floating_t> MODIFY = modify_vertex::dummy>
187 constexpr static const
188 auto pre_compiled = compile_time::icosahedron_tesselated_constexpr<texture_coord, normals, subdivision_count, floating_t, index_t, MODIFY>();
189 }
190 namespace mesh::icosahedron_tesselated::build
191 {
192 template<CONDITION_ARGS, unsigned int subdivision_count,
193 typename floating_t, typename index_t,
194 PF_ModifyVertex<floating_t> MODIFY> [[nodiscard]]
195 bool icosahedron_tesselated_constexpr(MESH_TEMPLATE *p_mesh) {
196 auto &compiled = pre_compiled<texture_coord,normals, subdivision_count,
197 floating_t, index_t, MODIFY>;
198 if (not p_mesh->init(compiled.vertex_count, compiled.index_count))
199 return false;
200
201 index_t size = compiled.vertex_count * sizeof (*p_mesh->vertexes.p_array);
202 memcpy(p_mesh->vertexes.p_array, &compiled.vertices, size);
203
204 size = compiled.index_count * sizeof (index_t);
205 memcpy(p_mesh->indexes.p_array, &compiled.indices, size);
206 return true;
207 }
208
209 template<CONDITION_ARGS, typename floating_t, typename index_t> [[nodiscard]]
210 bool
211 icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh)
212 {
213 using namespace math;
214 using namespace detail;
215
216 void(*TREE_CB)(index_t, int) = [] (index_t, int) {
217 jabort_release("duplicates must not exist");
218 };
219 {
220 size_t triangle_count = icosahedron_tesselated::
221 triangle_count<size_t>(subdivision_count);
222 size_t icount = icosahedron_tesselated::
223 index_count<size_t>(triangle_count);
224 jassert(icount <= std::numeric_limits<index_t>::max(),
225 "index value overflow");
226 }
227 index_t triangle_count = icosahedron_tesselated::
228 triangle_count<index_t>(subdivision_count);
229 index_t vertex_count = icosahedron_tesselated::
230 vertex_count <index_t>(triangle_count);
231 index_t index_count = icosahedron_tesselated::
232 index_count <index_t>(triangle_count);
233
234 if (not p_mesh->init(vertex_count, index_count))
235 return false;
236
237 //prepare swap-indices arrays
238 index_t *p_indices_src, *p_indices_dst = p_mesh->indexes.begin();
239 if (not jl::allocate(&p_indices_src, index_count)) {
240 p_mesh->destroy();
241 return false;
242 }
243
244 //fill first indices
245 for (uint_fast8_t i = 0; i < icosahedron::INDEX_COUNT; ++i)
246 p_indices_dst[i] = icosahedron::pre_compiled<ARGS>.indice._[i];
247
248 //fill first vertices
249 for (uint_fast8_t i = 0; i < icosahedron::VERTEX_COUNT; ++i)
250 p_mesh->vertexes[i] = icosahedron::pre_compiled<ARGS>.vertice._[i];
251
252 //declarations
253 index_t ind_middle_12, ind_middle_23, ind_middle_13;
254 index_t index_i = icosahedron::INDEX_COUNT;
255 index_t vertex_i = icosahedron::VERTEX_COUNT - 1;
256
257 mtl::tree::red_black_keys<index_t, vec3<floating_t>> unique_vertices; unique_vertices.init();
258
259 for (unsigned int i = 0; i < subdivision_count; ++i)
260 {
261 std::swap(p_indices_src, p_indices_dst);
262
263 index_t p_index_count = index_i;
264 index_i = 0;
265 for (index_t j = 0; j < p_index_count; j += 3)
266 {
267 auto vertex1 = p_mesh->vertexes[p_indices_src[j + 0]];
268 auto vertex2 = p_mesh->vertexes[p_indices_src[j + 1]];
269 auto vertex3 = p_mesh->vertexes[p_indices_src[j + 2]];
270
271 auto vec_middle_12 = middle_vector(vertex1, vertex2);
272 auto vec_middle_23 = middle_vector(vertex2, vertex3);
273 auto vec_middle_13 = middle_vector(vertex1, vertex3);
274 auto &v12_pos = vec_middle_12.template part<0,3>();
275 auto &v23_pos = vec_middle_23.template part<0,3>();
276 auto &v13_pos = vec_middle_13.template part<0,3>();
277
278 if (not unique_vertices.find(v12_pos, ind_middle_12)) {
279 p_mesh->vertexes[++vertex_i] = vec_middle_12;
280 ind_middle_12 = vertex_i;
281 if (not unique_vertices.insert(ind_middle_12, v12_pos, TREE_CB, 0))
282 goto CANCEL;
283 }
284 if (not unique_vertices.find(v23_pos, ind_middle_23)) {
285 p_mesh->vertexes[++vertex_i] = vec_middle_23;
286 ind_middle_23 = vertex_i;
287 if (not unique_vertices.insert(ind_middle_23, v23_pos, TREE_CB, 0))
288 goto CANCEL;
289 }
290 if (not unique_vertices.find(v13_pos, ind_middle_13)) {
291 p_mesh->vertexes[++vertex_i] = vec_middle_13;
292 ind_middle_13 = vertex_i;
293 if (not unique_vertices.insert(ind_middle_13, v13_pos, TREE_CB, 0))
294 goto CANCEL;
295 }
296
297 p_indices_dst[index_i++] = p_indices_src[j];
298 p_indices_dst[index_i++] = ind_middle_12;
299 p_indices_dst[index_i++] = ind_middle_13;
300
301 p_indices_dst[index_i++] = ind_middle_12;
302 p_indices_dst[index_i++] = p_indices_src[j + 1];
303 p_indices_dst[index_i++] = ind_middle_23;
304
305 p_indices_dst[index_i++] = ind_middle_13;
306 p_indices_dst[index_i++] = ind_middle_23;
307 p_indices_dst[index_i++] = p_indices_src[j + 2];
308
309 p_indices_dst[index_i++] = ind_middle_12;
310 p_indices_dst[index_i++] = ind_middle_23;
311 p_indices_dst[index_i++] = ind_middle_13;
312 }
313 }
314 jassert(index_i == index_count and vertex_i + 1 == vertex_count,
315 "wrong result");
316 jl::deallocate(&p_indices_src);
317 return true;
318
319 CANCEL:
320 jl::deallocate(&p_indices_src);
321 jl::deallocate(&p_indices_dst);
322 p_mesh->vertexes.destroy();
323 unique_vertices.destroy();
324 return false;
325 }
341 326 } }
342 327
343 328 #undef CONDITION_ARGS #undef CONDITION_ARGS
File libs/mesh/sphere.h changed (mode: 100644) (index b200cc4..e735d2e)
4 4 #include "cube.h" #include "cube.h"
5 5 #include "polyhedron/icosahedron_tesselated.h" #include "polyhedron/icosahedron_tesselated.h"
6 6 #include <limits> #include <limits>
7 #include <math/coordinates/coordinates.h>
7 8
8 9 #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t> #define TEMPLATE_ARGS template<bool texture_coord, bool normals, typename floating_t, typename index_t>
9 10 #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t> #define MESH_TEMPLATE Mesh_T<texture_coord, normals, floating_t, index_t>
10 11
11 namespace mesh
12 namespace mesh::sphere::build
12 13 { {
13 namespace sphere
14 {
15 namespace build
16 {
17
18 TEMPLATE_ARGS
19 [[nodiscard]] bool uv(index_t parallels_count, index_t meridians_count, floating_t radius,
20 MESH_TEMPLATE *p_mesh);
21
22 TEMPLATE_ARGS
23 [[nodiscard]] inline bool cube_normalized(index_t edge_cell_count, floating_t edge_size,
24 MESH_TEMPLATE *p_mesh);
25
26 TEMPLATE_ARGS
27 [[nodiscard]] inline bool cube_spherified(index_t edge_vertex_count, floating_t edge_size,
28 MESH_TEMPLATE *p_mesh);
29
30 TEMPLATE_ARGS
31 [[nodiscard]] inline bool icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh);
32 }
33 }
14 TEMPLATE_ARGS [[nodiscard]]
15 bool
16 uv(index_t parallels_count, index_t meridians_count, floating_t radius,
17 MESH_TEMPLATE *p_mesh);
18
19 TEMPLATE_ARGS [[nodiscard]]
20 bool
21 cube_normalized(index_t edge_cell_count, floating_t edge_size,
22 MESH_TEMPLATE *p_mesh);
23
24 TEMPLATE_ARGS [[nodiscard]]
25 bool
26 cube_spherified(index_t edge_vertex_count, floating_t edge_size,
27 MESH_TEMPLATE *p_mesh);
28
29 TEMPLATE_ARGS [[nodiscard]]
30 bool
31 icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh);
34 32 } }
35 33
36 namespace mesh
34 namespace mesh::sphere::build::detail
37 35 { {
38 namespace sphere
39 {
40 namespace build
41 {
42 namespace __hiden
43 {
44 template<unsigned int vec_size, typename floating_t>
45 void set_texture_coordinate
46 (
47 math::vector<vec_size, floating_t> &vertex,
48 floating_t u,
49 floating_t v
50 )
51 { using namespace math;
52
53 if (vec_size == 5)
54 setSubVector<3,2>(vertex, vec2<floating_t>{ v, u });
55 }
56 }
57
58 TEMPLATE_ARGS
59 [[nodiscard]] bool uv(index_t parallels_count, index_t meridians_count, floating_t radius,
60 MESH_TEMPLATE *p_mesh)
61 {
62 using namespace math;
63 static_assert(std::is_floating_point<floating_t>::value);
64 using namespace __hiden;
36 template<unsigned int vec_size, typename floating_t>
37 void
38 set_texture_coordinate(math::vector<vec_size, floating_t> &vertex,
39 floating_t u, floating_t v) {
40 if (vec_size == 5)
41 vertex.template part<3,2>() = math::vec2<floating_t>{ v, u };
42 }
43 }
44 namespace mesh::sphere::build
45 {
46 TEMPLATE_ARGS [[nodiscard]]
47 bool
48 uv(index_t parallels_count, index_t meridians_count, floating_t radius,
49 MESH_TEMPLATE *p_mesh)
50 {
51 using namespace math;
52 static_assert(std::is_floating_point<floating_t>::value);
53 using namespace detail;
65 54 #ifndef NDEBUG #ifndef NDEBUG
66 fassert(size_t(parallels_count) * size_t(meridians_count) * 6 < std::numeric_limits<index_t>::max(),
67 "index overflow");
55 fassert(size_t(parallels_count) * size_t(meridians_count) * 6
56 < std::numeric_limits<index_t>::max(),
57 "index overflow");
68 58 #endif #endif
69 index_t vertexCount = parallels_count * (meridians_count+1);
70 if (not p_mesh->init(vertexCount, (parallels_count - 2) * (meridians_count + 1) * 6))
71 return false;
72
73 math::coordinates::spherical_3D<floating_t> spherical_pos = { .radius = radius };
74
75 floating_t x_ratio, y_ratio;
76 floating_t x_ratio_diff = math::cast<floating_t>(1) / (parallels_count - 1);
77 floating_t y_ratio_diff = math::cast<floating_t>(1) / meridians_count;
78 index_t indexIndex = 0, vertexIndex = 0;
79 index_t vertexIndexNextRow = meridians_count;
80
81 x_ratio = 0;
82 y_ratio = 0;
83 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
84 {
85 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
86
87 p_mesh->indexes[ indexIndex] = vertexIndexNextRow;
88 p_mesh->indexes[++indexIndex] = vertexIndex;
89 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
90 ++indexIndex;
91
92 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
93 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
94 }
95 y_ratio = 1;
96 spherical_pos.azimuth = 0;
97
98 p_mesh->indexes[ indexIndex] = vertexIndexNextRow;
99 p_mesh->indexes[++indexIndex] = vertexIndex;
100 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
101 ++indexIndex;
102
103 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
104 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
105 x_ratio += x_ratio_diff;
106
107 for(index_t x = 1; x < parallels_count - 2; ++x, x_ratio += x_ratio_diff)
108 {
109 spherical_pos.inclination = pi<floating_t> * x_ratio;
110 y_ratio = 0;
111 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
112 {
113 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
114
115 p_mesh->indexes[ indexIndex] = vertexIndex;
116 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
117 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
118 p_mesh->indexes[++indexIndex] = vertexIndexNextRow;
119 p_mesh->indexes[++indexIndex] = vertexIndexNextRow - 1;
120 p_mesh->indexes[++indexIndex] = vertexIndex;
121 ++indexIndex;
122
123 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
124 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
125 }
126 y_ratio = 1;
127 spherical_pos.azimuth = 0;
128
129 p_mesh->indexes[ indexIndex] = vertexIndex;
130 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
131 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
132 p_mesh->indexes[++indexIndex] = vertexIndexNextRow;
133 p_mesh->indexes[++indexIndex] = vertexIndexNextRow - 1;
134 p_mesh->indexes[++indexIndex] = vertexIndex;
135 ++indexIndex;
136
137 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
138 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
139 }
140 {
141 spherical_pos.inclination = pi<floating_t> * x_ratio;
142 y_ratio = 0;
143 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
144 {
145 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
146
147 p_mesh->indexes[ indexIndex] = vertexIndex;
148 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
149 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
150 ++indexIndex;
151
152 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
153 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
154 }
155 y_ratio = 1;
156 spherical_pos.azimuth = 0;
157
158 p_mesh->indexes[ indexIndex] = vertexIndex;
159 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
160 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
161 ++indexIndex;
162
163 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
164 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
165 }
166 x_ratio = 1;
167 spherical_pos.inclination = pi<floating_t>;
168 y_ratio = 0;
169 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
170 {
171 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
172
173 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
174 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
175 }
176 y_ratio = 1;
177 spherical_pos.azimuth = 0;
178 setSubVector<0,3>(p_mesh->vertexes[vertexIndex], spherical_pos.to_cartesian());
179 set_texture_coordinate(p_mesh->vertexes[vertexIndex], x_ratio, y_ratio);
180 return true;
181 }
182
183
184 TEMPLATE_ARGS
185 [[nodiscard]] inline bool cube_normalized(index_t edge_cell_count, floating_t edge_size,
186 MESH_TEMPLATE *p_mesh)
187 {
188 return cube::build::tesselated<texture_coord, normals, floating_t, index_t,
189 modify_vertex::normalize>
190 (p_mesh, edge_cell_count, edge_size);
191 }
192
193 TEMPLATE_ARGS
194 [[nodiscard]] inline bool cube_spherified(index_t edge_vertex_count, floating_t edge_size,
195 MESH_TEMPLATE *p_mesh)
196 {
197 return cube::build::tesselated<texture_coord, normals, floating_t, index_t,
198 modify_vertex::spheriy_vertex>
199 (p_mesh, edge_vertex_count, edge_size);
200 }
201
202 TEMPLATE_ARGS
203 [[nodiscard]] inline bool icosahedron_tesselated(unsigned int subdivision_count, MESH_TEMPLATE *p_mesh)
204 {
205 return icosahedron_tesselated::build::icosahedron_tesselated<texture_coord, floating_t, index_t>
206 (p_mesh, subdivision_count);
207 }
208 }
209 }
59 index_t vertexCount = parallels_count * (meridians_count+1);
60 if (not p_mesh->init(vertexCount, (parallels_count - 2) * (meridians_count + 1) * 6))
61 return false;
62
63 math::coordinates::spherical_3D<floating_t> spherical_pos = {
64 .radius = radius
65 };
66
67 floating_t x_ratio, y_ratio;
68 floating_t x_ratio_diff = math::cast<floating_t>(1) / (parallels_count - 1);
69 floating_t y_ratio_diff = math::cast<floating_t>(1) / meridians_count;
70 index_t indexIndex = 0, vertexIndex = 0;
71 index_t vertexIndexNextRow = meridians_count;
72
73 x_ratio = 0;
74 y_ratio = 0;
75 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff) {
76 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
77
78 p_mesh->indexes[ indexIndex] = vertexIndexNextRow;
79 p_mesh->indexes[++indexIndex] = vertexIndex;
80 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
81 ++indexIndex;
82
83 p_mesh->vertexes[vertexIndex].template part<0,3>() =
84 spherical_pos.to_cartesian();
85 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
86 }
87 y_ratio = 1;
88 spherical_pos.azimuth = 0;
89
90 p_mesh->indexes[ indexIndex] = vertexIndexNextRow;
91 p_mesh->indexes[++indexIndex] = vertexIndex;
92 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
93 ++indexIndex;
94
95 p_mesh->vertexes[vertexIndex].template part<0,3>() =
96 spherical_pos.to_cartesian();
97 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
98 x_ratio += x_ratio_diff;
99
100 for(index_t x = 1; x < parallels_count - 2; ++x, x_ratio += x_ratio_diff)
101 {
102 spherical_pos.inclination = pi<floating_t> * x_ratio;
103 y_ratio = 0;
104 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
105 {
106 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
107
108 p_mesh->indexes[ indexIndex] = vertexIndex;
109 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
110 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
111 p_mesh->indexes[++indexIndex] = vertexIndexNextRow;
112 p_mesh->indexes[++indexIndex] = vertexIndexNextRow - 1;
113 p_mesh->indexes[++indexIndex] = vertexIndex;
114 ++indexIndex;
115
116 p_mesh->vertexes[vertexIndex].template part<0,3>() =
117 spherical_pos.to_cartesian();
118 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
119 }
120 y_ratio = 1;
121 spherical_pos.azimuth = 0;
122
123 p_mesh->indexes[ indexIndex] = vertexIndex;
124 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
125 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
126 p_mesh->indexes[++indexIndex] = vertexIndexNextRow;
127 p_mesh->indexes[++indexIndex] = vertexIndexNextRow - 1;
128 p_mesh->indexes[++indexIndex] = vertexIndex;
129 ++indexIndex;
130
131 p_mesh->vertexes[vertexIndex].template part<0,3>() =
132 spherical_pos.to_cartesian();
133 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
134 }
135 {
136 spherical_pos.inclination = pi<floating_t> * x_ratio;
137 y_ratio = 0;
138 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
139 {
140 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
141
142 p_mesh->indexes[ indexIndex] = vertexIndex;
143 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
144 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
145 ++indexIndex;
146
147 p_mesh->vertexes[vertexIndex].template part<0,3>() =
148 spherical_pos.to_cartesian();
149 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
150 }
151 y_ratio = 1;
152 spherical_pos.azimuth = 0;
153
154 p_mesh->indexes[ indexIndex] = vertexIndex;
155 p_mesh->indexes[++indexIndex] = vertexIndex + 1;
156 p_mesh->indexes[++indexIndex] = ++vertexIndexNextRow;
157 ++indexIndex;
158
159 p_mesh->vertexes[vertexIndex].template part<0,3>() =
160 spherical_pos.to_cartesian();
161 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
162 }
163 x_ratio = 1;
164 spherical_pos.inclination = pi<floating_t>;
165 y_ratio = 0;
166 for (index_t y = 0; y < meridians_count; ++y, y_ratio += y_ratio_diff)
167 {
168 spherical_pos.azimuth = pi2<floating_t> * y_ratio;
169
170 p_mesh->vertexes[vertexIndex].template part<0,3>() =
171 spherical_pos.to_cartesian();
172 set_texture_coordinate(p_mesh->vertexes[vertexIndex++], x_ratio, y_ratio);
173 }
174 y_ratio = 1;
175 spherical_pos.azimuth = 0;
176 p_mesh->vertexes[vertexIndex].template part<0,3>() =
177 spherical_pos.to_cartesian();
178 set_texture_coordinate(p_mesh->vertexes[vertexIndex], x_ratio, y_ratio);
179 return true;
180 }
181
182 TEMPLATE_ARGS [[nodiscard]]
183 bool
184 cube_normalized(index_t edge_cell_count, floating_t edge_size,
185 MESH_TEMPLATE *p_mesh) {
186 return cube::build::tesselated<texture_coord, normals, floating_t, index_t,
187 modify_vertex::normalize>(p_mesh, edge_cell_count, edge_size);
188 }
189
190 TEMPLATE_ARGS [[nodiscard]]
191 bool
192 cube_spherified(index_t edge_vertex_count, floating_t edge_size,
193 MESH_TEMPLATE *p_mesh) {
194 return cube::build::tesselated<texture_coord, normals, floating_t, index_t,
195 modify_vertex::spheriy_vertex>(p_mesh, edge_vertex_count, edge_size);
196 }
197
198 TEMPLATE_ARGS [[nodiscard]]
199 bool
200 icosahedron_tesselated(unsigned int subdivision_count,
201 MESH_TEMPLATE *p_mesh) {
202 return icosahedron_tesselated::build::
203 icosahedron_tesselated<texture_coord, floating_t, index_t>
204 (p_mesh, subdivision_count);
205 }
210 206 } }
211 207
212 208 #undef TEMPLATE_ARGS #undef TEMPLATE_ARGS
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/Jackalope/jen

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/Jackalope/jen

Clone this repository using git:
git clone git://git.rocketgit.com/user/Jackalope/jen

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main