@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.
- package/core/assert.js +2 -2
- package/core/collection/RingBuffer.js +15 -0
- package/core/collection/array/array_swap.js +3 -3
- package/core/collection/map/AsyncLoadingCache.js +47 -0
- package/core/geom/3d/aabb/aabb3_compute_distance_above_plane_max.js +1 -1
- package/core/math/statistics/computeSampleSize_Cochran.js +3 -3
- package/editor/ecs/component/editors/geom/QuaternionEditor.js +12 -5
- package/engine/Engine.js +6 -1
- package/engine/EngineBootstrapper.js +2 -1
- package/engine/EngineHarness.js +5 -1
- package/engine/asset/AssetManager.js +97 -7
- package/engine/development/performance/AbstractMetric.js +3 -1
- package/engine/development/performance/RingBufferMetric.js +39 -4
- package/engine/ecs/EntityBuilder.js +29 -4
- package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +17 -1
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +18 -30
- package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +57 -16
- package/engine/graphics/ecs/mesh-v2/allocate_v3.js +37 -0
- package/engine/graphics/geometry/MikkT/AddTriToGroup.js +10 -0
- package/engine/graphics/geometry/MikkT/AssignRecur.js +84 -0
- package/engine/graphics/geometry/MikkT/AvgTSpace.js +38 -0
- package/engine/graphics/geometry/MikkT/Build4RuleGroups.js +96 -0
- package/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +137 -0
- package/engine/graphics/geometry/MikkT/CalcTexArea.js +31 -0
- package/engine/graphics/geometry/MikkT/CompareSubGroups.js +26 -0
- package/engine/graphics/geometry/MikkT/DegenEpilogue.js +220 -0
- package/engine/graphics/geometry/MikkT/DegenPrologue.js +115 -0
- package/engine/graphics/geometry/MikkT/EvalTspace.js +128 -0
- package/engine/graphics/geometry/MikkT/GenerateInitialVerticesIndexList.js +48 -0
- package/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +184 -0
- package/engine/graphics/geometry/MikkT/GenerateTSpaces.js +226 -0
- package/engine/graphics/geometry/MikkT/GetEdge.js +45 -0
- package/engine/graphics/geometry/MikkT/GetNormal.js +16 -0
- package/engine/graphics/geometry/MikkT/GetPosition.js +25 -0
- package/engine/graphics/geometry/MikkT/GetTexCoord.js +18 -0
- package/engine/graphics/geometry/MikkT/InitTriInfo.js +180 -0
- package/engine/graphics/geometry/MikkT/Length.js +10 -0
- package/engine/graphics/geometry/MikkT/MakeIndex.js +18 -0
- package/engine/graphics/geometry/MikkT/MikkTSpace.js +165 -2197
- package/engine/graphics/geometry/MikkT/NormalizeSafe.js +21 -0
- package/engine/graphics/geometry/MikkT/NotZero.js +10 -0
- package/engine/graphics/geometry/MikkT/QuickSort.js +54 -0
- package/engine/graphics/geometry/MikkT/QuickSortEdges.js +71 -0
- package/engine/graphics/geometry/MikkT/SSubGroup.js +15 -0
- package/engine/graphics/geometry/MikkT/STSpace.js +36 -0
- package/engine/graphics/geometry/MikkT/constants/GROUP_WITH_ANY.js +1 -0
- package/engine/graphics/geometry/MikkT/constants/INTERNAL_RND_SORT_SEED.js +1 -0
- package/engine/graphics/geometry/MikkT/constants/MARK_DEGENERATE.js +1 -0
- package/engine/graphics/geometry/MikkT/constants/ORIENT_PRESERVING.js +1 -0
- package/engine/graphics/geometry/MikkT/constants/QUAD_ONE_DEGEN_TRI.js +1 -0
- package/engine/graphics/geometry/MikkT/m_getNormal.js +16 -0
- package/engine/graphics/geometry/MikkT/m_getNumFaces.js +8 -0
- package/engine/graphics/geometry/MikkT/m_getNumVerticesOfFace.js +11 -0
- package/engine/graphics/geometry/MikkT/m_getPosition.js +20 -0
- package/engine/graphics/geometry/MikkT/m_getTexCoord.js +16 -0
- package/engine/graphics/geometry/MikkT/m_setTSpace.js +35 -0
- package/engine/graphics/geometry/MikkT/m_setTSpaceBasic.js +22 -0
- package/engine/graphics/geometry/MikkT/malloc.js +16 -0
- package/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +52 -0
- package/engine/graphics/impostors/octahedral/ImpostorBaker.js +3 -2
- package/engine/graphics/impostors/octahedral/prototypeBaker.js +5 -5
- package/engine/graphics/render/forward_plus/LightManager.js +16 -6
- package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +7 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +13 -3
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
- package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +14 -2
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
- package/engine/intelligence/behavior/util/RotationBehavior.js +69 -0
- package/generation/example/filters/SampleGroundMoistureFilter.js +5 -5
- 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
|
+
}
|