@carbonenginejs/runtime-utils 0.1.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.
- package/LICENSE +21 -0
- package/NOTICE +23 -0
- package/README.md +56 -0
- package/THIRD-PARTY-NOTICES.md +38 -0
- package/docs/README.md +81 -0
- package/docs/architecture.md +101 -0
- package/docs/concepts/foundation-consolidation.md +86 -0
- package/docs/const-kb.md +92 -0
- package/docs/core-types/DECORATOR-TODOS.md +25 -0
- package/docs/core-types/README.md +203 -0
- package/docs/reference/api.md +70 -0
- package/docs/reference/classes/README.md +115 -0
- package/package.json +132 -0
- package/src/arrays.js +5 -0
- package/src/audio/audioFormats.js +34 -0
- package/src/audio/index.js +1 -0
- package/src/box3.js +1385 -0
- package/src/bytes.js +56 -0
- package/src/compression.js +56 -0
- package/src/constants/index.js +6 -0
- package/src/constants.js +15 -0
- package/src/curve.js +419 -0
- package/src/d3d/dxgiFormats.js +46 -0
- package/src/d3d/index.js +2 -0
- package/src/d3d/primitiveTopology.js +11 -0
- package/src/document/CjsCarbonDocument.js +212 -0
- package/src/document/CjsClassRegistry.js +373 -0
- package/src/document/CjsDocumentDehydrator.js +142 -0
- package/src/document/CjsDocumentHydrator.js +156 -0
- package/src/document/CjsStructRegistry.js +348 -0
- package/src/document/hydrationAdapter.js +129 -0
- package/src/document/index.js +6 -0
- package/src/geometry/box.js +137 -0
- package/src/geometry/cylinder.js +244 -0
- package/src/geometry/helpers/LICENSE +15 -0
- package/src/geometry/helpers/earcut.js +766 -0
- package/src/geometry/helpers/misc.js +103 -0
- package/src/geometry/index.js +8 -0
- package/src/geometry/json.js +165 -0
- package/src/geometry/lathe.js +172 -0
- package/src/geometry/octahedron.js +0 -0
- package/src/geometry/plane.js +81 -0
- package/src/geometry/shape.js +95 -0
- package/src/geometry/sphere.js +123 -0
- package/src/geometry/torus.js +96 -0
- package/src/graphics/colorSpaces.js +22 -0
- package/src/graphics/index.js +4 -0
- package/src/graphics/pixelFormats.js +158 -0
- package/src/graphics/textureDimensions.js +22 -0
- package/src/graphics/trinityEnums.js +87 -0
- package/src/index.js +58 -0
- package/src/is.js +524 -0
- package/src/json.js +23 -0
- package/src/lifecycle/CjsLifecycleState.js +77 -0
- package/src/lifecycle/index.js +1 -0
- package/src/lne3.js +497 -0
- package/src/lookup.js +48 -0
- package/src/mat3.js +131 -0
- package/src/mat4.js +699 -0
- package/src/math/index.js +25 -0
- package/src/math/scalar.js +63 -0
- package/src/media/index.js +1 -0
- package/src/media/mediaTypes.js +50 -0
- package/src/mesh.js +394 -0
- package/src/model/CjsEventEmitter.js +333 -0
- package/src/model/CjsModel.js +1544 -0
- package/src/model/CjsModelState.js +72 -0
- package/src/model/index.js +4 -0
- package/src/model/sourceRecordUtils.js +54 -0
- package/src/noise.js +310 -0
- package/src/num.js +827 -0
- package/src/path.js +21 -0
- package/src/pln.js +762 -0
- package/src/pool.js +160 -0
- package/src/quat.js +144 -0
- package/src/ray3.js +1085 -0
- package/src/renderContext/formats.js +145 -0
- package/src/renderContext/index.js +5 -0
- package/src/renderContext/presentation.js +125 -0
- package/src/renderContext/resources.js +27 -0
- package/src/renderContext/upscaling.js +22 -0
- package/src/renderContext/window.js +20 -0
- package/src/runtime/CjsRuntimeState.js +50 -0
- package/src/schema/CjsSchema.js +1009 -0
- package/src/schema/index.js +17 -0
- package/src/shader/index.js +1 -0
- package/src/shader/shaderStages.js +37 -0
- package/src/sph3.js +754 -0
- package/src/tangent.js +288 -0
- package/src/text.js +40 -0
- package/src/tri3.js +650 -0
- package/src/types/carbonTypes.js +635 -0
- package/src/types/index.js +2 -0
- package/src/utils.js +58 -0
- package/src/validation.js +46 -0
- package/src/vec2.js +229 -0
- package/src/vec3.js +1172 -0
- package/src/vec4.js +347 -0
- package/src/vertex.js +108 -0
- package/src/webgpu/index.js +1 -0
- package/src/webgpu/textureFormats.js +121 -0
package/src/tangent.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packed tangent-frame helpers for CarbonEngineJS/GR2-style mesh data.
|
|
3
|
+
*
|
|
4
|
+
* The packed-frame constants and decode/encode behavior are based on observed
|
|
5
|
+
* Fenris Creations (CCP Games) shader behavior for EVE/Carbon packed tangent
|
|
6
|
+
* frames. No shader source is included here.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
generateBiNormals,
|
|
11
|
+
generateNormals,
|
|
12
|
+
generateTangentFrames,
|
|
13
|
+
generateTangents
|
|
14
|
+
} from "./mesh.js";
|
|
15
|
+
import {
|
|
16
|
+
EPSILON,
|
|
17
|
+
clamp
|
|
18
|
+
} from "./num.js";
|
|
19
|
+
import {
|
|
20
|
+
cross,
|
|
21
|
+
dot,
|
|
22
|
+
length as vec3Length,
|
|
23
|
+
normalize
|
|
24
|
+
} from "gl-matrix/esm/vec3.js";
|
|
25
|
+
|
|
26
|
+
/** Full-turn float32 constant used by the CCP tangent-frame shader. */
|
|
27
|
+
export const TANGENT_TAU = 6.28318548;
|
|
28
|
+
|
|
29
|
+
/** Half-turn float32 constant used by the CCP tangent-frame shader. */
|
|
30
|
+
export const TANGENT_PI = 3.14159274;
|
|
31
|
+
|
|
32
|
+
const
|
|
33
|
+
TAU = TANGENT_TAU,
|
|
34
|
+
PI = TANGENT_PI,
|
|
35
|
+
POLAR_EPSILON = 1e-6;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Packed UNorm sentinel used for vertices with no authored tangent frame.
|
|
39
|
+
*
|
|
40
|
+
* @type {number[]}
|
|
41
|
+
*/
|
|
42
|
+
export const NULL_TANGENT_UNORM = Object.freeze([ 0, 1, 0, 1 ]);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Test whether a packed tangent payload is the null-frame sentinel.
|
|
46
|
+
*
|
|
47
|
+
* @param {ArrayLike<number>} u Four UNorm values.
|
|
48
|
+
* @returns {boolean} Whether the payload marks a missing authored frame.
|
|
49
|
+
*/
|
|
50
|
+
export function isNullTangent(u)
|
|
51
|
+
{
|
|
52
|
+
const
|
|
53
|
+
e1 = u[1],
|
|
54
|
+
e3 = u[3];
|
|
55
|
+
|
|
56
|
+
return (e1 <= 1e-3 || e1 >= 1 - 1e-3) && (e3 <= 1e-3 || e3 >= 1 - 1e-3);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const
|
|
60
|
+
scratchT = new Float64Array(3),
|
|
61
|
+
scratchB = new Float64Array(3),
|
|
62
|
+
scratchN = new Float64Array(3);
|
|
63
|
+
|
|
64
|
+
function decodeTangentFrameInto(u0, u1, u2, u3, outT, outB, outN)
|
|
65
|
+
{
|
|
66
|
+
const
|
|
67
|
+
a0 = u0 * TAU - PI,
|
|
68
|
+
a1 = u1 * TAU - PI,
|
|
69
|
+
a2 = u2 * TAU - PI,
|
|
70
|
+
a3 = u3 * TAU - PI,
|
|
71
|
+
s1 = Math.abs(Math.sin(a1)),
|
|
72
|
+
s3 = Math.abs(Math.sin(a3));
|
|
73
|
+
|
|
74
|
+
outT[0] = s1 * Math.cos(a0);
|
|
75
|
+
outT[1] = s1 * Math.sin(a0);
|
|
76
|
+
outT[2] = Math.cos(a1);
|
|
77
|
+
|
|
78
|
+
outB[0] = s3 * Math.cos(a2);
|
|
79
|
+
outB[1] = s3 * Math.sin(a2);
|
|
80
|
+
outB[2] = Math.cos(a3);
|
|
81
|
+
|
|
82
|
+
const sign = (a1 > 0 && a3 > 0) ? 1 : -1;
|
|
83
|
+
outN[0] = (outT[1] * outB[2] - outT[2] * outB[1]) * sign;
|
|
84
|
+
outN[1] = (outT[2] * outB[0] - outT[0] * outB[2]) * sign;
|
|
85
|
+
outN[2] = (outT[0] * outB[1] - outT[1] * outB[0]) * sign;
|
|
86
|
+
|
|
87
|
+
return s1 < 1e-6 && s3 < 1e-6;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Decode a packed tangent frame.
|
|
92
|
+
*
|
|
93
|
+
* @param {ArrayLike<number>} u Four UNorm values in `[0, 1]`.
|
|
94
|
+
* @returns {{T: number[], B: number[], N: number[], null: boolean}} Decoded basis.
|
|
95
|
+
*/
|
|
96
|
+
export function decodeTangentFrame(u)
|
|
97
|
+
{
|
|
98
|
+
const isNull = decodeTangentFrameInto(u[0], u[1], u[2], u[3], scratchT, scratchB, scratchN);
|
|
99
|
+
return { T: Array.from(scratchT), B: Array.from(scratchB), N: Array.from(scratchN), null: isNull };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Encode a tangent frame back to four UNorm angles.
|
|
104
|
+
*
|
|
105
|
+
* @param {ArrayLike<number>} T Unit tangent.
|
|
106
|
+
* @param {ArrayLike<number>} B Unit binormal.
|
|
107
|
+
* @param {ArrayLike<number>} [N] Unit normal; only handedness is used.
|
|
108
|
+
* @returns {number[]} Four UNorm values in `[0, 1]`.
|
|
109
|
+
*/
|
|
110
|
+
export function encodeTangentFrame(T, B, N)
|
|
111
|
+
{
|
|
112
|
+
let a0 = Math.atan2(T[1], T[0]),
|
|
113
|
+
a1 = Math.acos(clamp(T[2], -1, 1));
|
|
114
|
+
|
|
115
|
+
const a2 = Math.atan2(B[1], B[0]);
|
|
116
|
+
let a3 = Math.acos(clamp(B[2], -1, 1));
|
|
117
|
+
|
|
118
|
+
const negativeHandedness = N && dot(N, cross([ 0, 0, 0 ], T, B)) < 0;
|
|
119
|
+
if (negativeHandedness)
|
|
120
|
+
{
|
|
121
|
+
a1 = a1 === 0 ? -POLAR_EPSILON : -a1;
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
{
|
|
125
|
+
if (a1 === 0) a1 = POLAR_EPSILON;
|
|
126
|
+
if (a3 === 0) a3 = POLAR_EPSILON;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const enc = angle => clamp((angle + PI) / TAU, 0, 1);
|
|
130
|
+
return [ enc(a0), enc(a1), enc(a2), enc(a3) ];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function vertexCount(mesh)
|
|
134
|
+
{
|
|
135
|
+
const p = mesh.vertex && mesh.vertex.position;
|
|
136
|
+
return p ? (p.length / 3) | 0 : 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Is this shared JSON mesh's tangent frame packed?
|
|
141
|
+
*
|
|
142
|
+
* @param {object} mesh Shared JSON mesh.
|
|
143
|
+
* @returns {boolean} Whether the mesh has packed tangent frames.
|
|
144
|
+
*/
|
|
145
|
+
export function isPacked(mesh)
|
|
146
|
+
{
|
|
147
|
+
const v = mesh.vertex;
|
|
148
|
+
if (!v || !v.tangent || !v.tangent.length) return false;
|
|
149
|
+
|
|
150
|
+
const n = vertexCount(mesh);
|
|
151
|
+
if (!n) return false;
|
|
152
|
+
|
|
153
|
+
const
|
|
154
|
+
comps = v.tangent.length / n,
|
|
155
|
+
empty = value => !value || value.length === 0;
|
|
156
|
+
|
|
157
|
+
return comps === 4 && empty(v.normal) && empty(v.binormal);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Unpack a packed shared JSON mesh in place.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} mesh Shared JSON mesh to mutate.
|
|
164
|
+
* @returns {boolean} Whether unpacking happened.
|
|
165
|
+
*/
|
|
166
|
+
export function unpackMeshTangents(mesh)
|
|
167
|
+
{
|
|
168
|
+
if (!isPacked(mesh)) return false;
|
|
169
|
+
|
|
170
|
+
const
|
|
171
|
+
v = mesh.vertex,
|
|
172
|
+
n = vertexCount(mesh),
|
|
173
|
+
src = v.tangent,
|
|
174
|
+
normal = new Array(n * 3),
|
|
175
|
+
tangent = new Array(n * 3),
|
|
176
|
+
binormal = new Array(n * 3);
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < n; i++)
|
|
179
|
+
{
|
|
180
|
+
const
|
|
181
|
+
s = i * 4,
|
|
182
|
+
o = i * 3,
|
|
183
|
+
isNull = decodeTangentFrameInto(src[s], src[s + 1], src[s + 2], src[s + 3], scratchT, scratchB, scratchN);
|
|
184
|
+
|
|
185
|
+
if (isNull)
|
|
186
|
+
{
|
|
187
|
+
normal[o] = normal[o + 1] = normal[o + 2] = 0;
|
|
188
|
+
tangent[o] = tangent[o + 1] = tangent[o + 2] = 0;
|
|
189
|
+
binormal[o] = binormal[o + 1] = binormal[o + 2] = 0;
|
|
190
|
+
}
|
|
191
|
+
else
|
|
192
|
+
{
|
|
193
|
+
normal[o] = scratchN[0];
|
|
194
|
+
normal[o + 1] = scratchN[1];
|
|
195
|
+
normal[o + 2] = scratchN[2];
|
|
196
|
+
tangent[o] = scratchT[0];
|
|
197
|
+
tangent[o + 1] = scratchT[1];
|
|
198
|
+
tangent[o + 2] = scratchT[2];
|
|
199
|
+
binormal[o] = scratchB[0];
|
|
200
|
+
binormal[o + 1] = scratchB[1];
|
|
201
|
+
binormal[o + 2] = scratchB[2];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
v.normal = normal;
|
|
206
|
+
v.tangent = tangent;
|
|
207
|
+
v.binormal = binormal;
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Pack explicit tangent frames into GR2-style four-component tangent data.
|
|
213
|
+
*
|
|
214
|
+
* @param {ArrayLike<number>} normals Flat xyz normals.
|
|
215
|
+
* @param {ArrayLike<number>} tangents Flat xyz tangents.
|
|
216
|
+
* @param {ArrayLike<number>} binormals Flat xyz binormals.
|
|
217
|
+
* @returns {number[]} Flat xyzw packed tangent-frame values.
|
|
218
|
+
*/
|
|
219
|
+
export function packTangentFrames(normals, tangents, binormals)
|
|
220
|
+
{
|
|
221
|
+
if (normals.length !== tangents.length ||
|
|
222
|
+
normals.length !== binormals.length ||
|
|
223
|
+
normals.length % 3 !== 0)
|
|
224
|
+
{
|
|
225
|
+
throw new Error("packTangentFrames requires matching complete xyz channels");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const packed = new Array((normals.length / 3) * 4);
|
|
229
|
+
for (let i = 0, o = 0; i < normals.length; i += 3, o += 4)
|
|
230
|
+
{
|
|
231
|
+
const components = [
|
|
232
|
+
normals[i], normals[i + 1], normals[i + 2],
|
|
233
|
+
tangents[i], tangents[i + 1], tangents[i + 2],
|
|
234
|
+
binormals[i], binormals[i + 1], binormals[i + 2]
|
|
235
|
+
];
|
|
236
|
+
if (!components.every(Number.isFinite))
|
|
237
|
+
{
|
|
238
|
+
throw new Error(`packTangentFrames received non-finite data at vertex ${i / 3}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const
|
|
242
|
+
normal = normalize([ 0, 0, 0 ], components.slice(0, 3)),
|
|
243
|
+
tangent = normalize([ 0, 0, 0 ], components.slice(3, 6)),
|
|
244
|
+
binormal = normalize([ 0, 0, 0 ], components.slice(6, 9)),
|
|
245
|
+
frameNormalLength = vec3Length(cross([ 0, 0, 0 ], tangent, binormal));
|
|
246
|
+
|
|
247
|
+
if (vec3Length(normal) <= EPSILON ||
|
|
248
|
+
vec3Length(tangent) <= EPSILON ||
|
|
249
|
+
vec3Length(binormal) <= EPSILON ||
|
|
250
|
+
frameNormalLength <= EPSILON)
|
|
251
|
+
{
|
|
252
|
+
packed[o] = NULL_TANGENT_UNORM[0];
|
|
253
|
+
packed[o + 1] = NULL_TANGENT_UNORM[1];
|
|
254
|
+
packed[o + 2] = NULL_TANGENT_UNORM[2];
|
|
255
|
+
packed[o + 3] = NULL_TANGENT_UNORM[3];
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const encoded = encodeTangentFrame(tangent, binormal, normal);
|
|
260
|
+
packed[o] = encoded[0];
|
|
261
|
+
packed[o + 1] = encoded[1];
|
|
262
|
+
packed[o + 2] = encoded[2];
|
|
263
|
+
packed[o + 3] = encoded[3];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return packed;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export const tangent = Object.freeze({
|
|
270
|
+
TAU: TANGENT_TAU,
|
|
271
|
+
PI: TANGENT_PI,
|
|
272
|
+
NULL_TANGENT_UNORM,
|
|
273
|
+
isNull: isNullTangent,
|
|
274
|
+
isNullTangent,
|
|
275
|
+
decode: decodeTangentFrame,
|
|
276
|
+
decodeTangentFrame,
|
|
277
|
+
pack: encodeTangentFrame,
|
|
278
|
+
encode: encodeTangentFrame,
|
|
279
|
+
encodeTangentFrame,
|
|
280
|
+
packTangentFrames,
|
|
281
|
+
unpack: unpackMeshTangents,
|
|
282
|
+
unpackMeshTangents,
|
|
283
|
+
isPacked,
|
|
284
|
+
generateNormals,
|
|
285
|
+
generateTangents,
|
|
286
|
+
generateTangentFrames,
|
|
287
|
+
generateBiNormals
|
|
288
|
+
});
|
package/src/text.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { asUint8Array } from "./bytes.js";
|
|
2
|
+
|
|
3
|
+
/** Encodes a value as UTF-8 without importing a platform-specific module. */
|
|
4
|
+
export function encodeUtf8(value)
|
|
5
|
+
{
|
|
6
|
+
const TextEncoderClass = globalThis.TextEncoder;
|
|
7
|
+
|
|
8
|
+
if (typeof TextEncoderClass !== "function")
|
|
9
|
+
{
|
|
10
|
+
throw unsupportedTextCodec("TextEncoder");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return new TextEncoderClass().encode(String(value));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Decodes supported byte input as UTF-8. */
|
|
17
|
+
export function decodeUtf8(value, options = {})
|
|
18
|
+
{
|
|
19
|
+
const TextDecoderClass = globalThis.TextDecoder;
|
|
20
|
+
|
|
21
|
+
if (typeof TextDecoderClass !== "function")
|
|
22
|
+
{
|
|
23
|
+
throw unsupportedTextCodec("TextDecoder");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const decoder = new TextDecoderClass("utf-8", {
|
|
27
|
+
fatal: Boolean(options.fatal),
|
|
28
|
+
ignoreBOM: Boolean(options.ignoreBOM)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return decoder.decode(asUint8Array(value, "UTF-8 input"));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function unsupportedTextCodec(name)
|
|
35
|
+
{
|
|
36
|
+
const error = new Error(`${name} is unavailable in this environment.`);
|
|
37
|
+
|
|
38
|
+
error.code = "CJS_TEXT_CODEC_UNSUPPORTED";
|
|
39
|
+
return error;
|
|
40
|
+
}
|