@woosh/meep-engine 2.40.1 → 2.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/core/collection/HashMap.d.ts +2 -0
  2. package/core/collection/HashMap.js +22 -0
  3. package/core/geom/3d/apply_mat4_transform_to_v3_array.js +2 -4
  4. package/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +5 -0
  5. package/core/geom/3d/normal/octahedron/decode_octahedron_to_unit.js +31 -0
  6. package/core/geom/3d/normal/octahedron/encode_unit_to_octahedron.js +33 -0
  7. package/core/geom/3d/normal/octahedron/encoding.spec.js +29 -0
  8. package/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +28 -0
  9. package/core/geom/3d/topology/struct/BinaryTopology.js +112 -0
  10. package/core/geom/Quaternion.js +14 -0
  11. package/core/math/sign_not_zero.js +8 -0
  12. package/core/parser/simple/SimpleParser.js +3 -86
  13. package/core/parser/simple/readUnsignedInteger.js +66 -0
  14. package/core/parser/simple/skipWhitespace.js +21 -0
  15. package/engine/EngineHarness.js +13 -3
  16. package/engine/asset/AssetDescription.spec.js +27 -0
  17. package/engine/asset/loaders/GLTFAssetLoader.js +5 -3
  18. package/engine/ecs/foliage/ImpostorFoliage.js +4 -0
  19. package/engine/ecs/transform/Transform.js +23 -3
  20. package/engine/graphics/ecs/decal/v2/Decal.d.ts +11 -0
  21. package/engine/graphics/ecs/decal/v2/Decal.js +50 -0
  22. package/engine/graphics/ecs/decal/v2/FPDecalSystem.d.ts +8 -0
  23. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +213 -0
  24. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +237 -0
  25. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -1
  26. package/engine/graphics/ecs/mesh-v2/build_three_object.js +4 -0
  27. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +22 -7
  28. package/engine/graphics/filter/ImageFilter.js +2 -1
  29. package/engine/graphics/geometry/MikkT/MikkTSpace.js +466 -305
  30. package/engine/graphics/geometry/MikkT/MikkTSpace.spec.js +7 -1
  31. package/engine/{asset/loaders/geometry/geometry → graphics/geometry/buffered}/computeBufferAttributeHash.js +1 -1
  32. package/engine/{asset/loaders/geometry/geometry → graphics/geometry/buffered}/computeGeometryEquality.js +2 -2
  33. package/engine/{asset/loaders/geometry/geometry → graphics/geometry/buffered}/computeGeometryHash.js +1 -1
  34. package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +2 -2
  35. package/engine/graphics/impostors/card_cluster/FacePlaneAssignment.js +30 -0
  36. package/engine/graphics/impostors/card_cluster/README.md +13 -0
  37. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +345 -0
  38. package/engine/graphics/impostors/octahedral/ImpostorCaptureType.js +10 -0
  39. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +69 -0
  40. package/engine/graphics/impostors/octahedral/README.md +30 -0
  41. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere.js +45 -0
  42. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere_radius_only.js +37 -0
  43. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +117 -0
  44. package/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +20 -0
  45. package/engine/graphics/impostors/octahedral/grid/OctahedralUvEncoder.js +25 -0
  46. package/engine/graphics/impostors/octahedral/grid/UvEncoder.js +21 -0
  47. package/engine/graphics/impostors/octahedral/prototypeBaker.js +237 -0
  48. package/engine/graphics/impostors/octahedral/shader/BakeShaderStandard.js +196 -0
  49. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderStandard.js +306 -0
  50. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +349 -0
  51. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV1.js +74 -0
  52. package/engine/graphics/impostors/octahedral/shader/glsl/common.glsl +206 -0
  53. package/engine/graphics/impostors/octahedral/shader/glsl/v1/common.glsl +209 -0
  54. package/engine/graphics/impostors/octahedral/shader/glsl/v1/flagment.glsl +80 -0
  55. package/engine/graphics/impostors/octahedral/shader/glsl/v1/vertex.glsl +350 -0
  56. package/engine/graphics/micron/convert_three_object_to_micron.js +2 -2
  57. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +2 -2
  58. package/engine/graphics/micron/render/v1/getTransformedPositionsCached.js +1 -1
  59. package/engine/graphics/particles/node-based/codegen/CodeGenerator.js +1 -1
  60. package/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.js +1 -1
  61. package/engine/graphics/render/forward_plus/LightManager.js +1 -1
  62. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +1 -3
  63. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
  64. package/engine/graphics/render/forward_plus/model/Decal.js +19 -2
  65. package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +32 -10
  66. package/engine/graphics/shaders/ScreenSpaceQuadShader.js +4 -14
  67. package/engine/graphics/shaders/glsl_gen_swizzled_read.js +39 -0
  68. package/engine/graphics/texture/sampler/Sampler2D.js +10 -10
  69. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +117 -11
  70. package/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +66 -0
  71. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +2 -2
  72. package/engine/ui/GUIEngine.js +8 -1
  73. package/package.json +1 -1
  74. package/view/tooltip/gml/parser/readReferenceToken.js +1 -1
  75. package/engine/asset/GameAssetManager.js +0 -137
@@ -2,30 +2,36 @@ import { assert } from "../../../../core/assert.js";
2
2
  import { EPSILON } from "../../../../core/math/MathUtils.js";
3
3
  import { array_copy } from "../../../../core/collection/array/copyArray.js";
4
4
  import { fabsf } from "../../../../core/math/fabsf.js";
5
-
6
- // To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
7
- // normal map sampler must use the exact inverse of the pixel shader transformation.
8
- // The most efficient transformation we can possibly do in the pixel shader is
9
- // achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
10
- // pixel shader (fast transform out)
11
- // vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
12
- // where vNt is the tangent space normal. The normal map sampler must likewise use the
13
- // interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
14
- // sampler does (exact inverse of pixel shader):
15
- // float3 row0 = cross(vB, vN);
16
- // float3 row1 = cross(vN, vT);
17
- // float3 row2 = cross(vT, vB);
18
- // float fSign = dot(vT, row0)<0 ? -1 : 1;
19
- // vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
20
- // where vNout is the sampled normal in some chosen 3D space.
21
- //
22
- // Should you choose to reconstruct the bitangent in the pixel shader instead
23
- // of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
24
- // Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
25
- // quads as your renderer then problems will occur since the interpolated tangent spaces will differ
26
- // eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
27
- // sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
28
- // However, this must be used both by the sampler and your tools/rendering pipeline.
5
+ import { v3_distance_sqr } from "../../../../core/geom/v3_distance_sqr.js";
6
+
7
+
8
+ /*
9
+ To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
10
+ normal map sampler must use the exact inverse of the pixel shader transformation.
11
+ The most efficient transformation we can possibly do in the pixel shader is
12
+ achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
13
+ pixel shader (fast transform out)
14
+ vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
15
+ where vNt is the tangent space normal. The normal map sampler must likewise use the
16
+ interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
17
+ sampler does (exact inverse of pixel shader):
18
+ float3 row0 = cross(vB, vN);
19
+ float3 row1 = cross(vN, vT);
20
+ float3 row2 = cross(vT, vB);
21
+ float fSign = dot(vT, row0)<0 ? -1 : 1;
22
+ vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
23
+ where vNout is the sampled normal in some chosen 3D space.
24
+
25
+ Should you choose to reconstruct the bitangent in the pixel shader instead
26
+ of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
27
+ Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
28
+ quads as your renderer then problems will occur since the interpolated tangent spaces will differ
29
+ eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
30
+ sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
31
+ However, this must be used both by the sampler and your tools/rendering pipeline.
32
+
33
+ @see https://github.com/mmikk/MikkTSpace/blob/master/mikktspace.c
34
+ */
29
35
 
30
36
 
31
37
  /**
@@ -63,6 +69,12 @@ class SVec3 {
63
69
  this.z = v;
64
70
  }
65
71
 
72
+ copy(other) {
73
+ this.x = other.x;
74
+ this.y = other.y;
75
+ this.z = other.z;
76
+ }
77
+
66
78
  }
67
79
 
68
80
  class SEdge {
@@ -124,9 +136,9 @@ class STSpace {
124
136
  * @param {STSpace} other
125
137
  */
126
138
  copy(other) {
127
- this.vOs = other.vOs;
139
+ this.vOs.copy(other.vOs);
128
140
  this.fMagS = other.fMagS;
129
- this.vOt = other.vOt;
141
+ this.vOt.copy(other.vOt);
130
142
  this.fMagT = other.fMagT;
131
143
  this.iCounter = other.iCounter;
132
144
  this.bOrient = other.bOrient;
@@ -143,7 +155,7 @@ class SSubGroup {
143
155
 
144
156
  /**
145
157
  * *int
146
- * @type {null}
158
+ * @type {Int32Array|null}
147
159
  */
148
160
  this.pTriMembers = null;
149
161
  }
@@ -210,130 +222,6 @@ class STriInfo {
210
222
  }
211
223
  }
212
224
 
213
- class SMikkTSpaceInterface {
214
- constructor() {
215
-
216
- }
217
-
218
- /**
219
- * Returns the number of faces (triangles/quads) on the mesh to be processed.
220
- * @param {SMikkTSpaceContext} pContext
221
- * @returns {number}
222
- */
223
- m_getNumFaces(pContext) {
224
- return pContext.geometry_buffer_index.length / 3;
225
- }
226
-
227
- /**
228
- * Returns the number of vertices on face number iFace
229
- * iFace is a number in the range {0, 1, ..., getNumFaces()-1}
230
- * @param {SMikkTSpaceContext} pContext
231
- * @param {number} iFace
232
- * @returns {number}
233
- */
234
- m_getNumVerticesOfFace(pContext, iFace) {
235
- // only support triangles
236
- return 3;
237
- }
238
-
239
- // returns the position/normal/texcoord of the referenced face of vertex number iVert.
240
- // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
241
-
242
- /**
243
- *
244
- * @param {SMikkTSpaceContext} pContext
245
- * @param {number[]|{0:number,1:number,2:number}} fvPosOut
246
- * @param {number} iFace
247
- * @param {number} iVert
248
- * @returns {void}
249
- */
250
- m_getPosition(pContext, fvPosOut, iFace, iVert) {
251
- // figure out which vertex it is
252
- const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
253
-
254
- array_copy(pContext.geometry_buffer_vertex_position, vertex_index * 3, fvPosOut, 0, 3);
255
- }
256
-
257
- /**
258
- *
259
- * @param {SMikkTSpaceContext} pContext
260
- * @param {number[]|{0:number,1:number,2:number}} fvNormOut
261
- * @param {number} iFace
262
- * @param {number} iVert
263
- * @returns {void}
264
- */
265
- m_getNormal(pContext, fvNormOut, iFace, iVert) {
266
- // figure out which vertex it is
267
- const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
268
-
269
- array_copy(pContext.geometry_buffer_vertex_normal, vertex_index * 3, fvNormOut, 0, 3);
270
- }
271
-
272
- /**
273
- *
274
- * @param {SMikkTSpaceContext} pContext
275
- * @param {number[]|{0:number,1:number}} fvTexcOut
276
- * @param {number} iFace
277
- * @param {number} iVert
278
- * @returns {void}
279
- */
280
- m_getTexCoord(pContext, fvTexcOut, iFace, iVert) {
281
- // figure out which vertex it is
282
- const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
283
-
284
- array_copy(pContext.geometry_buffer_vertex_uv, vertex_index * 2, fvTexcOut, 0, 3);
285
- }
286
-
287
- /**
288
- * either (or both) of the two setTSpace callbacks can be set.
289
- * The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
290
- *
291
- * This function is used to return the tangent and fSign to the application.
292
- * fvTangent is a unit length vector.
293
- * For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
294
- * bitangent = fSign * cross(vN, tangent);
295
- * Note that the results are returned unindexed. It is possible to generate a new index list
296
- * But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
297
- * DO NOT! use an already existing index list.
298
- *
299
- * @param {SMikkTSpaceContext} pContext
300
- * @param {number[]} fvTangent
301
- * @param {number} fSign
302
- * @param {number} iFace
303
- * @param {number} iVert
304
- * @returns {void}
305
- */
306
- m_setTSpaceBasic(pContext, fvTangent, fSign, iFace, iVert) {
307
- throw new Error('Not supported');
308
- }
309
-
310
- /**
311
- *
312
- * @param {SMikkTSpaceContext} pContext
313
- * @param {number[]} fvTangent
314
- * @param {number[]} fvBiTangent
315
- * @param {number} fMagS
316
- * @param {number} fMagT
317
- * @param {boolean} bIsOrientationPreserving
318
- * @param {number} iFace
319
- * @param {number} iVert
320
- * @returns {void}
321
- */
322
- m_setTSpace(pContext, fvTangent, fvBiTangent, fMagS, fMagT, bIsOrientationPreserving, iFace, iVert) {
323
- // figure out which vertex it is
324
- const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
325
-
326
- const tangent_destination = pContext.geometry_buffer_vertex_tangent;
327
- const tangent_address = vertex_index * 4;
328
-
329
- // for logic explanation, see https://github.com/gltf-rs/mikktspace/blob/6275cc4f15cff8be29819fb34ae8be3b9129dae1/src/lib.rs#L33
330
- tangent_destination[tangent_address] = fvTangent[0];
331
- tangent_destination[tangent_address + 1] = fvTangent[1];
332
- tangent_destination[tangent_address + 2] = fvTangent[2];
333
- tangent_destination[tangent_address + 3] = bIsOrientationPreserving ? 1 : -1;
334
- }
335
- }
336
-
337
225
  export class SMikkTSpaceContext {
338
226
  constructor() {
339
227
  /**
@@ -367,15 +255,127 @@ export class SMikkTSpaceContext {
367
255
  * @type {number[]}
368
256
  */
369
257
  this.geometry_buffer_vertex_bitangent = [];
370
-
371
- /**
372
- *
373
- * @type {SMikkTSpaceInterface|null}
374
- */
375
- this.m_pInterface = new SMikkTSpaceInterface();
376
258
  }
377
259
  }
378
260
 
261
+ /**
262
+ * Returns the number of faces (triangles/quads) on the mesh to be processed.
263
+ * @param {SMikkTSpaceContext} pContext
264
+ * @returns {number}
265
+ */
266
+ function m_getNumFaces(pContext) {
267
+ return pContext.geometry_buffer_index.length / 3;
268
+ }
269
+
270
+ /**
271
+ * Returns the number of vertices on face number iFace
272
+ * iFace is a number in the range {0, 1, ..., getNumFaces()-1}
273
+ * @param {SMikkTSpaceContext} pContext
274
+ * @param {number} iFace
275
+ * @returns {number}
276
+ */
277
+ function m_getNumVerticesOfFace(pContext, iFace) {
278
+ // only support triangles
279
+ return 3;
280
+ }
281
+
282
+ // returns the position/normal/texcoord of the referenced face of vertex number iVert.
283
+ // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
284
+
285
+ /**
286
+ *
287
+ * @param {SMikkTSpaceContext} pContext
288
+ * @param {number[]|{0:number,1:number,2:number}} fvPosOut
289
+ * @param {number} iFace
290
+ * @param {number} iVert
291
+ * @returns {void}
292
+ */
293
+ function m_getPosition(pContext, fvPosOut, iFace, iVert) {
294
+ // figure out which vertex it is
295
+ const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
296
+
297
+ array_copy(pContext.geometry_buffer_vertex_position, vertex_index * 3, fvPosOut, 0, 3);
298
+ }
299
+
300
+ /**
301
+ *
302
+ * @param {SMikkTSpaceContext} pContext
303
+ * @param {number[]|{0:number,1:number,2:number}} fvNormOut
304
+ * @param {number} iFace
305
+ * @param {number} iVert
306
+ * @returns {void}
307
+ */
308
+ function m_getNormal(pContext, fvNormOut, iFace, iVert) {
309
+ // figure out which vertex it is
310
+ const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
311
+
312
+ array_copy(pContext.geometry_buffer_vertex_normal, vertex_index * 3, fvNormOut, 0, 3);
313
+ }
314
+
315
+ /**
316
+ *
317
+ * @param {SMikkTSpaceContext} pContext
318
+ * @param {number[]|{0:number,1:number}} fvTexcOut
319
+ * @param {number} iFace
320
+ * @param {number} iVert
321
+ * @returns {void}
322
+ */
323
+ function m_getTexCoord(pContext, fvTexcOut, iFace, iVert) {
324
+ // figure out which vertex it is
325
+ const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
326
+
327
+ array_copy(pContext.geometry_buffer_vertex_uv, vertex_index * 2, fvTexcOut, 0, 3);
328
+ }
329
+
330
+ /**
331
+ * either (or both) of the two setTSpace callbacks can be set.
332
+ * The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
333
+ *
334
+ * This function is used to return the tangent and fSign to the application.
335
+ * fvTangent is a unit length vector.
336
+ * For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
337
+ * bitangent = fSign * cross(vN, tangent);
338
+ * Note that the results are returned unindexed. It is possible to generate a new index list
339
+ * But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
340
+ * DO NOT! use an already existing index list.
341
+ *
342
+ * @param {SMikkTSpaceContext} pContext
343
+ * @param {number[]} fvTangent
344
+ * @param {number} fSign
345
+ * @param {number} iFace
346
+ * @param {number} iVert
347
+ * @returns {void}
348
+ */
349
+ function m_setTSpaceBasic(pContext, fvTangent, fSign, iFace, iVert) {
350
+ throw new Error('Not supported');
351
+ }
352
+
353
+ /**
354
+ *
355
+ * @param {SMikkTSpaceContext} pContext
356
+ * @param {number[]} fvTangent
357
+ * @param {number[]} fvBiTangent
358
+ * @param {number} fMagS
359
+ * @param {number} fMagT
360
+ * @param {boolean} bIsOrientationPreserving
361
+ * @param {number} iFace
362
+ * @param {number} iVert
363
+ * @returns {void}
364
+ */
365
+ function m_setTSpace(pContext, fvTangent, fvBiTangent, fMagS, fMagT, bIsOrientationPreserving, iFace, iVert) {
366
+ // figure out which vertex it is
367
+ const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
368
+
369
+ const tangent_destination = pContext.geometry_buffer_vertex_tangent;
370
+ const tangent_address = vertex_index * 4;
371
+
372
+ // for logic explanation, see https://github.com/gltf-rs/mikktspace/blob/6275cc4f15cff8be29819fb34ae8be3b9129dae1/src/lib.rs#L33
373
+ tangent_destination[tangent_address] = fvTangent[0];
374
+ tangent_destination[tangent_address + 1] = fvTangent[1];
375
+ tangent_destination[tangent_address + 2] = fvTangent[2];
376
+ tangent_destination[tangent_address + 3] = bIsOrientationPreserving ? 1 : -1;
377
+ }
378
+
379
379
  const MARK_DEGENERATE = 1;
380
380
  const QUAD_ONE_DEGEN_TRI = 2;
381
381
  const GROUP_WITH_ANY = 4;
@@ -395,34 +395,38 @@ function veq(v1, v2) {
395
395
 
396
396
  /**
397
397
  *
398
+ * @param {SVec3} res
398
399
  * @param {SVec3} v1
399
400
  * @param {SVec3} v2
400
- * @returns {SVec3}
401
401
  */
402
- function vadd(v1, v2) {
403
- const res = new SVec3();
402
+ function vadd(res, v1, v2) {
404
403
 
405
- res.x = v1.x + v2.x;
406
- res.y = v1.y + v2.y;
407
- res.z = v1.z + v2.z;
404
+ const x = v1.x + v2.x;
405
+ const y = v1.y + v2.y;
406
+ const z = v1.z + v2.z;
407
+
408
+ res.x = x;
409
+ res.y = y;
410
+ res.z = z;
408
411
 
409
- return res;
410
412
  }
411
413
 
412
414
  /**
413
415
  *
416
+ * @param {SVec3} res
414
417
  * @param {SVec3} v1
415
418
  * @param {SVec3} v2
416
- * @returns {SVec3}
417
419
  */
418
- function vsub(v1, v2) {
419
- const res = new SVec3();
420
+ function vsub(res, v1, v2) {
420
421
 
421
- res.x = v1.x - v2.x;
422
- res.y = v1.y - v2.y;
423
- res.z = v1.z - v2.z;
422
+ const x = v1.x - v2.x;
423
+ const y = v1.y - v2.y;
424
+ const z = v1.z - v2.z;
425
+
426
+ res.x = x;
427
+ res.y = y;
428
+ res.z = z;
424
429
 
425
- return res;
426
430
  }
427
431
 
428
432
  /**
@@ -450,6 +454,16 @@ function LengthSquared(v) {
450
454
  return v.x * v.x + v.y * v.y + v.z * v.z;
451
455
  }
452
456
 
457
+ /**
458
+ *
459
+ * @param {SVec3} v0
460
+ * @param {SVec3} v1
461
+ * @returns {number}
462
+ */
463
+ function DistanceSquared(v0, v1) {
464
+ return v3_distance_sqr(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z);
465
+ }
466
+
453
467
  /**
454
468
  *
455
469
  * @param {SVec3} v
@@ -462,11 +476,22 @@ function Length(v) {
462
476
 
463
477
  /**
464
478
  *
465
- * @param {SVec3} v
466
- * @returns {SVec3}
479
+ * @param {SVec3} out
480
+ * @param {SVec3} input
467
481
  */
468
- function Normalize(v) {
469
- return vscale(1 / Length(v), v);
482
+ function NormalizeSafe(out, input) {
483
+
484
+ const len = Length(input);
485
+
486
+ if (len !== 0) {
487
+ const m = 1 / len;
488
+
489
+ out.x = input.x * m;
490
+ out.y = input.y * m;
491
+ out.z = input.z * m;
492
+ } else {
493
+ out.copy(input);
494
+ }
470
495
  }
471
496
 
472
497
  /**
@@ -481,11 +506,11 @@ function vdot(v1, v2) {
481
506
 
482
507
  /**
483
508
  *
484
- * @param {number} fX
509
+ * @param {number} v
485
510
  * @returns {boolean}
486
511
  */
487
- function NotZero(fX) {
488
- return Math.abs(fX) > EPSILON;
512
+ function NotZero(v) {
513
+ return Math.abs(v) > EPSILON;
489
514
  }
490
515
 
491
516
  /**
@@ -519,19 +544,25 @@ function AvgTSpace(ts_res, pTS0, pTS1) {
519
544
  // this if is important. Due to floating point precision
520
545
  // averaging when ts0==ts1 will cause a slight difference
521
546
  // which results in tangent space splits later on
522
- if (pTS0.fMagS === pTS1.fMagS && pTS0.fMagT === pTS1.fMagT &&
523
- veq(pTS0.vOs, pTS1.vOs) && veq(pTS0.vOt, pTS1.vOt)) {
547
+ if (
548
+ pTS0.fMagS === pTS1.fMagS && pTS0.fMagT === pTS1.fMagT &&
549
+ veq(pTS0.vOs, pTS1.vOs) && veq(pTS0.vOt, pTS1.vOt)
550
+ ) {
551
+
524
552
  ts_res.fMagS = pTS0.fMagS;
525
553
  ts_res.fMagT = pTS0.fMagT;
526
554
  ts_res.vOs = pTS0.vOs;
527
555
  ts_res.vOt = pTS0.vOt;
556
+
528
557
  } else {
529
558
  ts_res.fMagS = 0.5 * (pTS0.fMagS + pTS1.fMagS);
530
559
  ts_res.fMagT = 0.5 * (pTS0.fMagT + pTS1.fMagT);
531
- ts_res.vOs = vadd(pTS0.vOs, pTS1.vOs);
532
- ts_res.vOt = vadd(pTS0.vOt, pTS1.vOt);
533
- if (VNotZero(ts_res.vOs)) ts_res.vOs = Normalize(ts_res.vOs);
534
- if (VNotZero(ts_res.vOt)) ts_res.vOt = Normalize(ts_res.vOt);
560
+
561
+ vadd(ts_res.vOs, pTS0.vOs, pTS1.vOs);
562
+ vadd(ts_res.vOt, pTS0.vOt, pTS1.vOt);
563
+
564
+ NormalizeSafe(ts_res.vOs, ts_res.vOs);
565
+ NormalizeSafe(ts_res.vOt, ts_res.vOt);
535
566
  }
536
567
 
537
568
  }
@@ -550,7 +581,7 @@ function GetPosition(pContext, index) {
550
581
  const iF = index & 0x3;
551
582
  const iI = index >> 2;
552
583
 
553
- pContext.m_pInterface.m_getPosition(pContext, res, iF, iI);
584
+ m_getPosition(pContext, res, iF, iI);
554
585
 
555
586
  return res;
556
587
  }
@@ -568,26 +599,25 @@ function GetNormal(pContext, index) {
568
599
  const iF = index & 0x3;
569
600
  const iI = index >> 2;
570
601
 
571
- pContext.m_pInterface.m_getNormal(pContext, res, iF, iI);
602
+ m_getNormal(pContext, res, iF, iI);
572
603
 
573
604
  return res;
574
605
  }
575
606
 
576
607
  /**
577
608
  * TODO doesn't need to be V3, can save memory
609
+ * @param {SVec3} res
578
610
  * @param {SMikkTSpaceContext} pContext
579
611
  * @param {number} index
580
612
  * @returns {SVec3}
581
613
  */
582
- function GetTexCoord(pContext, index) {
583
-
584
- const res = new SVec3();
614
+ function GetTexCoord(res, pContext, index) {
585
615
 
586
616
  // inlined : IndexToData(&iF, &iI, index);
587
617
  const iF = index & 0x3;
588
618
  const iI = index >> 2;
589
619
 
590
- pContext.m_pInterface.m_getTexCoord(pContext, res, iF, iI);
620
+ m_getTexCoord(pContext, res, iF, iI);
591
621
 
592
622
  res.z = 1;
593
623
 
@@ -702,9 +732,13 @@ function GetEdge(out, indices, indices_offset, i0_in, i1_in) {
702
732
  */
703
733
  function CalcTexArea(pContext, indices, indices_offset) {
704
734
 
705
- const t1 = GetTexCoord(pContext, indices[indices_offset + 0]);
706
- const t2 = GetTexCoord(pContext, indices[indices_offset + 1]);
707
- const t3 = GetTexCoord(pContext, indices[indices_offset + 2]);
735
+ const t1 = new SVec3();
736
+ const t2 = new SVec3();
737
+ const t3 = new SVec3();
738
+
739
+ GetTexCoord(t1, pContext, indices[indices_offset + 0]);
740
+ GetTexCoord(t2, pContext, indices[indices_offset + 1]);
741
+ GetTexCoord(t3, pContext, indices[indices_offset + 2]);
708
742
 
709
743
  const t21x = t2.x - t1.x;
710
744
  const t21y = t2.y - t1.y;
@@ -745,71 +779,94 @@ function malloc(Klass, count) {
745
779
  */
746
780
  function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVertexRepresentitive) {
747
781
  const res = new STSpace();
782
+
748
783
  let fAngleSum = 0;
749
784
  let face = 0;
785
+
750
786
  res.vOs.x = 0.0;
751
787
  res.vOs.y = 0.0;
752
788
  res.vOs.z = 0.0;
789
+
753
790
  res.vOt.x = 0.0;
754
791
  res.vOt.y = 0.0;
755
792
  res.vOt.z = 0.0;
793
+
756
794
  res.fMagS = 0;
757
795
  res.fMagT = 0;
758
796
 
797
+ const vOs = new SVec3();
798
+ const vOt = new SVec3();
799
+
759
800
  for (face = 0; face < iFaces; face++) {
760
801
  const f = face_indices[face];
802
+ const tri_info = pTriInfos[f];
761
803
 
762
804
  // only valid triangles get to add their contribution
763
- if ((pTriInfos[f].iFlag & GROUP_WITH_ANY) === 0) {
805
+ if ((tri_info.iFlag & GROUP_WITH_ANY) === 0) {
764
806
  /**
765
807
  * @type {SVec3}
766
808
  */
767
- let n, vOs, vOt, p0, p1, p2, v1, v2;
809
+ let n, p0, p1, p2, v1, v2;
768
810
  /**
769
811
  * @type {number}
770
812
  */
771
813
  let fCos, fAngle, fMagS, fMagT;
772
814
  let i = -1, index = -1, i0 = -1, i1 = -1, i2 = -1;
773
815
 
774
- if (piTriListIn[3 * f + 0] === iVertexRepresentitive) i = 0;
775
- else if (piTriListIn[3 * f + 1] === iVertexRepresentitive) i = 1;
776
- else if (piTriListIn[3 * f + 2] === iVertexRepresentitive) i = 2;
816
+ const f3 = 3 * f;
817
+
818
+ if (piTriListIn[f3] === iVertexRepresentitive) {
819
+ i = 0;
820
+ } else if (piTriListIn[f3 + 1] === iVertexRepresentitive) {
821
+ i = 1;
822
+ } else if (piTriListIn[f3 + 2] === iVertexRepresentitive) {
823
+ i = 2;
824
+ }
825
+
777
826
  assert(i >= 0 && i < 3);
778
827
 
779
828
  // project
780
- index = piTriListIn[3 * f + i];
829
+ index = piTriListIn[f3 + i];
781
830
  n = GetNormal(pContext, index);
782
- vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n));
783
- vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n));
784
- if (VNotZero(vOs)) vOs = Normalize(vOs);
785
- if (VNotZero(vOt)) vOt = Normalize(vOt);
786
831
 
787
- i2 = piTriListIn[3 * f + (i < 2 ? (i + 1) : 0)];
788
- i1 = piTriListIn[3 * f + i];
789
- i0 = piTriListIn[3 * f + (i > 0 ? (i - 1) : 2)];
832
+ vsub(vOs, tri_info.vOs, vscale(vdot(n, tri_info.vOs), n));
833
+
834
+ vsub(vOt, tri_info.vOt, vscale(vdot(n, tri_info.vOt), n));
835
+
836
+ NormalizeSafe(vOs, vOs);
837
+ NormalizeSafe(vOt, vOt);
838
+
839
+ i2 = piTriListIn[f3 + (i < 2 ? (i + 1) : 0)];
840
+ i1 = piTriListIn[f3 + i];
841
+ i0 = piTriListIn[f3 + (i > 0 ? (i - 1) : 2)];
790
842
 
791
843
  p0 = GetPosition(pContext, i0);
792
844
  p1 = GetPosition(pContext, i1);
793
845
  p2 = GetPosition(pContext, i2);
794
- v1 = vsub(p0, p1);
795
- v2 = vsub(p2, p1);
846
+
847
+ v1 = new SVec3();
848
+ vsub(v1, p0, p1);
849
+ v2 = new SVec3();
850
+ vsub(v2, p2, p1);
796
851
 
797
852
  // project
798
- v1 = vsub(v1, vscale(vdot(n, v1), n));
799
- if (VNotZero(v1)) v1 = Normalize(v1);
800
- v2 = vsub(v2, vscale(vdot(n, v2), n));
801
- if (VNotZero(v2)) v2 = Normalize(v2);
853
+ vsub(v1, v1, vscale(vdot(n, v1), n));
854
+ NormalizeSafe(v1, v1);
855
+
856
+ vsub(v2, v2, vscale(vdot(n, v2), n));
857
+ NormalizeSafe(v2, v2);
802
858
 
803
859
  // weight contribution by the angle
804
860
  // between the two edge vectors
805
861
  fCos = vdot(v1, v2);
806
862
  fCos = fCos > 1 ? 1 : (fCos < (-1) ? (-1) : fCos);
807
863
  fAngle = Math.acos(fCos);
808
- fMagS = pTriInfos[f].fMagS;
809
- fMagT = pTriInfos[f].fMagT;
864
+ fMagS = tri_info.fMagS;
865
+ fMagT = tri_info.fMagT;
866
+
867
+ vadd(res.vOs, res.vOs, vscale(fAngle, vOs));
868
+ vadd(res.vOt, res.vOt, vscale(fAngle, vOt));
810
869
 
811
- res.vOs = vadd(res.vOs, vscale(fAngle, vOs));
812
- res.vOt = vadd(res.vOt, vscale(fAngle, vOt));
813
870
  res.fMagS += (fAngle * fMagS);
814
871
  res.fMagT += (fAngle * fMagT);
815
872
  fAngleSum += fAngle;
@@ -817,8 +874,9 @@ function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVer
817
874
  }
818
875
 
819
876
  // normalize
820
- if (VNotZero(res.vOs)) res.vOs = Normalize(res.vOs);
821
- if (VNotZero(res.vOt)) res.vOt = Normalize(res.vOt);
877
+ NormalizeSafe(res.vOs, res.vOs);
878
+ NormalizeSafe(res.vOt, res.vOt);
879
+
822
880
  if (fAngleSum > 0) {
823
881
  res.fMagS /= fAngleSum;
824
882
  res.fMagT /= fAngleSum;
@@ -836,11 +894,21 @@ function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVer
836
894
  function CompareSubGroups(pg1, pg2) {
837
895
  let bStillSame = true;
838
896
  let i = 0;
839
- if (pg1.iNrFaces !== pg2.iNrFaces) return false;
897
+
898
+ if (pg1.iNrFaces !== pg2.iNrFaces) {
899
+ return false;
900
+ }
901
+
840
902
  while (i < pg1.iNrFaces && bStillSame) {
903
+
841
904
  bStillSame = pg1.pTriMembers[i] === pg2.pTriMembers[i];
842
- if (bStillSame) ++i;
905
+
906
+ if (bStillSame) {
907
+ ++i;
908
+ }
909
+
843
910
  }
911
+
844
912
  return bStillSame;
845
913
  }
846
914
 
@@ -906,13 +974,18 @@ function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
906
974
  // build array of edges
907
975
  const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
908
976
  let iEntries = 0, iCurStartIndex = -1, f = 0, i = 0;
977
+
909
978
  for (f = 0; f < iNrTrianglesIn; f++)
979
+
910
980
  for (i = 0; i < 3; i++) {
911
981
  const i0 = piTriListIn[f * 3 + i];
912
982
  const i1 = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];
913
- pEdges[f * 3 + i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
914
- pEdges[f * 3 + i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
915
- pEdges[f * 3 + i].f = f; // record face number
983
+
984
+ const edge = pEdges[f * 3 + i];
985
+
986
+ edge.i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
987
+ edge.i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
988
+ edge.f = f; // record face number
916
989
  }
917
990
 
918
991
  // sort over all edges by i0, this is the pricy one.
@@ -923,6 +996,7 @@ function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
923
996
  // with i0 as msb in the quicksort call above.
924
997
  iEntries = iNrTrianglesIn * 3;
925
998
  iCurStartIndex = 0;
999
+
926
1000
  for (i = 1; i < iEntries; i++) {
927
1001
  if (pEdges[iCurStartIndex].i0 !== pEdges[i].i0) {
928
1002
  const iL = iCurStartIndex;
@@ -1061,45 +1135,66 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
1061
1135
  // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function.
1062
1136
 
1063
1137
  // generate neighbor info list
1064
- for (f = 0; f < iNrTrianglesIn; f++)
1138
+ for (f = 0; f < iNrTrianglesIn; f++) {
1065
1139
  for (i = 0; i < 3; i++) {
1066
- pTriInfos[f].FaceNeighbors[i] = -1;
1067
- pTriInfos[f].AssignedGroup[i] = null;
1068
-
1069
- pTriInfos[f].vOs.x = 0.0;
1070
- pTriInfos[f].vOs.y = 0.0;
1071
- pTriInfos[f].vOs.z = 0.0;
1072
- pTriInfos[f].vOt.x = 0.0;
1073
- pTriInfos[f].vOt.y = 0.0;
1074
- pTriInfos[f].vOt.z = 0.0;
1075
- pTriInfos[f].fMagS = 0;
1076
- pTriInfos[f].fMagT = 0;
1140
+ const tri = pTriInfos[f];
1141
+
1142
+ tri.FaceNeighbors[i] = -1;
1143
+ tri.AssignedGroup[i] = null;
1144
+
1145
+ tri.vOs.x = 0.0;
1146
+ tri.vOs.y = 0.0;
1147
+ tri.vOs.z = 0.0;
1148
+
1149
+ tri.vOt.x = 0.0;
1150
+ tri.vOt.y = 0.0;
1151
+ tri.vOt.z = 0.0;
1152
+
1153
+ tri.fMagS = 0;
1154
+ tri.fMagT = 0;
1077
1155
 
1078
1156
  // assumed bad
1079
- pTriInfos[f].iFlag |= GROUP_WITH_ANY;
1157
+ tri.iFlag |= GROUP_WITH_ANY;
1080
1158
  }
1159
+ }
1160
+
1161
+ const t1 = new SVec3();
1162
+ const t2 = new SVec3();
1163
+ const t3 = new SVec3();
1164
+
1165
+ const d1 = new SVec3();
1166
+ const d2 = new SVec3();
1167
+
1168
+ const vOs = new SVec3();
1169
+ const vOt = new SVec3();
1081
1170
 
1082
1171
  // evaluate first order derivatives
1083
1172
  for (f = 0; f < iNrTrianglesIn; f++) {
1084
1173
  // initial values
1085
- const v1 = GetPosition(pContext, piTriListIn[f * 3 + 0]);
1086
- const v2 = GetPosition(pContext, piTriListIn[f * 3 + 1]);
1087
- const v3 = GetPosition(pContext, piTriListIn[f * 3 + 2]);
1088
- const t1 = GetTexCoord(pContext, piTriListIn[f * 3 + 0]);
1089
- const t2 = GetTexCoord(pContext, piTriListIn[f * 3 + 1]);
1090
- const t3 = GetTexCoord(pContext, piTriListIn[f * 3 + 2]);
1174
+ const f3 = f * 3;
1175
+
1176
+ const v1 = GetPosition(pContext, piTriListIn[f3 + 0]);
1177
+ const v2 = GetPosition(pContext, piTriListIn[f3 + 1]);
1178
+ const v3 = GetPosition(pContext, piTriListIn[f3 + 2]);
1179
+
1180
+ GetTexCoord(t1, pContext, piTriListIn[f3 + 0]);
1181
+ GetTexCoord(t2, pContext, piTriListIn[f3 + 1]);
1182
+ GetTexCoord(t3, pContext, piTriListIn[f3 + 2]);
1091
1183
 
1092
1184
  const t21x = t2.x - t1.x;
1093
1185
  const t21y = t2.y - t1.y;
1186
+
1094
1187
  const t31x = t3.x - t1.x;
1095
1188
  const t31y = t3.y - t1.y;
1096
- const d1 = vsub(v2, v1);
1097
- const d2 = vsub(v3, v1);
1189
+
1190
+ vsub(d1, v2, v1);
1191
+ vsub(d2, v3, v1);
1098
1192
 
1099
1193
  const fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
1100
1194
  //assert(fSignedAreaSTx2!=0);
1101
- let vOs = vsub(vscale(t31y, d1), vscale(t21y, d2)); // eq 18
1102
- let vOt = vadd(vscale(-t31x, d1), vscale(t21x, d2)); // eq 19
1195
+ vsub(vOs, vscale(t31y, d1), vscale(t21y, d2)); // eq 18
1196
+
1197
+ vadd(vOt, vscale(-t31x, d1), vscale(t21x, d2)); // eq 19
1103
1198
 
1104
1199
  pTriInfos[f].iFlag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
1105
1200
 
@@ -1108,16 +1203,21 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
1108
1203
  const fLenOs = Length(vOs);
1109
1204
  const fLenOt = Length(vOt);
1110
1205
  const fS = (pTriInfos[f].iFlag & ORIENT_PRESERVING) === 0 ? (-1.0) : 1.0;
1111
- if (NotZero(fLenOs)) pTriInfos[f].vOs = vscale(fS / fLenOs, vOs);
1112
- if (NotZero(fLenOt)) pTriInfos[f].vOt = vscale(fS / fLenOt, vOt);
1206
+ if (NotZero(fLenOs)) {
1207
+ pTriInfos[f].vOs = vscale(fS / fLenOs, vOs);
1208
+ }
1209
+ if (NotZero(fLenOt)) {
1210
+ pTriInfos[f].vOt = vscale(fS / fLenOt, vOt);
1211
+ }
1113
1212
 
1114
1213
  // evaluate magnitudes prior to normalization of vOs and vOt
1115
1214
  pTriInfos[f].fMagS = fLenOs / fAbsArea;
1116
1215
  pTriInfos[f].fMagT = fLenOt / fAbsArea;
1117
1216
 
1118
1217
  // if this is a good triangle
1119
- if (NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT))
1218
+ if (NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) {
1120
1219
  pTriInfos[f].iFlag &= (~GROUP_WITH_ANY);
1220
+ }
1121
1221
  }
1122
1222
  }
1123
1223
 
@@ -1140,7 +1240,7 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
1140
1240
  //printf("found quad with bad mapping\n");
1141
1241
  let bChooseOrientFirstTri = false;
1142
1242
  if ((pTriInfos[t + 1].iFlag & GROUP_WITH_ANY) !== 0) bChooseOrientFirstTri = true;
1143
- else if (CalcTexArea(pContext, piTriListIn, t * 3 + 0) >= CalcTexArea(pContext, piTriListIn, (t + 1) * 3 + 0))
1243
+ else if (CalcTexArea(pContext, piTriListIn, t * 3) >= CalcTexArea(pContext, piTriListIn, (t + 1) * 3 + 0))
1144
1244
  bChooseOrientFirstTri = true;
1145
1245
 
1146
1246
  // force match
@@ -1176,21 +1276,14 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
1176
1276
  let iNrTrianglesIn = 0, f = 0, t = 0, i = 0;
1177
1277
  let iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
1178
1278
  let iNrActiveGroups = 0, index = 0;
1179
- const iNrFaces = pContext.m_pInterface.m_getNumFaces(pContext);
1279
+ const iNrFaces = m_getNumFaces(pContext);
1180
1280
  let bRes = false;
1181
1281
  const fThresCos = Math.cos((fAngularThreshold * Math.PI) / 180.0);
1182
1282
 
1183
- // verify all call-backs have been set
1184
- if (pContext.m_pInterface.m_getNumFaces === null ||
1185
- pContext.m_pInterface.m_getNumVerticesOfFace === null ||
1186
- pContext.m_pInterface.m_getPosition === null ||
1187
- pContext.m_pInterface.m_getNormal === null ||
1188
- pContext.m_pInterface.m_getTexCoord === null)
1189
- return false;
1190
1283
 
1191
1284
  // count triangles on supported faces
1192
1285
  for (f = 0; f < iNrFaces; f++) {
1193
- const verts = pContext.m_pInterface.m_getNumVerticesOfFace(pContext, f);
1286
+ const verts = m_getNumVerticesOfFace(pContext, f);
1194
1287
  if (verts === 3) ++iNrTrianglesIn;
1195
1288
  else if (verts === 4) iNrTrianglesIn += 2;
1196
1289
  }
@@ -1294,7 +1387,7 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
1294
1387
 
1295
1388
  index = 0;
1296
1389
  for (f = 0; f < iNrFaces; f++) {
1297
- const verts = pContext.m_pInterface.m_getNumVerticesOfFace(pContext, f);
1390
+ const verts = m_getNumVerticesOfFace(pContext, f);
1298
1391
  if (verts !== 3 && verts !== 4) continue;
1299
1392
 
1300
1393
 
@@ -1325,7 +1418,7 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
1325
1418
  const tang = [pTSpace.vOs.x, pTSpace.vOs.y, pTSpace.vOs.z];
1326
1419
  const bitang = [pTSpace.vOt.x, pTSpace.vOt.y, pTSpace.vOt.z];
1327
1420
 
1328
- pContext.m_pInterface.m_setTSpace(pContext, tang, bitang, pTSpace.fMagS, pTSpace.fMagT, pTSpace.bOrient, f, i);
1421
+ m_setTSpace(pContext, tang, bitang, pTSpace.fMagS, pTSpace.fMagT, pTSpace.bOrient, f, i);
1329
1422
 
1330
1423
  ++index;
1331
1424
  }
@@ -1390,7 +1483,10 @@ function GenerateSharedVerticesIndexList(piTriList_in_and_out, pContext, iNrTria
1390
1483
  else if (vMax.z < vP.z) vMax.z = vP.z;
1391
1484
  }
1392
1485
 
1393
- vDim = vsub(vMax, vMin);
1486
+ vDim = new SVec3();
1487
+
1488
+ vsub(vDim, vMax, vMin);
1489
+
1394
1490
  iChannel = 0;
1395
1491
  fMin = vMin.x;
1396
1492
  fMax = vMax.x;
@@ -1485,14 +1581,25 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
1485
1581
  let c = 0, l = 0, channel = 0;
1486
1582
  let fvMin = [], fvMax = [];
1487
1583
  let dx = 0, dy = 0, dz = 0, fSep = 0;
1584
+
1488
1585
  for (c = 0; c < 3; c++) {
1489
1586
  fvMin[c] = pTmpVert[iL_in].vert[c];
1490
1587
  fvMax[c] = fvMin[c];
1491
1588
  }
1589
+
1492
1590
  for (l = (iL_in + 1); l <= iR_in; l++) {
1591
+ const temp_vert = pTmpVert[l];
1592
+
1493
1593
  for (c = 0; c < 3; c++) {
1494
- if (fvMin[c] > pTmpVert[l].vert[c]) fvMin[c] = pTmpVert[l].vert[c];
1495
- if (fvMax[c] < pTmpVert[l].vert[c]) fvMax[c] = pTmpVert[l].vert[c];
1594
+ const coordinate = temp_vert.vert[c];
1595
+
1596
+ if (fvMin[c] > coordinate) {
1597
+ fvMin[c] = coordinate;
1598
+ }
1599
+
1600
+ if (fvMax[c] < coordinate) {
1601
+ fvMax[c] = coordinate;
1602
+ }
1496
1603
  }
1497
1604
  }
1498
1605
 
@@ -1507,8 +1614,9 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
1507
1614
  fSep = 0.5 * (fvMax[channel] + fvMin[channel]);
1508
1615
 
1509
1616
  // stop if all vertices are NaNs
1510
- if (!Number.isFinite(fSep))
1617
+ if (!Number.isFinite(fSep)) {
1511
1618
  return;
1619
+ }
1512
1620
 
1513
1621
  // terminate recursion when the separation/average value
1514
1622
  // is no longer strictly between fMin and fMax values.
@@ -1519,7 +1627,8 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
1519
1627
  const index = piTriList_in_and_out[i];
1520
1628
  const vP = GetPosition(pContext, index);
1521
1629
  const vN = GetNormal(pContext, index);
1522
- const vT = GetTexCoord(pContext, index);
1630
+ const vT = new SVec3();
1631
+ GetTexCoord(vT, pContext, index);
1523
1632
 
1524
1633
  let bNotFound = true;
1525
1634
  let l2 = iL_in, i2rec = -1;
@@ -1528,16 +1637,22 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
1528
1637
  const index2 = piTriList_in_and_out[i2];
1529
1638
  const vP2 = GetPosition(pContext, index2);
1530
1639
  const vN2 = GetNormal(pContext, index2);
1531
- const vT2 = GetTexCoord(pContext, index2);
1640
+
1641
+ const vT2 = new SVec3();
1642
+ GetTexCoord(vT2, pContext, index2);
1643
+
1532
1644
  i2rec = i2;
1533
1645
 
1534
1646
  //if (vP==vP2 && vN==vN2 && vT==vT2)
1535
- if (vP.x === vP2.x && vP.y === vP2.y && vP.z == vP2.z &&
1647
+ if (
1648
+ vP.x === vP2.x && vP.y === vP2.y && vP.z === vP2.z &&
1536
1649
  vN.x === vN2.x && vN.y === vN2.y && vN.z === vN2.z &&
1537
- vT.x === vT2.x && vT.y === vT2.y && vT.z === vT2.z)
1650
+ vT.x === vT2.x && vT.y === vT2.y && vT.z === vT2.z
1651
+ ) {
1538
1652
  bNotFound = false;
1539
- else
1653
+ } else {
1540
1654
  ++l2;
1655
+ }
1541
1656
  }
1542
1657
 
1543
1658
  // merge if previously found
@@ -1599,8 +1714,8 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
1599
1714
  function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iNrTrianglesIn) {
1600
1715
  let iTSpacesOffs = 0, f = 0, t = 0;
1601
1716
  let iDstTriIndex = 0;
1602
- for (f = 0; f < pContext.m_pInterface.m_getNumFaces(pContext); f++) {
1603
- const verts = pContext.m_pInterface.m_getNumVerticesOfFace(pContext, f);
1717
+ for (f = 0; f < m_getNumFaces(pContext); f++) {
1718
+ const verts = m_getNumVerticesOfFace(pContext, f);
1604
1719
  if (verts !== 3 && verts !== 4) continue;
1605
1720
 
1606
1721
  pTriInfos[iDstTriIndex].iOrgFaceNumber = f;
@@ -1629,12 +1744,19 @@ function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iN
1629
1744
  const i1 = MakeIndex(f, 1);
1630
1745
  const i2 = MakeIndex(f, 2);
1631
1746
  const i3 = MakeIndex(f, 3);
1632
- const T0 = GetTexCoord(pContext, i0);
1633
- const T1 = GetTexCoord(pContext, i1);
1634
- const T2 = GetTexCoord(pContext, i2);
1635
- const T3 = GetTexCoord(pContext, i3);
1636
- const distSQ_02 = LengthSquared(vsub(T2, T0));
1637
- const distSQ_13 = LengthSquared(vsub(T3, T1));
1747
+
1748
+ const T0 = new SVec3();
1749
+ GetTexCoord(T0, pContext, i0);
1750
+ const T1 = new SVec3();
1751
+ GetTexCoord(T1, pContext, i1);
1752
+ const T2 = new SVec3();
1753
+ GetTexCoord(T2, pContext, i2);
1754
+ const T3 = new SVec3();
1755
+ GetTexCoord(T3, pContext, i3);
1756
+
1757
+
1758
+ const distSQ_02 = DistanceSquared(T2, T0);
1759
+ const distSQ_13 = DistanceSquared(T3, T1);
1638
1760
  let bQuadDiagIs_02 = false;
1639
1761
  if (distSQ_02 < distSQ_13)
1640
1762
  bQuadDiagIs_02 = true;
@@ -1645,8 +1767,8 @@ function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iN
1645
1767
  const P1 = GetPosition(pContext, i1);
1646
1768
  const P2 = GetPosition(pContext, i2);
1647
1769
  const P3 = GetPosition(pContext, i3);
1648
- const distSQ_02 = LengthSquared(vsub(P2, P0));
1649
- const distSQ_13 = LengthSquared(vsub(P3, P1));
1770
+ const distSQ_02 = DistanceSquared(P2, P0);
1771
+ const distSQ_13 = DistanceSquared(P3, P1);
1650
1772
 
1651
1773
  bQuadDiagIs_02 = distSQ_13 >= distSQ_02;
1652
1774
  }
@@ -1909,6 +2031,9 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
1909
2031
 
1910
2032
  iUniqueTspaces = 0;
1911
2033
 
2034
+ const vOs = new SVec3();
2035
+ const vOt = new SVec3();
2036
+
1912
2037
  for (g = 0; g < iNrActiveGroups; g++) {
1913
2038
  const pGroup = pGroups[g];
1914
2039
  let iUniqueSubGroups = 0, s = 0;
@@ -1925,7 +2050,7 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
1925
2050
  /**
1926
2051
  * @type {SVec3}
1927
2052
  */
1928
- let n, vOs, vOt;
2053
+ let n;
1929
2054
 
1930
2055
  if (pTriInfos[f].AssignedGroup[0] === pGroup) index = 0;
1931
2056
  else if (pTriInfos[f].AssignedGroup[1] === pGroup) index = 1;
@@ -1939,10 +2064,12 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
1939
2064
  n = GetNormal(pContext, iVertIndex);
1940
2065
 
1941
2066
  // project
1942
- vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n));
1943
- vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n));
1944
- if (VNotZero(vOs)) vOs = Normalize(vOs);
1945
- if (VNotZero(vOt)) vOt = Normalize(vOt);
2067
+
2068
+ vsub(vOs, pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n));
2069
+ vsub(vOt, pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n));
2070
+
2071
+ NormalizeSafe(vOs, vOs);
2072
+ NormalizeSafe(vOt, vOt);
1946
2073
 
1947
2074
  // original face number
1948
2075
  iOF_1 = pTriInfos[f].iOrgFaceNumber;
@@ -1953,10 +2080,14 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
1953
2080
  const iOF_2 = pTriInfos[t].iOrgFaceNumber;
1954
2081
 
1955
2082
  // project
1956
- let vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n, pTriInfos[t].vOs), n));
1957
- let vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n, pTriInfos[t].vOt), n));
1958
- if (VNotZero(vOs2)) vOs2 = Normalize(vOs2);
1959
- if (VNotZero(vOt2)) vOt2 = Normalize(vOt2);
2083
+ let vOs2 = new SVec3();
2084
+ vsub(vOs2, pTriInfos[t].vOs, vscale(vdot(n, pTriInfos[t].vOs), n));
2085
+
2086
+ let vOt2 = new SVec3();
2087
+ vsub(vOt2, pTriInfos[t].vOt, vscale(vdot(n, pTriInfos[t].vOt), n));
2088
+
2089
+ NormalizeSafe(vOs2, vOs2);
2090
+ NormalizeSafe(vOt2, vOt2);
1960
2091
 
1961
2092
  {
1962
2093
  const bAny = ((pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY) !== 0;
@@ -1975,6 +2106,7 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
1975
2106
  // sort pTmpMembers
1976
2107
  tmp_group.iNrFaces = iMembers;
1977
2108
  tmp_group.pTriMembers = pTmpMembers;
2109
+
1978
2110
  if (iMembers > 1) {
1979
2111
  const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
1980
2112
  QuickSort(pTmpMembers, 0, iMembers - 1, uSeed);
@@ -2140,30 +2272,43 @@ function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesI
2140
2272
 
2141
2273
  // deal with degenerate triangles
2142
2274
  // punishment for degenerate triangles is O(N^2)
2275
+
2143
2276
  for (t = iNrTrianglesIn; t < iTotTris; t++) {
2277
+ const tri0 = pTriInfos[t];
2278
+
2144
2279
  // degenerate triangles on a quad with one good triangle are skipped
2145
2280
  // here but processed in the next loop
2146
- const bSkip = (pTriInfos[t].iFlag & QUAD_ONE_DEGEN_TRI) !== 0;
2281
+ const bSkip = (tri0.iFlag & QUAD_ONE_DEGEN_TRI) !== 0;
2147
2282
 
2148
2283
  if (!bSkip) {
2149
2284
  for (i = 0; i < 3; i++) {
2285
+
2150
2286
  const index1 = piTriListIn[t * 3 + i];
2151
2287
  // search through the good triangles
2152
2288
  let bNotFound = true;
2153
2289
  let j = 0;
2290
+
2154
2291
  while (bNotFound && j < (3 * iNrTrianglesIn)) {
2155
2292
  const index2 = piTriListIn[j];
2156
- if (index1 === index2) bNotFound = false;
2157
- else ++j;
2293
+
2294
+ if (index1 === index2) {
2295
+ bNotFound = false;
2296
+ } else {
2297
+ ++j;
2298
+ }
2158
2299
  }
2159
2300
 
2160
2301
  if (!bNotFound) {
2161
2302
  const iTri = j / 3;
2162
2303
  const iVert = j % 3;
2163
- const iSrcVert = pTriInfos[iTri].vert_num[iVert];
2164
- const iSrcOffs = pTriInfos[iTri].iTSpacesOffs;
2165
- const iDstVert = pTriInfos[t].vert_num[i];
2166
- const iDstOffs = pTriInfos[t].iTSpacesOffs;
2304
+
2305
+ const tri1 = pTriInfos[iTri];
2306
+
2307
+ const iSrcVert = tri1.vert_num[iVert];
2308
+ const iSrcOffs = tri1.iTSpacesOffs;
2309
+
2310
+ const iDstVert = tri0.vert_num[i];
2311
+ const iDstOffs = tri0.iTSpacesOffs;
2167
2312
 
2168
2313
  // copy tspace
2169
2314
  psTspace[iDstOffs + iDstVert] = psTspace[iSrcOffs + iSrcVert];
@@ -2176,33 +2321,49 @@ function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesI
2176
2321
  for (t = 0; t < iNrTrianglesIn; t++) {
2177
2322
  // this triangle belongs to a quad where the
2178
2323
  // other triangle is degenerate
2179
- if ((pTriInfos[t].iFlag & QUAD_ONE_DEGEN_TRI) !== 0) {
2324
+ const tri = pTriInfos[t];
2325
+
2326
+ if ((tri.iFlag & QUAD_ONE_DEGEN_TRI) !== 0) {
2327
+
2180
2328
  /**
2181
2329
  * @type {SVec3}
2182
2330
  */
2183
2331
  let vDstP;
2184
2332
  let iOrgF = -1, i = 0;
2185
2333
  let bNotFound;
2186
- const pV = pTriInfos[t].vert_num;
2334
+
2335
+ const pV = tri.vert_num;
2187
2336
  const iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
2337
+
2188
2338
  let iMissingIndex = 0;
2189
- if ((iFlag & 2) === 0) iMissingIndex = 1;
2190
- else if ((iFlag & 4) === 0) iMissingIndex = 2;
2191
- else if ((iFlag & 8) === 0) iMissingIndex = 3;
2192
2339
 
2193
- iOrgF = pTriInfos[t].iOrgFaceNumber;
2340
+ if ((iFlag & 2) === 0) {
2341
+ iMissingIndex = 1;
2342
+ } else if ((iFlag & 4) === 0) {
2343
+ iMissingIndex = 2;
2344
+ } else if ((iFlag & 8) === 0) {
2345
+ iMissingIndex = 3;
2346
+ }
2347
+
2348
+ iOrgF = tri.iOrgFaceNumber;
2194
2349
  vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex));
2195
2350
  bNotFound = true;
2351
+
2196
2352
  i = 0;
2353
+
2197
2354
  while (bNotFound && i < 3) {
2355
+
2198
2356
  const iVert = pV[i];
2199
2357
  const vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert));
2200
- if (veq(vSrcP, vDstP) === true) {
2201
- const iOffs = pTriInfos[t].iTSpacesOffs;
2358
+
2359
+ if (veq(vSrcP, vDstP)) {
2360
+ const iOffs = tri.iTSpacesOffs;
2202
2361
  psTspace[iOffs + iMissingIndex] = psTspace[iOffs + iVert];
2203
2362
  bNotFound = false;
2204
- } else
2363
+ } else {
2205
2364
  ++i;
2365
+ }
2366
+
2206
2367
  }
2207
2368
  assert(!bNotFound);
2208
2369
  }