@woosh/meep-engine 2.41.0 → 2.42.1

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 (98) hide show
  1. package/core/assert.js +2 -2
  2. package/core/collection/array/array_swap.js +3 -3
  3. package/core/collection/map/AsyncLoadingCache.js +47 -0
  4. package/core/geom/3d/aabb/aabb3_compute_distance_above_plane_max.js +1 -1
  5. package/core/geom/3d/apply_mat4_transform_to_v3_array.js +2 -4
  6. package/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +28 -0
  7. package/core/geom/Quaternion.js +14 -0
  8. package/core/math/statistics/computeSampleSize_Cochran.js +3 -3
  9. package/editor/ecs/component/editors/geom/QuaternionEditor.js +12 -5
  10. package/engine/Engine.js +6 -1
  11. package/engine/EngineBootstrapper.js +2 -1
  12. package/engine/EngineHarness.js +13 -3
  13. package/engine/asset/AssetManager.js +97 -7
  14. package/engine/development/performance/AbstractMetric.js +1 -0
  15. package/engine/development/performance/RingBufferMetric.js +25 -4
  16. package/engine/ecs/EntityBuilder.js +29 -4
  17. package/engine/ecs/transform/Transform.js +23 -3
  18. package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +17 -1
  19. package/engine/graphics/ecs/decal/v2/Decal.d.ts +11 -0
  20. package/engine/graphics/ecs/decal/v2/Decal.js +50 -0
  21. package/engine/graphics/ecs/decal/v2/FPDecalSystem.d.ts +8 -0
  22. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +201 -0
  23. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +278 -0
  24. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -1
  25. package/engine/graphics/ecs/mesh-v2/allocate_v3.js +37 -0
  26. package/engine/graphics/ecs/mesh-v2/build_three_object.js +4 -0
  27. package/engine/graphics/geometry/MikkT/AddTriToGroup.js +10 -0
  28. package/engine/graphics/geometry/MikkT/AssignRecur.js +84 -0
  29. package/engine/graphics/geometry/MikkT/AvgTSpace.js +38 -0
  30. package/engine/graphics/geometry/MikkT/Build4RuleGroups.js +96 -0
  31. package/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +137 -0
  32. package/engine/graphics/geometry/MikkT/CalcTexArea.js +31 -0
  33. package/engine/graphics/geometry/MikkT/CompareSubGroups.js +26 -0
  34. package/engine/graphics/geometry/MikkT/DegenEpilogue.js +220 -0
  35. package/engine/graphics/geometry/MikkT/DegenPrologue.js +115 -0
  36. package/engine/graphics/geometry/MikkT/EvalTspace.js +128 -0
  37. package/engine/graphics/geometry/MikkT/GenerateInitialVerticesIndexList.js +48 -0
  38. package/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +184 -0
  39. package/engine/graphics/geometry/MikkT/GenerateTSpaces.js +226 -0
  40. package/engine/graphics/geometry/MikkT/GetEdge.js +45 -0
  41. package/engine/graphics/geometry/MikkT/GetNormal.js +16 -0
  42. package/engine/graphics/geometry/MikkT/GetPosition.js +25 -0
  43. package/engine/graphics/geometry/MikkT/GetTexCoord.js +18 -0
  44. package/engine/graphics/geometry/MikkT/InitTriInfo.js +180 -0
  45. package/engine/graphics/geometry/MikkT/Length.js +10 -0
  46. package/engine/graphics/geometry/MikkT/MakeIndex.js +18 -0
  47. package/engine/graphics/geometry/MikkT/MikkTSpace.js +197 -2068
  48. package/engine/graphics/geometry/MikkT/NormalizeSafe.js +21 -0
  49. package/engine/graphics/geometry/MikkT/NotZero.js +10 -0
  50. package/engine/graphics/geometry/MikkT/QuickSort.js +54 -0
  51. package/engine/graphics/geometry/MikkT/QuickSortEdges.js +71 -0
  52. package/engine/graphics/geometry/MikkT/SSubGroup.js +15 -0
  53. package/engine/graphics/geometry/MikkT/STSpace.js +36 -0
  54. package/engine/graphics/geometry/MikkT/constants/GROUP_WITH_ANY.js +1 -0
  55. package/engine/graphics/geometry/MikkT/constants/INTERNAL_RND_SORT_SEED.js +1 -0
  56. package/engine/graphics/geometry/MikkT/constants/MARK_DEGENERATE.js +1 -0
  57. package/engine/graphics/geometry/MikkT/constants/ORIENT_PRESERVING.js +1 -0
  58. package/engine/graphics/geometry/MikkT/constants/QUAD_ONE_DEGEN_TRI.js +1 -0
  59. package/engine/graphics/geometry/MikkT/m_getNormal.js +16 -0
  60. package/engine/graphics/geometry/MikkT/m_getNumFaces.js +8 -0
  61. package/engine/graphics/geometry/MikkT/m_getNumVerticesOfFace.js +11 -0
  62. package/engine/graphics/geometry/MikkT/m_getPosition.js +20 -0
  63. package/engine/graphics/geometry/MikkT/m_getTexCoord.js +16 -0
  64. package/engine/graphics/geometry/MikkT/m_setTSpace.js +35 -0
  65. package/engine/graphics/geometry/MikkT/m_setTSpaceBasic.js +22 -0
  66. package/engine/graphics/geometry/MikkT/malloc.js +16 -0
  67. package/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +52 -0
  68. package/engine/graphics/geometry/buffered/computeGeometryEquality.js +1 -1
  69. package/engine/graphics/geometry/buffered/computeGeometryHash.js +1 -1
  70. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +28 -14
  71. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +6 -0
  72. package/engine/graphics/impostors/octahedral/README.md +1 -0
  73. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere.js +25 -22
  74. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere_radius_only.js +37 -0
  75. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +30 -1
  76. package/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +1 -1
  77. package/engine/graphics/impostors/octahedral/prototypeBaker.js +121 -22
  78. package/engine/graphics/impostors/octahedral/shader/BakeShaderStandard.js +46 -7
  79. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +349 -0
  80. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV1.js +74 -0
  81. package/engine/graphics/impostors/octahedral/shader/glsl/v1/common.glsl +209 -0
  82. package/engine/graphics/impostors/octahedral/shader/glsl/v1/flagment.glsl +80 -0
  83. package/engine/graphics/impostors/octahedral/shader/glsl/v1/vertex.glsl +350 -0
  84. package/engine/graphics/micron/render/v1/getTransformedPositionsCached.js +1 -1
  85. package/engine/graphics/render/forward_plus/LightManager.js +17 -7
  86. package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +7 -1
  87. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +13 -5
  88. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +3 -1
  89. package/engine/graphics/render/forward_plus/model/Decal.js +19 -2
  90. package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +14 -2
  91. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
  92. package/engine/graphics/texture/sampler/Sampler2D.js +10 -10
  93. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +117 -11
  94. package/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +66 -0
  95. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +2 -2
  96. package/engine/intelligence/behavior/util/RotationBehavior.js +69 -0
  97. package/generation/example/filters/SampleGroundMoistureFilter.js +5 -5
  98. package/package.json +1 -1
@@ -0,0 +1,38 @@
1
+ import { vec3 } from "gl-matrix";
2
+ import { NormalizeSafe } from "./NormalizeSafe.js";
3
+
4
+ /**
5
+ *
6
+ * @param {STSpace} ts_res
7
+ * @param {STSpace} pTS0
8
+ * @param {STSpace} pTS1
9
+ * @returns {void}
10
+ */
11
+ export function AvgTSpace(ts_res, pTS0, pTS1) {
12
+
13
+ // this if is important. Due to floating point precision
14
+ // averaging when ts0==ts1 will cause a slight difference
15
+ // which results in tangent space splits later on
16
+ if (
17
+ pTS0.fMagS === pTS1.fMagS && pTS0.fMagT === pTS1.fMagT &&
18
+ vec3.exactEquals(pTS0.vOs, pTS1.vOs) && vec3.exactEquals(pTS0.vOt, pTS1.vOt)
19
+ ) {
20
+
21
+ ts_res.fMagS = pTS0.fMagS;
22
+ ts_res.fMagT = pTS0.fMagT;
23
+
24
+ vec3.copy(ts_res.vOs, pTS0.vOs);
25
+ vec3.copy(ts_res.vOt, pTS0.vOt);
26
+
27
+ } else {
28
+ ts_res.fMagS = 0.5 * (pTS0.fMagS + pTS1.fMagS);
29
+ ts_res.fMagT = 0.5 * (pTS0.fMagT + pTS1.fMagT);
30
+
31
+ vec3.add(ts_res.vOs, pTS0.vOs, pTS1.vOs);
32
+ vec3.add(ts_res.vOt, pTS0.vOt, pTS1.vOt);
33
+
34
+ NormalizeSafe(ts_res.vOs, ts_res.vOs);
35
+ NormalizeSafe(ts_res.vOt, ts_res.vOt);
36
+ }
37
+
38
+ }
@@ -0,0 +1,96 @@
1
+ import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
2
+ import { assert } from "../../../../core/assert.js";
3
+ import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
4
+ import { AddTriToGroup } from "./AddTriToGroup.js";
5
+ import { AssignRecur } from "./AssignRecur.js";
6
+
7
+ /**
8
+ *
9
+ * @param {STriInfo[]} pTriInfos
10
+ * @param {SGroup[]} pGroups
11
+ * @param {number[]|Int32Array} piGroupTrianglesBuffer
12
+ * @param {number[]|Int32Array} piTriListIn
13
+ * @param {number} iNrTrianglesIn
14
+ * @return {number}
15
+ */
16
+ export function Build4RuleGroups(
17
+ pTriInfos,
18
+ pGroups,
19
+ piGroupTrianglesBuffer,
20
+ piTriListIn,
21
+ iNrTrianglesIn
22
+ ) {
23
+
24
+ const iNrMaxGroups = iNrTrianglesIn * 3;
25
+ let iNrActiveGroups = 0;
26
+ let iOffset = 0;
27
+
28
+ for (let f=0; f < iNrTrianglesIn; f++) {
29
+ const tri_info_f = pTriInfos[f];
30
+
31
+ for (let i = 0; i < 3; i++) {
32
+
33
+ // if not assigned to a group
34
+ if ((tri_info_f.iFlag & GROUP_WITH_ANY) === 0 && tri_info_f.AssignedGroup[i] === null) {
35
+
36
+ const vert_index = piTriListIn[f * 3 + i];
37
+
38
+ assert.lessThan(iNrActiveGroups, iNrMaxGroups);
39
+
40
+ const assigned_group = pGroups[iNrActiveGroups];
41
+ tri_info_f.AssignedGroup[i] = assigned_group;
42
+
43
+ assigned_group.iVertexRepresentitive = vert_index;
44
+
45
+ const bOrPre = (tri_info_f.iFlag & ORIENT_PRESERVING) !== 0;
46
+
47
+ assigned_group.bOrientPreservering = bOrPre;
48
+ assigned_group.iNrFaces = 0;
49
+ assigned_group.pFaceIndices = new Int32Array(piGroupTrianglesBuffer.buffer, iOffset * 4);
50
+ ++iNrActiveGroups;
51
+
52
+ AddTriToGroup(assigned_group, f);
53
+
54
+ const neigh_indexL = tri_info_f.FaceNeighbors[i];
55
+ const neigh_indexR = tri_info_f.FaceNeighbors[i > 0 ? (i - 1) : 2];
56
+
57
+ if (neigh_indexL >= 0) {
58
+
59
+ // neighbor
60
+ const bAnswer = AssignRecur(
61
+ piTriListIn,
62
+ pTriInfos,
63
+ neigh_indexL,
64
+ assigned_group
65
+ );
66
+
67
+ assert(bAnswer || (bOrPre !== ((pTriInfos[neigh_indexL].iFlag & ORIENT_PRESERVING) !== 0)) );
68
+
69
+ }
70
+ if (neigh_indexR >= 0) {
71
+
72
+ // neighbor
73
+ const bAnswer = AssignRecur(
74
+ piTriListIn,
75
+ pTriInfos,
76
+ neigh_indexR,
77
+ assigned_group
78
+ );
79
+
80
+ assert(bAnswer || bOrPre !== ((pTriInfos[neigh_indexR].iFlag & ORIENT_PRESERVING) !== 0));
81
+
82
+ }
83
+
84
+ // update offset
85
+ iOffset += assigned_group.iNrFaces;
86
+
87
+ // since the groups are disjoint a triangle can never
88
+ // belong to more than 3 groups. Subsequently, something
89
+ // is completely screwed if this assertion ever hits.
90
+ assert.lessThanOrEqual(iOffset, iNrMaxGroups);
91
+ }
92
+ }
93
+ }
94
+
95
+ return iNrActiveGroups;
96
+ }
@@ -0,0 +1,137 @@
1
+ import { INTERNAL_RND_SORT_SEED } from "./constants/INTERNAL_RND_SORT_SEED.js";
2
+ import { QuickSortEdges } from "./QuickSortEdges.js";
3
+ import { vec3 } from "gl-matrix";
4
+ import { GetEdge } from "./GetEdge.js";
5
+
6
+ /**
7
+ *
8
+ * @param {STriInfo[]} pTriInfos
9
+ * @param {number[]|Float32Array} pEdges
10
+ * @param {number[]} piTriListIn
11
+ * @param {number} iNrTrianglesIn
12
+ * @returns {void}
13
+ */
14
+ export function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
15
+ // build array of edges
16
+ const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
17
+
18
+ for (let f = 0; f < iNrTrianglesIn; f++) {
19
+ for (let i = 0; i < 3; i++) {
20
+
21
+ const edge_index = f * 3 + i;
22
+
23
+ const i0 = piTriListIn[edge_index];
24
+ const i1 = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];
25
+
26
+ pEdges[edge_index * 3] = i0 < i1 ? i0 : i1; // put minimum index in i0
27
+ pEdges[edge_index * 3 + 1] = !(i0 < i1) ? i0 : i1; // put maximum index in i1
28
+ pEdges[edge_index * 3 + 2] = f; // record face number
29
+ }
30
+ }
31
+
32
+ // sort over all edges by i0, this is a pricey one.
33
+ QuickSortEdges(pEdges, 0, iNrTrianglesIn * 3 - 1, 0, uSeed); // sort channel 0 which is i0
34
+
35
+ // sub sort over i1, should be fast.
36
+ // could replace this with a 64 bit int sort over (i0,i1)
37
+ // with i0 as msb in the quicksort call above.
38
+ const iEntries = iNrTrianglesIn * 3;
39
+ let iCurStartIndex = 0;
40
+
41
+ for (let i = 1; i < iEntries; i++) {
42
+ if (pEdges[iCurStartIndex * 3] !== pEdges[i * 3]) {
43
+
44
+ const iL = iCurStartIndex;
45
+ const iR = i - 1;
46
+ //const int iElems = i-iL;
47
+ iCurStartIndex = i;
48
+
49
+ QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1
50
+
51
+ }
52
+ }
53
+
54
+ // sub sort over f, which should be fast.
55
+ // this step is to remain compliant with BuildNeighborsSlow() when
56
+ // more than 2 triangles use the same edge (such as a butterfly topology).
57
+ iCurStartIndex = 0;
58
+
59
+ for (let i = 1; i < iEntries; i++) {
60
+
61
+ if (
62
+ pEdges[iCurStartIndex * 3] !== pEdges[i * 3]
63
+ || pEdges[iCurStartIndex * 3 + 1] !== pEdges[i * 3 + 1]
64
+ ) {
65
+ const iL = iCurStartIndex;
66
+ const iR = i - 1;
67
+ //const int iElems = i-iL;
68
+ iCurStartIndex = i;
69
+ QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f
70
+ }
71
+
72
+ }
73
+
74
+ const temp_edge_A = vec3.create();
75
+ const temp_edge_B = vec3.create();
76
+
77
+ // pair up, adjacent triangles
78
+ for (let i = 0; i < iEntries; i++) {
79
+
80
+ const i0 = pEdges[i * 3];
81
+ const i1 = pEdges[i * 3 + 1];
82
+ const f = pEdges[i * 3 + 2];
83
+
84
+ GetEdge(temp_edge_A, 0, piTriListIn, f * 3, i0, i1); // resolve index ordering and edge_num
85
+
86
+ const i0_A = temp_edge_A[0];
87
+ const i1_A = temp_edge_A[1];
88
+ const edgenum_A = temp_edge_A[2];
89
+
90
+ const bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] === -1;
91
+
92
+ if (!bUnassigned_A) {
93
+ continue;
94
+ }
95
+
96
+ let j = i + 1;
97
+
98
+ while (
99
+ j < iEntries
100
+ && i0 === pEdges[j * 3]
101
+ && i1 === pEdges[j * 3 + 1]
102
+ ) {
103
+
104
+ const t = pEdges[j * 3 + 2];
105
+
106
+
107
+ GetEdge(
108
+ temp_edge_B,
109
+ 0,
110
+ piTriListIn,
111
+ t * 3,
112
+ pEdges[j * 3],
113
+ pEdges[j * 3 + 1]
114
+ ); // resolve index ordering and edge_num
115
+
116
+ // flip i0_B and i1_B
117
+ const i0_B = temp_edge_B[1];
118
+ const i1_B = temp_edge_B[2];
119
+ const edgenum_B = temp_edge_B[2];
120
+
121
+ //assert(!(i0_A==i1_B && i1_A==i0_B));
122
+ const bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B] === -1;
123
+
124
+ if (i0_A === i0_B && i1_A === i1_B && bUnassigned_B) {
125
+
126
+ const t = pEdges[j * 3 + 2];
127
+ pTriInfos[f].FaceNeighbors[edgenum_A] = t;
128
+ //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1);
129
+ pTriInfos[t].FaceNeighbors[edgenum_B] = f;
130
+ break;
131
+
132
+ } else {
133
+ ++j;
134
+ }
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,31 @@
1
+ import { vec3 } from "gl-matrix";
2
+ import { GetTexCoord } from "./GetTexCoord.js";
3
+ import { fabsf } from "../../../../core/math/fabsf.js";
4
+
5
+ const t1 = vec3.create();
6
+ const t2 = vec3.create();
7
+ const t3 = vec3.create();
8
+
9
+ /**
10
+ * returns the texture area times 2
11
+ * @param {SMikkTSpaceContext } pContext
12
+ * @param {number[]} indices
13
+ * @param {number} indices_offset
14
+ * @returns {number}
15
+ */
16
+ export function CalcTexArea(pContext, indices, indices_offset) {
17
+
18
+ GetTexCoord(t1, pContext, indices[indices_offset ]);
19
+ GetTexCoord(t2, pContext, indices[indices_offset + 1]);
20
+ GetTexCoord(t3, pContext, indices[indices_offset + 2]);
21
+
22
+ const t21x = t2[0] - t1[0];
23
+ const t21y = t2[1] - t1[1];
24
+
25
+ const t31x = t3[0] - t1[0];
26
+ const t31y = t3[1] - t1[1];
27
+
28
+ const fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
29
+
30
+ return fabsf(fSignedAreaSTx2);
31
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ *
3
+ * @param {SSubGroup} pg1
4
+ * @param {SSubGroup } pg2
5
+ * @returns {boolean}
6
+ */
7
+ export function CompareSubGroups(pg1, pg2) {
8
+ const n = pg1.iNrFaces;
9
+
10
+ if (n !== pg2.iNrFaces) {
11
+ return false;
12
+ }
13
+
14
+ const tris_1 = pg1.pTriMembers;
15
+ const tris_2 = pg2.pTriMembers;
16
+
17
+ for (let i = 0; i < n; i++) {
18
+
19
+ if (tris_1[i] !== tris_2[i]) {
20
+ return false
21
+ }
22
+
23
+ }
24
+
25
+ return true;
26
+ }
@@ -0,0 +1,220 @@
1
+ import { QUAD_ONE_DEGEN_TRI } from "./constants/QUAD_ONE_DEGEN_TRI.js";
2
+ import { vec3 } from "gl-matrix";
3
+ import { GetPosition } from "./GetPosition.js";
4
+ import { MakeIndex } from "./MakeIndex.js";
5
+ import { assert } from "../../../../core/assert.js";
6
+
7
+ /**
8
+ * @type {vec3}
9
+ */
10
+ const vDstP = vec3.create();
11
+ const vSrcP = vec3.create();
12
+
13
+ class VertReverseLookupContext {
14
+ /**
15
+ *
16
+ * @type {boolean}
17
+ */
18
+ bIsInitialized = false;
19
+ /**
20
+ * int*
21
+ * @type {Int32Array|null}
22
+ */
23
+ pLookup = null;
24
+ /**
25
+ * int
26
+ * @type {number}
27
+ */
28
+ iMaxVertIndex = 0;
29
+ }
30
+
31
+ /**
32
+ *
33
+ * @param {number[]} piTriListIn
34
+ * @param {number} iNrTrianglesIn
35
+ * @param {VertReverseLookupContext} pLookupCtx
36
+ */
37
+ function GenerateReverseLookup(
38
+ piTriListIn,
39
+ iNrTrianglesIn,
40
+ pLookupCtx
41
+ ) {
42
+ let t;
43
+
44
+ // Figure out what size of lookup array we need.
45
+ pLookupCtx.iMaxVertIndex = -1;
46
+
47
+ for (t = 0; t < 3 * iNrTrianglesIn; t++) {
48
+ const iVertIndex = piTriListIn[t];
49
+
50
+ if (iVertIndex > pLookupCtx.iMaxVertIndex) {
51
+ pLookupCtx.iMaxVertIndex = iVertIndex;
52
+ }
53
+
54
+ }
55
+ // Allocate memory.
56
+ if (pLookupCtx.iMaxVertIndex < 1) {
57
+ // Nothing to allocate, all triangles are degenerate.
58
+ return;
59
+ }
60
+ pLookupCtx.pLookup = new Int32Array(pLookupCtx.iMaxVertIndex + 1);
61
+
62
+ // Fill in lookup.
63
+ for (t = 0; t <= pLookupCtx.iMaxVertIndex; t++) {
64
+ pLookupCtx.pLookup[t] = -1;
65
+ }
66
+
67
+ for (t = 0; t < 3 * iNrTrianglesIn; t++) {
68
+ const iVertIndex = piTriListIn[t];
69
+
70
+ if (pLookupCtx.pLookup[iVertIndex] !== -1) {
71
+ continue;
72
+ }
73
+
74
+ pLookupCtx.pLookup[iVertIndex] = t;
75
+ }
76
+ }
77
+
78
+ /**
79
+ *
80
+ * @param {VertReverseLookupContext} pLookupCtx
81
+ * @param {number[]} piTriListIn
82
+ * @param {number} iNrTrianglesIn
83
+ * @param {number} iVertexIndex
84
+ * @returns {number}
85
+ */
86
+ function LookupVertexIndexFromGoodTriangle(
87
+ pLookupCtx,
88
+ piTriListIn,
89
+ iNrTrianglesIn,
90
+ iVertexIndex
91
+ ) {
92
+ // Allocate lookup on demand.
93
+ if (!pLookupCtx.bIsInitialized) {
94
+ GenerateReverseLookup(piTriListIn, iNrTrianglesIn, pLookupCtx);
95
+ pLookupCtx.bIsInitialized = true;
96
+ }
97
+ // Make sure vertex index is in the mapping.
98
+ if (iVertexIndex > pLookupCtx.iMaxVertIndex) {
99
+ return -1;
100
+ }
101
+ if (pLookupCtx.pLookup === null) {
102
+ return -1;
103
+ }
104
+
105
+ // Perform actual lookup.
106
+ return pLookupCtx.pLookup[iVertexIndex];
107
+ }
108
+
109
+ /**
110
+ *
111
+ * @param {STSpace[]} psTspace
112
+ * @param {STriInfo[]} pTriInfos
113
+ * @param {number[]|Int32Array} piTriListIn
114
+ * @param {SMikkTSpaceContext} pContext
115
+ * @param {number} iNrTrianglesIn
116
+ * @param {number} iTotTris
117
+ * @returns {void}
118
+ */
119
+ export function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris) {
120
+
121
+ // deal with degenerate triangles
122
+ // punishment for degenerate triangles is O(N^2)
123
+ const lookupCtx = new VertReverseLookupContext();
124
+
125
+ for (let t = iNrTrianglesIn; t < iTotTris; t++) {
126
+ const tri0 = pTriInfos[t];
127
+
128
+ // degenerate triangles on a quad with one good triangle are skipped
129
+ // here but processed in the next loop
130
+ const bSkip = (tri0.iFlag & QUAD_ONE_DEGEN_TRI) !== 0;
131
+
132
+ if (bSkip) {
133
+ continue;
134
+ }
135
+
136
+ for (let i = 0; i < 3; i++) {
137
+
138
+ const index1 = piTriListIn[t * 3 + i];
139
+ const j = LookupVertexIndexFromGoodTriangle(lookupCtx, piTriListIn, iNrTrianglesIn, index1);
140
+
141
+ if (j < 0) {
142
+ // Matching vertex from good triangle is not found.
143
+ continue;
144
+ }
145
+
146
+ const iTri = Math.floor(j / 3);
147
+ const iVert = j % 3;
148
+
149
+ const tri1 = pTriInfos[iTri];
150
+
151
+ const iSrcVert = tri1.vert_num[iVert];
152
+ const iSrcOffs = tri1.iTSpacesOffs;
153
+
154
+ const iDstVert = tri0.vert_num[i];
155
+ const iDstOffs = tri0.iTSpacesOffs;
156
+
157
+ // copy tspace
158
+ const dst_tspace = psTspace[iDstOffs + iDstVert];
159
+ const src_tspace = psTspace[iSrcOffs + iSrcVert];
160
+
161
+ dst_tspace.copy(src_tspace);
162
+ }
163
+ }
164
+
165
+
166
+ // deal with degenerate quads with one good triangle
167
+ for (let t = 0; t < iNrTrianglesIn; t++) {
168
+ // this triangle belongs to a quad where the
169
+ // other triangle is degenerate
170
+ const tri = pTriInfos[t];
171
+
172
+ if ((tri.iFlag & QUAD_ONE_DEGEN_TRI) === 0) {
173
+ continue;
174
+ }
175
+
176
+ const pV = tri.vert_num;
177
+
178
+ const iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
179
+
180
+ let iMissingIndex = 0;
181
+
182
+ if ((iFlag & 2) === 0) {
183
+ iMissingIndex = 1;
184
+ } else if ((iFlag & 4) === 0) {
185
+ iMissingIndex = 2;
186
+ } else if ((iFlag & 8) === 0) {
187
+ iMissingIndex = 3;
188
+ }
189
+
190
+ const iOrgF = tri.iOrgFaceNumber;
191
+
192
+ GetPosition(vDstP, 0, pContext, MakeIndex(iOrgF, iMissingIndex));
193
+
194
+ let bNotFound = true;
195
+ let i = 0;
196
+
197
+ while (i < 3) {
198
+
199
+ const iVert = pV[i];
200
+ GetPosition(vSrcP, 0, pContext, MakeIndex(iOrgF, iVert));
201
+
202
+ if (vec3.exactEquals(vSrcP, vDstP)) {
203
+
204
+ const iOffs = tri.iTSpacesOffs;
205
+
206
+ psTspace[iOffs + iMissingIndex].copy(psTspace[iOffs + iVert]);
207
+
208
+ bNotFound = false;
209
+
210
+ break;
211
+
212
+ } else {
213
+ ++i;
214
+ }
215
+
216
+ }
217
+
218
+ assert(!bNotFound);
219
+ }
220
+ }
@@ -0,0 +1,115 @@
1
+ import { MARK_DEGENERATE } from "./constants/MARK_DEGENERATE.js";
2
+ import { QUAD_ONE_DEGEN_TRI } from "./constants/QUAD_ONE_DEGEN_TRI.js";
3
+ import { assert } from "../../../../core/assert.js";
4
+
5
+ /**
6
+ *
7
+ * @param {STriInfo[]} pTriInfos
8
+ * @param {number[]|Int32Array} piTriList_out
9
+ * @param {number} iNrTrianglesIn
10
+ * @param {number} iTotTris
11
+ * @returns {void}
12
+ */
13
+ export function DegenPrologue(
14
+ pTriInfos,
15
+ piTriList_out,
16
+ iNrTrianglesIn,
17
+ iTotTris
18
+ ) {
19
+ // locate quads with only one good triangle
20
+ let t = 0;
21
+
22
+ while (t < (iTotTris - 1)) {
23
+
24
+ const tri_0 = pTriInfos[t];
25
+ const tri_1 = pTriInfos[t + 1];
26
+
27
+ const iFO_a = tri_0.iOrgFaceNumber;
28
+ const iFO_b = tri_1.iOrgFaceNumber;
29
+
30
+ if (iFO_a === iFO_b) {
31
+
32
+ // this is a quad
33
+ const bIsDeg_a = (tri_0.iFlag & MARK_DEGENERATE) !== 0;
34
+ const bIsDeg_b = (tri_1.iFlag & MARK_DEGENERATE) !== 0;
35
+
36
+ if (bIsDeg_a !== bIsDeg_b) {
37
+ tri_0.iFlag |= QUAD_ONE_DEGEN_TRI;
38
+ tri_1.iFlag |= QUAD_ONE_DEGEN_TRI;
39
+ }
40
+
41
+ t += 2;
42
+
43
+ } else {
44
+ ++t;
45
+ }
46
+ }
47
+
48
+ // reorder list so all degen triangles are moved to the back
49
+ // without reordering the good triangles
50
+ let iNextGoodTriangleSearchIndex = 1;
51
+ let bStillFindingGoodOnes = true;
52
+
53
+ t = 0;
54
+
55
+ while (t < iNrTrianglesIn && bStillFindingGoodOnes) {
56
+
57
+ const bIsGood = (pTriInfos[t].iFlag & MARK_DEGENERATE) === 0;
58
+
59
+ if (bIsGood) {
60
+ if (iNextGoodTriangleSearchIndex < (t + 2)) {
61
+ iNextGoodTriangleSearchIndex = t + 2;
62
+ }
63
+ } else {
64
+ // search for the first good triangle.
65
+ let bJustADegenerate = true;
66
+
67
+ while (bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris) {
68
+
69
+ const bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag & MARK_DEGENERATE) === 0;
70
+
71
+ if (bIsGood) {
72
+ bJustADegenerate = false;
73
+ } else {
74
+ ++iNextGoodTriangleSearchIndex;
75
+ }
76
+
77
+ }
78
+
79
+ const t0 = t;
80
+ const t1 = iNextGoodTriangleSearchIndex;
81
+
82
+ ++iNextGoodTriangleSearchIndex;
83
+ assert.greaterThan(iNextGoodTriangleSearchIndex, (t + 1));
84
+
85
+ // swap triangle t0 and t1
86
+ if (!bJustADegenerate) {
87
+
88
+ for (let i = 0; i < 3; i++) {
89
+ const i0 = t0 * 3 + i;
90
+ const i1 = t1 * 3 + i;
91
+
92
+ const index = piTriList_out[i0];
93
+
94
+ piTriList_out[i0] = piTriList_out[i1];
95
+ piTriList_out[i1] = index;
96
+ }
97
+
98
+ const tri_info = pTriInfos[t0];
99
+ pTriInfos[t0] = pTriInfos[t1];
100
+ pTriInfos[t1] = tri_info;
101
+
102
+ } else {
103
+ // this is not supposed to happen
104
+ bStillFindingGoodOnes = false;
105
+ }
106
+ }
107
+
108
+ if (bStillFindingGoodOnes) {
109
+ ++t;
110
+ }
111
+ }
112
+
113
+ assert(bStillFindingGoodOnes); // code will still work.
114
+ assert.equal(iNrTrianglesIn, t);
115
+ }