SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
InternalGeometry.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <Math/Math.hpp>
5#include <Math/Vector.hpp>
6
7/// Builds a subdivided flat quad on the XZ plane, facing up.
8inline Sleak::MeshData GetPlaneMesh(float width, float height, int subdivisionsX = 1, int subdivisionsY = 1) {
10
11 // Calculate step sizes for subdivisions
12 float stepX = width / subdivisionsX;
13 float stepY = height / subdivisionsY;
14
15 // Generate vertices
16 for (int y = 0; y <= subdivisionsY; ++y) {
17 for (int x = 0; x <= subdivisionsX; ++x) {
18 float posX = -width / 2.0f + x * stepX;
19 float posY = 0.0f;
20 float posZ = -height / 2.0f + y * stepY;
21
22 float u = x / (float)subdivisionsX;
23 float v = y / (float)subdivisionsY;
24
26 posX, posY, posZ, // Position
27 0, 1, 0, // Normal (pointing up)
28 1, 0, 0, // Tangent
29 u, v // UV
30 ));
31 }
32 }
33
34 for (int y = 0; y < subdivisionsY; ++y) {
35 for (int x = 0; x < subdivisionsX; ++x) {
36 int topLeft = y * (subdivisionsX + 1) + x;
37 int topRight = topLeft + 1;
38 int bottomLeft = (y + 1) * (subdivisionsX + 1) + x;
39 int bottomRight = bottomLeft + 1;
40
41 // First triangle
42 mesh.indices.add(topLeft);
43 mesh.indices.add(bottomLeft);
44 mesh.indices.add(topRight);
45
46 // Second triangle
47 mesh.indices.add(topRight);
48 mesh.indices.add(bottomLeft);
49 mesh.indices.add(bottomRight);
50 }
51 }
52
53 return mesh;
54}
55
56/// Builds a unit cube with per-face vertices for hard-edged normals.
58 Sleak::MeshData mesh;
59 //Position | Normal | Tangent | UV
60 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, 0.5f, 0, 0, 1, 1, 1, 1, 1, 0, 1)); // 0: bottom-left
61 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, +0.5f, 0.5f, 0, 0, 1, 1, 1, 1, 1, 0, 0)); // 1: top-left
62 mesh.vertices.AddVertex(Sleak::Vertex(+0.5f, +0.5f, 0.5f, 0, 0, 1, 1, 1, 1, 1, 1, 0)); // 2: top-right
63 mesh.vertices.AddVertex(Sleak::Vertex(+0.5f, -0.5f, 0.5f, 0, 0, 1, 1, 1, 1, 1, 1, 1)); // 3: bottom-right
64
65 // Back face (-Z)
66 //Position | Normal | Tangent | UV
67 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, -0.5f, 0, 0, -1, 1, 1, 1, 1, 0, 1)); // 4: bottom-left
68 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, 0.5f, -0.5f, 0, 0, -1, 1, 1, 1, 1, 0, 0)); // 5: top-left
69 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, 0.5f, -0.5f, 0, 0, -1, 1, 1, 1, 1, 1, 0)); // 6: top-right
70 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, -0.5f, 0, 0, -1, 1, 1, 1, 1, 1, 1)); // 7: bottom-right
71
72 // Left face (-X)
73 //Position | Normal | Tangent | UV
74 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, -0.5f, -1, 0, 0, 1, 1, 1, 1, 0, 1)); // 8: bottom-left
75 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, 0.5f, -0.5f, -1, 0, 0, 1, 1, 1, 1, 0, 0)); // 9: top-left
76 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, 0.5f, 0.5f, -1, 0, 0, 1, 1, 1, 1, 1, 0)); // 10: top-right
77 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, 0.5f, -1, 0, 0, 1, 1, 1, 1, 1, 1)); // 11: bottom-right
78
79 // Right face (+X)
80 //Position | Normal | Tangent | UV
81 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, 0.5f, 1, 0, 0, 1, 1, 1, 1, 0, 1)); // 12: bottom-left
82 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, 0.5f, 0.5f, 1, 0, 0, 1, 1, 1, 1, 0, 0)); // 13: top-left
83 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, 0.5f, -0.5f, 1, 0, 0, 1, 1, 1, 1, 1, 0)); // 14: top-right
84 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, -0.5f, 1, 0, 0, 1, 1, 1, 1, 1, 1)); // 15: bottom-right
85
86 // Top face (+Y)
87 //Position | Normal | Tangent | UV
88 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, 0.5f, 0.5f, 0, 1, 0, 0, 1, 1, 1, 0, 1)); // 16: bottom-left
89 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, 0.5f, -0.5f, 0, 1, 0, 1, 1, 1, 1, 0, 0)); // 17: top-left
90 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, 0.5f, -0.5f, 0, 1, 0, 1, 1, 1, 1, 1, 0)); // 18: top-right
91 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, 0.5f, 0.5f, 0, 1, 0, 1, 1, 0, 1, 1, 1)); // 19: bottom-right
92
93 // Bottom face (-Y)
94 //Position | Normal | Tangent | UV
95 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, -0.5f, 0, -1, 0, 1, 1, 1, 1, 0, 1)); // 20: bottom-left
96 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, 0.5f, 0, -1, 0, 1, 1, 1, 1, 0, 0)); // 21: top-left
97 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, 0.5f, 0, -1, 0, 1, 1, 1, 1, 1, 0)); // 22: top-right
98 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, -0.5f, 0, -1, 0, 1, 1, 1, 1, 1, 1)); // 23: bottom-right
99
100 mesh.indices = {// Front face
101 0, 1, 2, 0, 2, 3,
102 // Back face
103 4, 5, 6, 4, 6, 7,
104 // Left face
105 8, 9, 10, 8, 10, 11,
106 // Right face
107 12, 13, 14, 12, 14, 15,
108 // Top face
109 16, 17, 18, 16, 18, 19,
110 // Bottom face
111 20, 21, 22, 20, 22, 23};
112 return mesh;
113}
114
115/// Builds a UV sphere of unit radius with the given stack/slice resolution.
116inline Sleak::MeshData GetSphereMesh(int stacks = 16, int slices = 16) {
117 Sleak::MeshData mesh;
118
119 for (int i = 0; i <= stacks; ++i) {
120 float phi = PI * i / stacks;
121 for (int j = 0; j <= slices; ++j) {
122 float theta = 2 * PI * j / slices;
123 float x = sin(phi) * cos(theta);
124 float y = cos(phi);
125 float z = sin(phi) * sin(theta);
126
127 mesh.vertices.AddVertex(Sleak::Vertex(x, y, z, // position
128 x, y, z, //Normal
129 -sin(theta), 0, cos(theta), // Tangent
130 (float)j / slices, (float)i / stacks)); //UV
131 }
132 }
133
134 for (int i = 0; i < stacks; ++i) {
135 for (int j = 0; j < slices; ++j) {
136 int first = i * (slices + 1) + j;
137 int second = first + slices + 1;
138 mesh.indices.add(first);
139 mesh.indices.add(second);
140 mesh.indices.add(first + 1);
141 mesh.indices.add(second);
142 mesh.indices.add(second + 1);
143 mesh.indices.add(first + 1);
144 }
145 }
146 return mesh;
147}
148
149/// Builds a capped cylinder centered at the origin, extending +/- height/2 along Y.
150inline Sleak::MeshData GetCylinderMesh(int segments, float height, float radius) {
151 Sleak::MeshData mesh;
152
153 // Generate side vertices (centered at origin)
154 for (int i = 0; i <= segments; ++i) {
155 float theta = 2.0f * PI * i / segments;
156 float x = cos(theta) * radius;
157 float z = sin(theta) * radius;
158
159 // Side vertices (with proper normals)
161 x, -height/2, z, // Bottom vertex
162 cos(theta), 0, sin(theta), // Side normal
163 -sin(theta), 0, cos(theta), // Tangent
164 i/(float)segments, 0
165 ));
166
168 x, height/2, z, // Top vertex
169 cos(theta), 0, sin(theta), // Side normal
170 -sin(theta), 0, cos(theta), // Tangent
171 i/(float)segments, 1
172 ));
173 }
174
175 // Center vertices for caps
177 0, -height/2, 0, 0, -1, 0, 1, 0, 0, 0.5f, 0.5f
178 ));
179 int bottomCenter = mesh.vertices.GetSize() - 1;
180
182 0, height/2, 0, 0, 1, 0, 1, 0, 0, 0.5f, 0.5f
183 ));
184 int topCenter = mesh.vertices.GetSize() - 1;
185
186 // Generate indices
187 for (int i = 0; i < segments; ++i) {
188 int base = i * 2;
189
190 // Side quads
191 mesh.indices.add(base);
192 mesh.indices.add(base + 1);
193 mesh.indices.add(base + 2);
194
195 mesh.indices.add(base + 1);
196 mesh.indices.add(base + 3);
197 mesh.indices.add(base + 2);
198
199 // Bottom cap
200 mesh.indices.add(base);
201 mesh.indices.add(base + 2);
202 mesh.indices.add(bottomCenter);
203
204 // Top cap
205 mesh.indices.add(base + 1);
206 mesh.indices.add(topCenter);
207 mesh.indices.add(base + 3);
208 }
209
210 return mesh;
211}
212
213/// Builds a capsule (cylinder with hemispherical caps) centered at the origin.
214inline Sleak::MeshData GetCapsuleMesh(int segments, int rings, float height, float radius) {
215 Sleak::MeshData mesh;
216 float halfHeight = height * 0.5f;
217
218 // Generate vertices
219 for (int i = 0; i <= rings; ++i) {
220 float phi = PI * i / rings; // Now from 0 to PI (top to bottom)
221 for (int j = 0; j <= segments; ++j) {
222 float theta = 2.0f * PI * j / segments;
223 float x = sin(phi) * cos(theta) * radius;
224 float y = cos(phi) * radius;
225 float z = sin(phi) * sin(theta) * radius;
226
227 // Adjust y position for hemispheres
228 if (i <= rings/2) {
229 y -= halfHeight; // Bottom hemisphere
230 } else {
231 y += halfHeight; // Top hemisphere
232 }
233
234 // Correct normal calculation
236 sin(phi) * cos(theta),
237 cos(phi),
238 sin(phi) * sin(theta)
239 ).Normalize();
240
242 x, y, z,
243 normal.GetX(), normal.GetY(), normal.GetZ(),
244 -sin(theta), 0, cos(theta), // Correct tangent
245 j / (float)segments, i / (float)rings
246 ));
247 }
248 }
249
250 // Generate indices (fixed winding order)
251 for (int i = 0; i < rings; ++i) {
252 for (int j = 0; j < segments; ++j) {
253 int first = i * (segments + 1) + j;
254 int second = first + segments + 1;
255
256 mesh.indices.add(first);
257 mesh.indices.add(second);
258 mesh.indices.add(first + 1);
259
260 mesh.indices.add(second);
261 mesh.indices.add(second + 1);
262 mesh.indices.add(first + 1);
263 }
264 }
265
266 return mesh;
267}
268
269/// Builds a torus (donut) mesh spanning innerRadius to outerRadius.
270inline Sleak::MeshData GetTorusMesh(int segments, int rings, float innerRadius, float outerRadius) {
271 Sleak::MeshData mesh;
272
273 float radius = (outerRadius - innerRadius) / 2.0f;
274 float center = innerRadius + radius;
275
276 // Generate vertices
277 for (int i = 0; i <= rings; ++i) {
278 float phi = 2.0f * PI * i / rings; // Ring angle
279 for (int j = 0; j <= segments; ++j) {
280 float theta = 2.0f * PI * j / segments; // Segment angle
281 float x = (center + radius * cos(theta)) * cos(phi);
282 float y = radius * sin(theta);
283 float z = (center + radius * cos(theta)) * sin(phi);
284
286 x, y, z, // Position
287 cos(theta) * cos(phi), sin(theta), cos(theta) * sin(phi), // Normal
288 1, 0, 0, // Tangent
289 j / (float)segments, i / (float)rings // UV
290 ));
291 }
292 }
293
294 // Generate indices
295 for (int i = 0; i < rings; ++i) {
296 for (int j = 0; j < segments; ++j) {
297 int first = i * (segments + 1) + j;
298 int second = first + segments + 1;
299
300 // First triangle
301 mesh.indices.add(first);
302 mesh.indices.add(second);
303 mesh.indices.add(first + 1);
304
305 // Second triangle
306 mesh.indices.add(second);
307 mesh.indices.add(second + 1);
308 mesh.indices.add(first + 1);
309 }
310 }
311
312 return mesh;
313}
314
315/// Builds a square-based pyramid (4 triangular faces plus a quad base).
317 Sleak::MeshData mesh;
318
319 // Vertices
320 mesh.vertices.AddVertex(Sleak::Vertex(0, 0.5f, 0, 0, 1, 0, 1, 0, 0, 0, 0.5f, 1)); // Apex
321 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, 0.5f, 0, -1, 1, 1, 0, 0, 0, 0, 0)); // Bottom-left
322 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, 0.5f, 0, -1, 1, 1, 0, 0, 0, 1, 0)); // Bottom-right
323 mesh.vertices.AddVertex(Sleak::Vertex(0.5f, -0.5f, -0.5f, 0, -1, 1, 1, 0, 0, 0, 1, 1)); // Back-right
324 mesh.vertices.AddVertex(Sleak::Vertex(-0.5f, -0.5f, -0.5f, 0, -1, 1, 1, 0, 0, 0, 0, 1)); // Back-left
325
326 // Indices
327 // Base
328 mesh.indices.add(1);
329 mesh.indices.add(2);
330 mesh.indices.add(3);
331 mesh.indices.add(1);
332 mesh.indices.add(3);
333 mesh.indices.add(4);
334
335 // Faces
336 mesh.indices.add(0);
337 mesh.indices.add(1);
338 mesh.indices.add(2);
339
340 mesh.indices.add(0);
341 mesh.indices.add(2);
342 mesh.indices.add(3);
343
344 mesh.indices.add(0);
345 mesh.indices.add(3);
346 mesh.indices.add(4);
347
348 mesh.indices.add(0);
349 mesh.indices.add(4);
350 mesh.indices.add(1);
351
352 return mesh;
353}
int width
int height
Sleak::MeshData GetPlaneMesh(float width, float height, int subdivisionsX=1, int subdivisionsY=1)
Builds a subdivided flat quad on the XZ plane, facing up.
Sleak::MeshData GetPyramidMesh()
Builds a square-based pyramid (4 triangular faces plus a quad base).
Sleak::MeshData GetCapsuleMesh(int segments, int rings, float height, float radius)
Builds a capsule (cylinder with hemispherical caps) centered at the origin.
Sleak::MeshData GetCylinderMesh(int segments, float height, float radius)
Builds a capped cylinder centered at the origin, extending +/- height/2 along Y.
Sleak::MeshData GetSphereMesh(int stacks=16, int slices=16)
Builds a UV sphere of unit radius with the given stack/slice resolution.
Sleak::MeshData GetCubeMesh()
Builds a unit cube with per-face vertices for hard-edged normals.
Sleak::MeshData GetTorusMesh(int segments, int rings, float innerRadius, float outerRadius)
Builds a torus (donut) mesh spanning innerRadius to outerRadius.
#define PI
Definition Math.hpp:7
void add(const T &value)
Definition List.hpp:113
float GetY() const
Definition Vector.hpp:361
float GetX() const
Definition Vector.hpp:360
Vector3D & Normalize()
Definition Vector.hpp:435
float GetZ() const
Definition Vector.hpp:362
void AddVertex(const Vertex &vertex)
Definition MeshData.hpp:80
size_t GetSize() const
Definition MeshData.hpp:91
IndexGroup indices
Definition MeshData.hpp:105
VertexGroup vertices
Definition MeshData.hpp:104