TerraForge3D  2.3.1
3D Terrain And Landscape Generator
Mesh.cpp
1#include <Mesh.h>
2
3#include <glm/gtc/constants.hpp>
4#include <glm/gtc/quaternion.hpp>
5#include <glm/gtc/matrix_transform.hpp>
6#include <glm/ext/matrix_relational.hpp>
7#include <glm/ext/vector_relational.hpp>
8#include <glm/ext/scalar_relational.hpp>
9#include <glm/gtc/type_ptr.hpp>
10
11#include <cmath>
12
13
14#include <immintrin.h>
15
16
17// Load an FP32 3D vector from memory
18inline __m128 loadFloat3( const glm::vec3 &pos )
19{
20 static_assert( sizeof( glm::vec3 ) == 12, "Expected to be 12 bytes (3 floats)" );
21 __m128 low = _mm_castpd_ps( _mm_load_sd( (const double *)&pos ) );
22 // Modern compilers are optimizing the following 2 intrinsics into a single insertps with a memory operand
23 __m128 high = _mm_load_ss( ( (const float *)&pos ) + 2 );
24 return _mm_insert_ps( low, high, 0x27 );
25}
26
27// Store an FP32 3D vector to memory
28inline void storeFloat3( glm::vec3 &pos, __m128 vec )
29{
30 _mm_store_sd( (double *)&pos, _mm_castps_pd( vec ) );
31 ( (int *)( &pos ) )[ 2 ] = _mm_extract_ps( vec, 2 );
32}
33
34// Normalize a 3D vector; if the source is zero, will instead return a zero vector
35inline __m128 vector3Normalize( __m128 vec )
36{
37 // Compute x^2 + y^2 + z^2, broadcast the result to all 4 lanes
38 __m128 dp = _mm_dp_ps( vec, vec, 0b01111111 );
39 // res = vec / sqrt( dp )
40 __m128 res = _mm_div_ps( vec, _mm_sqrt_ps( dp ) );
41 // Compare for dp > 0
42 __m128 positiveLength = _mm_cmpgt_ps( dp, _mm_setzero_ps() );
43 // Zero out the vector if the dot product was zero
44 return _mm_and_ps( res, positiveLength );
45}
46
47// Copy-pasted from there: https://github.com/microsoft/DirectXMath/blob/jan2021/Inc/DirectXMathVector.inl#L9506-L9519
48// MIT license
49#ifdef __AVX__
50#define XM_PERMUTE_PS( v, c ) _mm_permute_ps( v, c )
51#else
52#define XM_PERMUTE_PS( v, c ) _mm_shuffle_ps( v, v, c )
53#endif
54
55#ifdef __AVX2__
56#define XM_FNMADD_PS( a, b, c ) _mm_fnmadd_ps((a), (b), (c))
57#else
58#define XM_FNMADD_PS( a, b, c ) _mm_sub_ps((c), _mm_mul_ps((a), (b)))
59#endif
60
61inline __m128 vector3Cross( __m128 V1, __m128 V2 )
62{
63 // y1,z1,x1,w1
64 __m128 vTemp1 = XM_PERMUTE_PS( V1, _MM_SHUFFLE( 3, 0, 2, 1 ) );
65 // z2,x2,y2,w2
66 __m128 vTemp2 = XM_PERMUTE_PS( V2, _MM_SHUFFLE( 3, 1, 0, 2 ) );
67 // Perform the left operation
68 __m128 vResult = _mm_mul_ps( vTemp1, vTemp2 );
69 // z1, x1, y1, w1
70 vTemp1 = XM_PERMUTE_PS( vTemp1, _MM_SHUFFLE( 3, 0, 2, 1 ) );
71 // y2, z2, x2, w2
72 vTemp2 = XM_PERMUTE_PS( vTemp2, _MM_SHUFFLE( 3, 1, 0, 2 ) );
73 // Perform the right operation
74 vResult = XM_FNMADD_PS( vTemp1, vTemp2, vResult );
75 return vResult;
76}
77
78// QUICK HACKS
79
80#define VEC3_SUB(a, b, out) out.x = a.x - b.x; \
81 out.y = a.y - b.y; \
82 out.z = a.z - b.z;
83
84#define VEC3_ADD(a, b, out) out.x = a.x + b.x; \
85 out.y = a.y + b.y; \
86 out.z = a.z + b.z;
87/*
88// Does not work in 64 bit mode
89inline float __fastcall asm_sqrt(float n)
90{
91 _asm fld dword ptr [esp+4]
92 _asm fsqrt
93 _asm ret 4
94}
95*/
96
97inline float Q_rsqrt(float number)
98{
99 long i;
100 float x2, y;
101 const float threehalfs = 1.5F;
102 x2 = number * 0.5F;
103 y = number;
104 i = *(long *) &y;
105 i = 0x5f3759df - (i >> 1);
106 y = *(float *) &i;
107 y = y * (threehalfs - (x2 * y * y));
108 // y = y * (threehalfs - (x2 * y * y));
109 return y;
110}
111
112#define VEC3_NORMALIZE(v, out) \
113{ \
114 \
115 float tempLength = ( (v.x) * (v.x) ) + ( (v.y) * (v.y) ) +( (v.z) * (v.z) ); \
116 float lengthSqrauedI = Q_rsqrt(tempLength); \
117 out.x = (v.x) * lengthSqrauedI; \
118 out.y = (v.y) * lengthSqrauedI; \
119 out.z = (v.z) * lengthSqrauedI; \
120}
121
122#define VEC3_CROSS(a, b, out) \
123{ \
124 out.x = ( (a.y) * (b.z) ) - ( (a.z) * (b.y) ); \
125 out.y = ( (a.z) * (b.x) ) - ( (a.x) * (b.z) ); \
126 out.z = ( (a.x) * (b.y) ) - ( (a.y) * (b.x) ); \
127}
128
129// QUICK HACKS
130
131Mesh::Mesh()
132{
133 vert = nullptr;
134 indices = nullptr;
135}
136
137Mesh::~Mesh()
138{
139 if (deleteOnDestruction)
140 {
141 if (vert)
142 {
143 delete vert;
144 }
145
146 if (indices)
147 {
148 delete indices;
149 }
150 }
151}
152
153void Mesh::ClearNormals()
154{
155 for(int i = 0 ; i < vertexCount ; i++)
156 {
157 vert[i].normal.x = 0.0f;
158 vert[i].normal.y = 0.0f;
159 vert[i].normal.z = 0.0f;
160 }
161}
162
163void Mesh::RecalculateNormals()
164{
165 glm::vec3 e1;
166 glm::vec3 e2;
167 glm::vec3 no;
168 int iabc[3];
169
170 for (int i = 0; i < indexCount; i += 3)
171 {
172 iabc[0] = indices[i];
173 iabc[1] = indices[i + 1];
174 iabc[2] = indices[i + 2];
175 glm::vec4 &tmp4a = vert[iabc[0]].position;
176 glm::vec4 &tmp4b = vert[iabc[1]].position;
177 glm::vec4 &tmp4c = vert[iabc[2]].position;
178 VEC3_SUB(tmp4a, tmp4b, e1);
179 VEC3_SUB(tmp4c, tmp4b, e2);
180 VEC3_CROSS(e1, e2, no);
181 VEC3_ADD(vert[iabc[0]].normal, no, vert[iabc[0]].normal);
182 VEC3_ADD(vert[iabc[1]].normal, no, vert[iabc[1]].normal);
183 VEC3_ADD(vert[iabc[2]].normal, no, vert[iabc[2]].normal);
184 }
185
186 for (int i = 0; i < vertexCount; i++)
187 {
188 VEC3_NORMALIZE(vert[i].normal, vert[i].normal);
189 }
190}
191
192void Mesh::GenerateIcoSphere(int resolution, float radius, float textureScale)
193{
194 currType = MeshType::Icosphere;
195 glm::vec3 vertis[] =
196 {
197 glm::vec3(0, -1, 0),
198 glm::vec3(0, 0, 1),
199 glm::vec3(1, 0, 0),
200 glm::vec3(0, 0, -1),
201 glm::vec3(-1, 0, 0),
202 glm::vec3(0, 1, 0)
203 };
204 int triangles[] =
205 {
206 0, 1, 2,
207 0, 2, 3,
208 0, 3, 4,
209 0, 4, 1,
210
211 5, 2, 1,
212 5, 3, 2,
213 5, 4, 3,
214 5, 1, 4
215 };
216
217 for (int i = 0; i < sizeof(vertis)/sizeof(glm::vec3); i++)
218 {
219 vertis[i] *= radius;
220 }
221
222 vertexCount = sizeof(vertis)/sizeof(int);
223 vert = new Vert[sizeof(vertis) / sizeof(int)];
224 memset(vert, 0, sizeof(Vert) * vertexCount);
225
226 for (int i = 0; i < vertexCount; i++)
227 {
228 vert[i] = Vert();
229 vert[i].position = glm::vec4(vertis[i], 1);
230 }
231
232 indexCount = sizeof(triangles)/sizeof(int);
233 indices = new int[indexCount];
234 memcpy(indices, triangles, sizeof(int) * indexCount);
235}
236
237void Mesh::GeneratePlane(int resolution, float scale, float textureScale)
238{
239 currType = MeshType::Plane;
240 maxHeight = -100;
241 minHeight = 100;
242 res = resolution;
243 sc = scale;
244 texSc = textureScale;
245 Vert *vertices = new Vert[resolution * resolution];
246 int *inds = new int[(resolution-1) * (resolution-1) * 6];
247 int triIndex = 0;
248
249 for (int y = 0; y < resolution; y++)
250 {
251 for (int x = 0; x < resolution; x++)
252 {
253 int i = x + y * resolution;
254 glm::vec2 percent = glm::vec2(x, y) / ((float)resolution - 1);
255 glm::vec3 pointOnPlane = (percent.x - .5f) * 2 * right + (percent.y - .5f) * 2 * front;
256 pointOnPlane *= scale;
257 vertices[i] = Vert();
258 vertices[i].position = glm::vec4(0.0f);
259 vertices[i].position.x = (float)pointOnPlane.x;
260 vertices[i].position.y = (float)pointOnPlane.y;
261 vertices[i].position.z = (float)pointOnPlane.z;
262 vertices[i].texCoord = glm::vec2(percent.x, percent.y)*textureScale;
263 vertices[i].normal = glm::vec4(0.0f);
264
265 if (x != resolution - 1 && y != resolution - 1)
266 {
267 inds[triIndex] = i;
268 inds[triIndex + 1] = i + resolution + 1;
269 inds[triIndex + 2] = i + resolution;
270 inds[triIndex + 3] = i;
271 inds[triIndex + 4] = i + 1;
272 inds[triIndex + 5] = i + resolution + 1;
273 triIndex += 6;
274 }
275
276 vertices[i].extras1 = glm::vec4(0.0f);
277 }
278 }
279
280 if (vert)
281 {
282 delete vert;
283 }
284
285 if (indices)
286 {
287 delete indices;
288 }
289
290 vertexCount = resolution * resolution;
291 vert = new Vert[resolution * resolution];
292 memset(vert, 0, sizeof(Vert) * vertexCount);
293 memcpy(vert, vertices, sizeof(Vert)*vertexCount);
294 indexCount = (resolution - 1) * (resolution - 1) * 6;
295 indices = new int[(resolution - 1) * (resolution - 1) * 6];
296 memset(indices, 0, indexCount);
297 memcpy(indices, inds, sizeof(int) * indexCount);
298 delete vertices;
299 delete inds;
300}
301
302void Mesh::GenerateScreenQuad(float dist)
303{
304 if (vert)
305 {
306 delete[] vert;
307 }
308
309 if (indices)
310 {
311 delete[] indices;
312 }
313
314 Vert v;
315 vert = new Vert[4];
316 v.position = glm::vec4(-1, -1, dist, 0);
317 v.texCoord = glm::vec2(0, 0);
318 vert[0] = v;
319 v.position = glm::vec4(-1, 1, dist, 0);
320 v.texCoord = glm::vec2(0, 1);
321 vert[1] = v;
322 v.position = glm::vec4(1, 1, dist, 0);
323 v.texCoord = glm::vec2(1, 1);
324 vert[2] = v;
325 v.position = glm::vec4(1, -1, dist, 0);
326 v.texCoord = glm::vec2(1, 0);
327 vert[3] = v;
328 vertexCount = 4;
329 indexCount = 6;
330 indices = new int[6];
331 indices[0] = 0;
332 indices[1] = 1;
333 indices[2] = 2;
334 indices[3] = 0;
335 indices[4] = 2;
336 indices[5] = 3;
337}
338
339void Mesh::SetElevation(float elevation, int x, int y)
340{
341 if(!vert)
342 {
343 return;
344 }
345
346 int i = x + y * res;
347
348 if (i > vertexCount)
349 {
350 return;
351 }
352
353 if (elevation > maxHeight)
354 {
355 maxHeight = elevation;
356 }
357
358 if (elevation < minHeight)
359 {
360 minHeight = elevation;
361 }
362
363 vert[i].position.y = elevation;
364 vert[i].extras1.x = elevation;
365}
366
367float Mesh::GetElevation(int x, int y)
368{
369 if (!vert)
370 {
371 return 0;
372 }
373
374 int i = x + y * res;
375
376 if (i > vertexCount)
377 {
378 return 0;
379 }
380
381 return vert[i].position.y;
382}
383
384glm::vec3 Mesh::GetNormals(int x, int y)
385{
386 if (!vert)
387 {
388 return glm::vec3(0);
389 }
390
391 int i = x + y * res;
392
393 if (i > vertexCount)
394 {
395 return glm::vec3(0);
396 }
397
398 return glm::vec3(vert[i].normal.x, vert[i].normal.y, vert[i].normal.z);
399}
400
401void Mesh::AddElevation(float elevation, int x, int y)
402{
403 if(!vert)
404 {
405 return;
406 }
407
408 int i = x + y * res;
409
410 if (i > vertexCount)
411 {
412 return;
413 }
414
415 vert[i].position.y += elevation;
416}
417
418glm::vec2 Mesh::GetTexCoord(float x, float y, float z)
419{
420 if (currType == MeshType::Plane)
421 {
422 return (glm::vec2(x, y) / ((float)res - 1)) * texSc;
423 }
424
425 else
426 {
427 return glm::vec2(1.0f);
428 }
429}
430
431Mesh *Mesh::Clone()
432{
433 Mesh *cloneMesh = new Mesh();
434 cloneMesh->res = res;
435 cloneMesh->sc = sc;
436 cloneMesh->maxHeight = maxHeight;
437 cloneMesh->vertexCount = vertexCount;
438 cloneMesh->indexCount = indexCount;
439 cloneMesh->vert = new Vert[vertexCount];
440 memcpy(cloneMesh->vert, vert, sizeof(Vert) * vertexCount);
441 cloneMesh->indices = new int[indexCount];
442 memcpy(cloneMesh->indices, indices, sizeof(int) * indexCount);
443 return cloneMesh;
444}
445
446bool Mesh::IsValid()
447{
448 if (vert && indices)
449 {
450 return true;
451 }
452
453 return false;
454}
Definition: Mesh.h:21
Definition: Mesh.h:13