@woosh/meep-engine 2.42.0 → 2.42.2

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 (70) hide show
  1. package/core/assert.js +2 -2
  2. package/core/collection/RingBuffer.js +15 -0
  3. package/core/collection/array/array_swap.js +3 -3
  4. package/core/collection/map/AsyncLoadingCache.js +47 -0
  5. package/core/geom/3d/aabb/aabb3_compute_distance_above_plane_max.js +1 -1
  6. package/core/math/statistics/computeSampleSize_Cochran.js +3 -3
  7. package/editor/ecs/component/editors/geom/QuaternionEditor.js +12 -5
  8. package/engine/Engine.js +6 -1
  9. package/engine/EngineBootstrapper.js +2 -1
  10. package/engine/EngineHarness.js +5 -1
  11. package/engine/asset/AssetManager.js +97 -7
  12. package/engine/development/performance/AbstractMetric.js +3 -1
  13. package/engine/development/performance/RingBufferMetric.js +39 -4
  14. package/engine/ecs/EntityBuilder.js +29 -4
  15. package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +17 -1
  16. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +18 -30
  17. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +57 -16
  18. package/engine/graphics/ecs/mesh-v2/allocate_v3.js +37 -0
  19. package/engine/graphics/geometry/MikkT/AddTriToGroup.js +10 -0
  20. package/engine/graphics/geometry/MikkT/AssignRecur.js +84 -0
  21. package/engine/graphics/geometry/MikkT/AvgTSpace.js +38 -0
  22. package/engine/graphics/geometry/MikkT/Build4RuleGroups.js +96 -0
  23. package/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +137 -0
  24. package/engine/graphics/geometry/MikkT/CalcTexArea.js +31 -0
  25. package/engine/graphics/geometry/MikkT/CompareSubGroups.js +26 -0
  26. package/engine/graphics/geometry/MikkT/DegenEpilogue.js +220 -0
  27. package/engine/graphics/geometry/MikkT/DegenPrologue.js +115 -0
  28. package/engine/graphics/geometry/MikkT/EvalTspace.js +128 -0
  29. package/engine/graphics/geometry/MikkT/GenerateInitialVerticesIndexList.js +48 -0
  30. package/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +184 -0
  31. package/engine/graphics/geometry/MikkT/GenerateTSpaces.js +226 -0
  32. package/engine/graphics/geometry/MikkT/GetEdge.js +45 -0
  33. package/engine/graphics/geometry/MikkT/GetNormal.js +16 -0
  34. package/engine/graphics/geometry/MikkT/GetPosition.js +25 -0
  35. package/engine/graphics/geometry/MikkT/GetTexCoord.js +18 -0
  36. package/engine/graphics/geometry/MikkT/InitTriInfo.js +180 -0
  37. package/engine/graphics/geometry/MikkT/Length.js +10 -0
  38. package/engine/graphics/geometry/MikkT/MakeIndex.js +18 -0
  39. package/engine/graphics/geometry/MikkT/MikkTSpace.js +165 -2197
  40. package/engine/graphics/geometry/MikkT/NormalizeSafe.js +21 -0
  41. package/engine/graphics/geometry/MikkT/NotZero.js +10 -0
  42. package/engine/graphics/geometry/MikkT/QuickSort.js +54 -0
  43. package/engine/graphics/geometry/MikkT/QuickSortEdges.js +71 -0
  44. package/engine/graphics/geometry/MikkT/SSubGroup.js +15 -0
  45. package/engine/graphics/geometry/MikkT/STSpace.js +36 -0
  46. package/engine/graphics/geometry/MikkT/constants/GROUP_WITH_ANY.js +1 -0
  47. package/engine/graphics/geometry/MikkT/constants/INTERNAL_RND_SORT_SEED.js +1 -0
  48. package/engine/graphics/geometry/MikkT/constants/MARK_DEGENERATE.js +1 -0
  49. package/engine/graphics/geometry/MikkT/constants/ORIENT_PRESERVING.js +1 -0
  50. package/engine/graphics/geometry/MikkT/constants/QUAD_ONE_DEGEN_TRI.js +1 -0
  51. package/engine/graphics/geometry/MikkT/m_getNormal.js +16 -0
  52. package/engine/graphics/geometry/MikkT/m_getNumFaces.js +8 -0
  53. package/engine/graphics/geometry/MikkT/m_getNumVerticesOfFace.js +11 -0
  54. package/engine/graphics/geometry/MikkT/m_getPosition.js +20 -0
  55. package/engine/graphics/geometry/MikkT/m_getTexCoord.js +16 -0
  56. package/engine/graphics/geometry/MikkT/m_setTSpace.js +35 -0
  57. package/engine/graphics/geometry/MikkT/m_setTSpaceBasic.js +22 -0
  58. package/engine/graphics/geometry/MikkT/malloc.js +16 -0
  59. package/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +52 -0
  60. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +3 -2
  61. package/engine/graphics/impostors/octahedral/prototypeBaker.js +5 -5
  62. package/engine/graphics/render/forward_plus/LightManager.js +16 -6
  63. package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +7 -1
  64. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +13 -3
  65. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
  66. package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +14 -2
  67. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
  68. package/engine/intelligence/behavior/util/RotationBehavior.js +69 -0
  69. package/generation/example/filters/SampleGroundMoistureFilter.js +5 -5
  70. package/package.json +1 -1
@@ -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
+ }
@@ -0,0 +1,128 @@
1
+ import { STSpace } from "./STSpace.js";
2
+ import { vec3 } from "gl-matrix";
3
+ import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
4
+ import { assert } from "../../../../core/assert.js";
5
+ import { GetNormal } from "./GetNormal.js";
6
+ import { NormalizeSafe } from "./NormalizeSafe.js";
7
+ import { GetPosition } from "./GetPosition.js";
8
+ import { clamp01 } from "../../../../core/math/clamp01.js";
9
+ import { v3_scale_dot_sub_normalize } from "./v3_scale_dot_sub_normalize.js";
10
+
11
+
12
+ let offset = 0;
13
+ const _buffer = new ArrayBuffer(3 * 4 * 6);
14
+
15
+ const vOs = new Float32Array(_buffer, offset, 3);
16
+ offset += 12;
17
+ const vOt = new Float32Array(_buffer, offset, 3);
18
+ offset += 12;
19
+ const n = new Float32Array(_buffer, offset, 3);
20
+ offset += 12;
21
+
22
+ const p0 = new Float32Array(_buffer, offset, 3);
23
+ offset += 12;
24
+ const p1 = new Float32Array(_buffer, offset, 3);
25
+ offset += 12;
26
+ const p2 = new Float32Array(_buffer, offset, 3);
27
+ offset += 12;
28
+
29
+ /**
30
+ *
31
+ * @param {STSpace} res
32
+ * @param {number[]|Uint32Array|Int32Array} face_indices
33
+ * @param {number} iFaces
34
+ * @param {number[]} piTriListIn
35
+ * @param {STriInfo[]} pTriInfos
36
+ * @param {SMikkTSpaceContext} pContext
37
+ * @param {number} iVertexRepresentitive
38
+ */
39
+ export function EvalTspace(res, face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVertexRepresentitive) {
40
+
41
+ let fAngleSum = 0;
42
+
43
+ res.vOs[0] = 0.0;
44
+ res.vOs[1] = 0.0;
45
+ res.vOs[2] = 0.0;
46
+
47
+ res.vOt[0] = 0.0;
48
+ res.vOt[1] = 0.0;
49
+ res.vOt[2] = 0.0;
50
+
51
+ res.fMagS = 0;
52
+ res.fMagT = 0;
53
+
54
+
55
+ for (let face = 0; face < iFaces; face++) {
56
+ const f = face_indices[face];
57
+ const tri_info = pTriInfos[f];
58
+
59
+ // only valid triangles get to add their contribution
60
+ if ((tri_info.iFlag & GROUP_WITH_ANY) === 0) {
61
+ let i = -1;
62
+
63
+ const f3 = 3 * f;
64
+
65
+ if (piTriListIn[f3] === iVertexRepresentitive) {
66
+ i = 0;
67
+ } else if (piTriListIn[f3 + 1] === iVertexRepresentitive) {
68
+ i = 1;
69
+ } else if (piTriListIn[f3 + 2] === iVertexRepresentitive) {
70
+ i = 2;
71
+ }
72
+
73
+ assert(i >= 0 && i < 3);
74
+
75
+ // project
76
+ const index = piTriListIn[f3 + i];
77
+
78
+ GetNormal(n, pContext, index);
79
+
80
+ v3_scale_dot_sub_normalize(vOs, n, tri_info.vOs);
81
+ v3_scale_dot_sub_normalize(vOt, n, tri_info.vOt);
82
+
83
+ const i0 = piTriListIn[f3 + (i > 0 ? (i - 1) : 2)];
84
+ const i1 = piTriListIn[f3 + i];
85
+ const i2 = piTriListIn[f3 + (i < 2 ? (i + 1) : 0)];
86
+
87
+ GetPosition(p0, 0, pContext, i0);
88
+ GetPosition(p1, 0, pContext, i1);
89
+ GetPosition(p2, 0, pContext, i2);
90
+
91
+ vec3.sub(p0, p0, p1);
92
+ vec3.sub(p1, p2, p1);
93
+
94
+ // project
95
+ v3_scale_dot_sub_normalize(p0, n, p0);
96
+ v3_scale_dot_sub_normalize(p1, n, p1);
97
+
98
+ // weight contribution by the angle
99
+ // between the two edge vectors
100
+
101
+ const fCos = clamp01(vec3.dot(p0, p1));
102
+ const fAngle = Math.acos(fCos);
103
+ const fMagS = tri_info.fMagS;
104
+ const fMagT = tri_info.fMagT;
105
+
106
+ vec3.scale(p2, vOs, fAngle);
107
+ vec3.add(res.vOs, res.vOs, p2);
108
+
109
+ vec3.scale(p2, vOt, fAngle);
110
+ vec3.add(res.vOt, res.vOt, p2);
111
+
112
+ res.fMagS += (fAngle * fMagS);
113
+ res.fMagT += (fAngle * fMagT);
114
+
115
+ fAngleSum += fAngle;
116
+ }
117
+ }
118
+
119
+ // normalize
120
+ NormalizeSafe(res.vOs, res.vOs);
121
+ NormalizeSafe(res.vOt, res.vOt);
122
+
123
+ if (fAngleSum > 0) {
124
+ res.fMagS /= fAngleSum;
125
+ res.fMagT /= fAngleSum;
126
+ }
127
+
128
+ }
@@ -0,0 +1,48 @@
1
+ import { m_getNumFaces } from "./m_getNumFaces.js";
2
+ import { MakeIndex } from "./MakeIndex.js";
3
+ import { assert } from "../../../../core/assert.js";
4
+
5
+ /**
6
+ *
7
+ * @param {STriInfo[]} pTriInfos
8
+ * @param {number[]|Int32Array} piTriList_out
9
+ * @param {SMikkTSpaceContext } pContext
10
+ * @param {number} iNrTrianglesIn
11
+ * @return {number}
12
+ */
13
+ export function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iNrTrianglesIn) {
14
+ let iTSpacesOffs = 0;
15
+ let iDstTriIndex = 0;
16
+
17
+ const face_count = m_getNumFaces(pContext);
18
+
19
+ for (let f = 0; f < face_count; f++) {
20
+
21
+ const tri_info = pTriInfos[iDstTriIndex];
22
+
23
+ tri_info.iOrgFaceNumber = f;
24
+ tri_info.iTSpacesOffs = iTSpacesOffs;
25
+
26
+ const pVerts = tri_info.vert_num;
27
+
28
+ pVerts[0] = 0;
29
+ pVerts[1] = 1;
30
+ pVerts[2] = 2;
31
+
32
+ piTriList_out[iDstTriIndex * 3 ] = MakeIndex(f, 0);
33
+ piTriList_out[iDstTriIndex * 3 + 1] = MakeIndex(f, 1);
34
+ piTriList_out[iDstTriIndex * 3 + 2] = MakeIndex(f, 2);
35
+
36
+ ++iDstTriIndex; // next
37
+
38
+ iTSpacesOffs += 3;
39
+ assert.lessThanOrEqual(iDstTriIndex, iNrTrianglesIn);
40
+ }
41
+
42
+ for (let t = 0; t < iNrTrianglesIn; t++) {
43
+ pTriInfos[t].iFlag = 0;
44
+ }
45
+
46
+ // return total amount of tspaces
47
+ return iTSpacesOffs;
48
+ }
@@ -0,0 +1,184 @@
1
+ import { vec3 } from "gl-matrix";
2
+ import { GetPosition } from "./GetPosition.js";
3
+ import { computeHashFloat } from "../../../../core/math/hash/computeHashFloat.js";
4
+ import { GetNormal } from "./GetNormal.js";
5
+ import { GetTexCoord } from "./GetTexCoord.js";
6
+
7
+ /**
8
+ *
9
+ * @param {number} x
10
+ * @param {number} y
11
+ * @param {number} z
12
+ * @returns {number}
13
+ */
14
+ function HASH(x, y, z) {
15
+ return ((x) * 73856093) ^ ((y) * 19349663) ^ ((z) * 83492791);
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param {number} x
21
+ * @param {number} y
22
+ * @param {number} z
23
+ * @returns {number}
24
+ */
25
+ function HASH_F(x, y, z) {
26
+ return (computeHashFloat(x) * 73856093) ^ (computeHashFloat(y) * 19349663) ^ (computeHashFloat(z) * 83492791);
27
+ }
28
+
29
+ /**
30
+ * Sort comp and data based on comp.
31
+ * comp2 and data2 are used as temporary storage.
32
+ *
33
+ * @param {Uint32Array} comp
34
+ * @param {Int32Array} data
35
+ * @param {Uint32Array} comp2
36
+ * @param {Int32Array} data2
37
+ * @param {number} n
38
+ */
39
+ function radixsort_pair(comp, data, comp2, data2, n) {
40
+ let shift = 0;
41
+
42
+ let _data_0 = data;
43
+ let _data_1 = data2;
44
+
45
+ let _comp_0 = comp;
46
+ let _comp_1 = comp2;
47
+
48
+ for (let pass = 0; pass < 4; pass++, shift += 8) {
49
+ const bins = new Int32Array(257);
50
+ /* Count number of elements per bin. */
51
+ for (let i = 0; i < n; i++) {
52
+ bins[((_comp_0[i] >> shift) & 0xff) + 1]++;
53
+ }
54
+ /* Compute prefix sum to find position of each bin in the sorted array. */
55
+ for (let i = 2; i < 256; i++) {
56
+ bins[i] += bins[i - 1];
57
+ }
58
+ /* Insert the elements in their correct location based on their bin. */
59
+ for (let i = 0; i < n; i++) {
60
+ const pos = bins[(_comp_0[i] >> shift) & 0xff]++;
61
+ _comp_1[pos] = _comp_0[i];
62
+ _data_1[pos] = _data_0[i];
63
+ }
64
+
65
+ /* Swap arrays. */
66
+ let tmpdata = _data_0;
67
+ _data_0 = _data_1;
68
+ _data_1 = tmpdata;
69
+
70
+ let tmpcomp = _comp_0;
71
+ _comp_0 = _comp_1;
72
+ _comp_1 = tmpcomp;
73
+ }
74
+ }
75
+
76
+ /**
77
+ *
78
+ * @param {number[]|Int32Array} piTriList_in_and_out
79
+ * @param {SMikkTSpaceContext} pContext
80
+ * @param {number} iNrTrianglesIn
81
+ * @returns {void}
82
+ */
83
+ export function GenerateSharedVerticesIndexList(
84
+ piTriList_in_and_out,
85
+ pContext,
86
+ iNrTrianglesIn
87
+ ) {
88
+ const numVertices = iNrTrianglesIn * 3;
89
+
90
+ const _buffer = new ArrayBuffer(numVertices * 4 * 4);
91
+
92
+ const hashes = new Uint32Array(_buffer, 0, numVertices);
93
+ const indices = new Int32Array(_buffer, numVertices * 4, numVertices);
94
+ const temp_hashes = new Uint32Array(_buffer, numVertices * 2 * 4, numVertices);
95
+ const temp_indices = new Int32Array(_buffer, numVertices * 3 * 4, numVertices);
96
+
97
+ const v = vec3.create();
98
+
99
+ for (let i = 0; i < numVertices; i++) {
100
+ const index = piTriList_in_and_out[i];
101
+
102
+ GetPosition(v, 0, pContext, index);
103
+ const hashP = HASH_F(v[0], v[1], v[2]);
104
+
105
+ GetNormal(v, pContext, index);
106
+ const hashN = HASH_F(v[0], v[1], v[2]);
107
+
108
+ GetTexCoord(v, pContext, index);
109
+ const hashT = HASH_F(v[0], v[1], v[2]);
110
+
111
+ hashes[i] = HASH(hashP, hashN, hashT);
112
+ indices[i] = i;
113
+ }
114
+
115
+ radixsort_pair(hashes, indices, temp_hashes, temp_indices, numVertices);
116
+
117
+ // free(temp_hashes);
118
+ // free(temp_indices);
119
+
120
+
121
+ const vT = vec3.create();
122
+ const vP = vec3.create();
123
+
124
+ const vT2 = vec3.create();
125
+ const vP2 = vec3.create();
126
+
127
+ const vN = vec3.create();
128
+ const vN2 = vec3.create();
129
+
130
+ /*
131
+ * Process blocks of vertices with the same hash.
132
+ * Vertices in the block might still be separate, but we know for sure that
133
+ * vertices in different blocks will never be identical.
134
+ */
135
+ let blockstart = 0;
136
+ while (blockstart < numVertices) {
137
+ /* Find end of this block (exclusive). */
138
+ const hash = hashes[blockstart];
139
+ let blockend = blockstart + 1;
140
+ for (; blockend < numVertices; blockend++) {
141
+ if (hashes[blockend] !== hash)
142
+ break;
143
+ }
144
+
145
+ for (let i = blockstart; i < blockend; i++) {
146
+
147
+ const index1 = piTriList_in_and_out[indices[i]];
148
+
149
+ GetPosition(vP, 0, pContext, index1);
150
+ GetNormal(vN, pContext, index1);
151
+ GetTexCoord(vT, pContext, index1);
152
+
153
+ for (let i2 = i + 1; i2 < blockend; i2++) {
154
+ const index2 = piTriList_in_and_out[indices[i2]];
155
+
156
+ if (index1 === index2) {
157
+ continue;
158
+ }
159
+
160
+ GetPosition(vP2, 0, pContext, index2);
161
+ GetNormal(vN2, pContext, index2);
162
+ GetTexCoord(vT2, pContext, index2);
163
+
164
+ if (
165
+ vP[0] === vP2[0] && vP[1] === vP2[1] && vP[2] === vP2[2] &&
166
+ vN[0] === vN2[0] && vN[1] === vN2[1] && vN[2] === vN2[2] &&
167
+ vT[0] === vT2[0] && vT[1] === vT2[1] && vT[2] === vT2[2]
168
+ ) {
169
+ piTriList_in_and_out[indices[i2]] = index1;
170
+ /* Once i2>i has been identified as a duplicate, we can stop since any
171
+ * i3>i2>i that is a duplicate of i (and therefore also i2) will also be
172
+ * compared to i2 and therefore be identified there anyways. */
173
+ break;
174
+ }
175
+ }
176
+ }
177
+
178
+ /* Advance to next block. */
179
+ blockstart = blockend;
180
+ }
181
+
182
+ // free(hashes);
183
+ // free(indices);
184
+ }