@babylonjs/loaders 9.11.0 → 9.12.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.
- package/FBX/fbxFileLoader.d.ts +194 -0
- package/FBX/fbxFileLoader.js +2440 -0
- package/FBX/fbxFileLoader.js.map +1 -0
- package/FBX/fbxFileLoader.metadata.d.ts +11 -0
- package/FBX/fbxFileLoader.metadata.js +11 -0
- package/FBX/fbxFileLoader.metadata.js.map +1 -0
- package/FBX/index.d.ts +3 -0
- package/FBX/index.js +3 -0
- package/FBX/index.js.map +1 -0
- package/FBX/interpreter/animation.d.ts +122 -0
- package/FBX/interpreter/animation.js +648 -0
- package/FBX/interpreter/animation.js.map +1 -0
- package/FBX/interpreter/blendShapes.d.ts +44 -0
- package/FBX/interpreter/blendShapes.js +192 -0
- package/FBX/interpreter/blendShapes.js.map +1 -0
- package/FBX/interpreter/connections.d.ts +95 -0
- package/FBX/interpreter/connections.js +233 -0
- package/FBX/interpreter/connections.js.map +1 -0
- package/FBX/interpreter/fbxInterpreter.d.ts +149 -0
- package/FBX/interpreter/fbxInterpreter.js +496 -0
- package/FBX/interpreter/fbxInterpreter.js.map +1 -0
- package/FBX/interpreter/geometry.d.ts +55 -0
- package/FBX/interpreter/geometry.js +573 -0
- package/FBX/interpreter/geometry.js.map +1 -0
- package/FBX/interpreter/materials.d.ts +50 -0
- package/FBX/interpreter/materials.js +144 -0
- package/FBX/interpreter/materials.js.map +1 -0
- package/FBX/interpreter/propertyTemplates.d.ts +22 -0
- package/FBX/interpreter/propertyTemplates.js +125 -0
- package/FBX/interpreter/propertyTemplates.js.map +1 -0
- package/FBX/interpreter/rig.d.ts +20 -0
- package/FBX/interpreter/rig.js +259 -0
- package/FBX/interpreter/rig.js.map +1 -0
- package/FBX/interpreter/sceneDiagnostics.d.ts +14 -0
- package/FBX/interpreter/sceneDiagnostics.js +55 -0
- package/FBX/interpreter/sceneDiagnostics.js.map +1 -0
- package/FBX/interpreter/skeleton.d.ts +93 -0
- package/FBX/interpreter/skeleton.js +515 -0
- package/FBX/interpreter/skeleton.js.map +1 -0
- package/FBX/interpreter/transform.d.ts +21 -0
- package/FBX/interpreter/transform.js +92 -0
- package/FBX/interpreter/transform.js.map +1 -0
- package/FBX/parsers/fbxAsciiParser.d.ts +5 -0
- package/FBX/parsers/fbxAsciiParser.js +330 -0
- package/FBX/parsers/fbxAsciiParser.js.map +1 -0
- package/FBX/parsers/fbxBinaryParser.d.ts +6 -0
- package/FBX/parsers/fbxBinaryParser.js +255 -0
- package/FBX/parsers/fbxBinaryParser.js.map +1 -0
- package/FBX/parsers/zlibInflate.d.ts +7 -0
- package/FBX/parsers/zlibInflate.js +350 -0
- package/FBX/parsers/zlibInflate.js.map +1 -0
- package/FBX/types/fbxTypes.d.ts +54 -0
- package/FBX/types/fbxTypes.js +66 -0
- package/FBX/types/fbxTypes.js.map +1 -0
- package/SPLAT/gaussianSplattingStream.d.ts +341 -0
- package/SPLAT/gaussianSplattingStream.js +976 -0
- package/SPLAT/gaussianSplattingStream.js.map +1 -0
- package/SPLAT/gaussianSplattingWorkBuffer.d.ts +51 -0
- package/SPLAT/gaussianSplattingWorkBuffer.js +159 -0
- package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -0
- package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +25 -0
- package/SPLAT/gaussianSplattingWorkBufferShaders.js +255 -0
- package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -0
- package/SPLAT/index.d.ts +1 -0
- package/SPLAT/index.js +1 -0
- package/SPLAT/index.js.map +1 -1
- package/SPLAT/sog.js +18 -16
- package/SPLAT/sog.js.map +1 -1
- package/SPLAT/splatFileLoader.d.ts +8 -0
- package/SPLAT/splatFileLoader.js +49 -0
- package/SPLAT/splatFileLoader.js.map +1 -1
- package/dynamic.js +9 -0
- package/dynamic.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */
|
|
2
|
+
import { Matrix } from "@babylonjs/core/Maths/math.vector.js";
|
|
3
|
+
export function eulerToMatrixXYZ(rx, ry, rz) {
|
|
4
|
+
const mx = Matrix.RotationX(rx);
|
|
5
|
+
const my = Matrix.RotationY(ry);
|
|
6
|
+
const mz = Matrix.RotationZ(rz);
|
|
7
|
+
return mx.multiply(my).multiply(mz);
|
|
8
|
+
}
|
|
9
|
+
export function eulerToMatrix(rx, ry, rz, order) {
|
|
10
|
+
const mx = Matrix.RotationX(rx);
|
|
11
|
+
const my = Matrix.RotationY(ry);
|
|
12
|
+
const mz = Matrix.RotationZ(rz);
|
|
13
|
+
switch (order) {
|
|
14
|
+
case 0:
|
|
15
|
+
return mx.multiply(my).multiply(mz); // XYZ
|
|
16
|
+
case 1:
|
|
17
|
+
return mx.multiply(mz).multiply(my); // XZY
|
|
18
|
+
case 2:
|
|
19
|
+
return my.multiply(mz).multiply(mx); // YZX
|
|
20
|
+
case 3:
|
|
21
|
+
return my.multiply(mx).multiply(mz); // YXZ
|
|
22
|
+
case 4:
|
|
23
|
+
return mz.multiply(mx).multiply(my); // ZXY
|
|
24
|
+
case 5:
|
|
25
|
+
return mz.multiply(my).multiply(mx); // ZYX
|
|
26
|
+
default:
|
|
27
|
+
return mx.multiply(my).multiply(mz); // fallback to XYZ
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function computeFBXGeometricMatrix(translation, rotation, scale) {
|
|
31
|
+
const translationM = Matrix.Translation(translation[0], translation[1], translation[2]);
|
|
32
|
+
return computeFBXGeometricDeltaMatrix(rotation, scale).multiply(translationM);
|
|
33
|
+
}
|
|
34
|
+
export function computeFBXGeometricDeltaMatrix(rotation, scale) {
|
|
35
|
+
const d2r = Math.PI / 180;
|
|
36
|
+
const scaleM = Matrix.Scaling(scale[0], scale[1], scale[2]);
|
|
37
|
+
const rotationM = eulerToMatrixXYZ(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r);
|
|
38
|
+
return scaleM.multiply(rotationM);
|
|
39
|
+
}
|
|
40
|
+
export function computeFBXGeometricNormalMatrix(rotation, scale) {
|
|
41
|
+
const d2r = Math.PI / 180;
|
|
42
|
+
const inverseScaleM = Matrix.Scaling(scale[0] === 0 ? 0 : 1 / scale[0], scale[1] === 0 ? 0 : 1 / scale[1], scale[2] === 0 ? 0 : 1 / scale[2]);
|
|
43
|
+
const rotationM = eulerToMatrixXYZ(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r);
|
|
44
|
+
return inverseScaleM.multiply(rotationM);
|
|
45
|
+
}
|
|
46
|
+
export function computeFBXLocalMatrix(components) {
|
|
47
|
+
const { translation, rotation, scale, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, rotationOrder } = components;
|
|
48
|
+
const d2r = Math.PI / 180;
|
|
49
|
+
const hasPivots = rotationPivot[0] !== 0 || rotationPivot[1] !== 0 || rotationPivot[2] !== 0 || scalingPivot[0] !== 0 || scalingPivot[1] !== 0 || scalingPivot[2] !== 0;
|
|
50
|
+
const hasOffsets = rotationOffset[0] !== 0 || rotationOffset[1] !== 0 || rotationOffset[2] !== 0 || scalingOffset[0] !== 0 || scalingOffset[1] !== 0 || scalingOffset[2] !== 0;
|
|
51
|
+
const hasPostRot = postRotation[0] !== 0 || postRotation[1] !== 0 || postRotation[2] !== 0;
|
|
52
|
+
if (!hasPivots && !hasOffsets && !hasPostRot) {
|
|
53
|
+
const preRotM = eulerToMatrixXYZ(preRotation[0] * d2r, preRotation[1] * d2r, preRotation[2] * d2r);
|
|
54
|
+
const lclRotM = eulerToMatrix(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r, rotationOrder);
|
|
55
|
+
const translationM = Matrix.Translation(translation[0], translation[1], translation[2]);
|
|
56
|
+
const rotationM = lclRotM.multiply(preRotM);
|
|
57
|
+
const scaleM = Matrix.Scaling(scale[0], scale[1], scale[2]);
|
|
58
|
+
return scaleM.multiply(rotationM).multiply(translationM);
|
|
59
|
+
}
|
|
60
|
+
const T = Matrix.Translation(translation[0], translation[1], translation[2]);
|
|
61
|
+
const Roff = Matrix.Translation(rotationOffset[0], rotationOffset[1], rotationOffset[2]);
|
|
62
|
+
const Rp = Matrix.Translation(rotationPivot[0], rotationPivot[1], rotationPivot[2]);
|
|
63
|
+
const RpInv = Matrix.Translation(-rotationPivot[0], -rotationPivot[1], -rotationPivot[2]);
|
|
64
|
+
const Soff = Matrix.Translation(scalingOffset[0], scalingOffset[1], scalingOffset[2]);
|
|
65
|
+
const Sp = Matrix.Translation(scalingPivot[0], scalingPivot[1], scalingPivot[2]);
|
|
66
|
+
const SpInv = Matrix.Translation(-scalingPivot[0], -scalingPivot[1], -scalingPivot[2]);
|
|
67
|
+
const Rpre = eulerToMatrixXYZ(preRotation[0] * d2r, preRotation[1] * d2r, preRotation[2] * d2r);
|
|
68
|
+
const R = eulerToMatrix(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r, rotationOrder);
|
|
69
|
+
const S = Matrix.Scaling(scale[0], scale[1], scale[2]);
|
|
70
|
+
let RpostInv;
|
|
71
|
+
if (hasPostRot) {
|
|
72
|
+
const Rpost = eulerToMatrixXYZ(postRotation[0] * d2r, postRotation[1] * d2r, postRotation[2] * d2r);
|
|
73
|
+
RpostInv = new Matrix();
|
|
74
|
+
Rpost.invertToRef(RpostInv);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
RpostInv = Matrix.Identity();
|
|
78
|
+
}
|
|
79
|
+
let result = SpInv;
|
|
80
|
+
result = result.multiply(S);
|
|
81
|
+
result = result.multiply(Sp);
|
|
82
|
+
result = result.multiply(Soff);
|
|
83
|
+
result = result.multiply(RpInv);
|
|
84
|
+
result = result.multiply(RpostInv);
|
|
85
|
+
result = result.multiply(R);
|
|
86
|
+
result = result.multiply(Rpre);
|
|
87
|
+
result = result.multiply(Rp);
|
|
88
|
+
result = result.multiply(Roff);
|
|
89
|
+
result = result.multiply(T);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/interpreter/transform.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\r\nimport { Matrix } from \"core/Maths/math.vector\";\r\n\r\nexport type FBXVector3 = [number, number, number];\r\n\r\nexport interface FBXTransformComponents {\r\n translation: FBXVector3;\r\n rotation: FBXVector3;\r\n scale: FBXVector3;\r\n preRotation: FBXVector3;\r\n postRotation: FBXVector3;\r\n rotationPivot: FBXVector3;\r\n scalingPivot: FBXVector3;\r\n rotationOffset: FBXVector3;\r\n scalingOffset: FBXVector3;\r\n rotationOrder: number;\r\n inheritType?: number;\r\n}\r\n\r\nexport function eulerToMatrixXYZ(rx: number, ry: number, rz: number): Matrix {\r\n const mx = Matrix.RotationX(rx);\r\n const my = Matrix.RotationY(ry);\r\n const mz = Matrix.RotationZ(rz);\r\n return mx.multiply(my).multiply(mz);\r\n}\r\n\r\nexport function eulerToMatrix(rx: number, ry: number, rz: number, order: number): Matrix {\r\n const mx = Matrix.RotationX(rx);\r\n const my = Matrix.RotationY(ry);\r\n const mz = Matrix.RotationZ(rz);\r\n\r\n switch (order) {\r\n case 0:\r\n return mx.multiply(my).multiply(mz); // XYZ\r\n case 1:\r\n return mx.multiply(mz).multiply(my); // XZY\r\n case 2:\r\n return my.multiply(mz).multiply(mx); // YZX\r\n case 3:\r\n return my.multiply(mx).multiply(mz); // YXZ\r\n case 4:\r\n return mz.multiply(mx).multiply(my); // ZXY\r\n case 5:\r\n return mz.multiply(my).multiply(mx); // ZYX\r\n default:\r\n return mx.multiply(my).multiply(mz); // fallback to XYZ\r\n }\r\n}\r\n\r\nexport function computeFBXGeometricMatrix(translation: FBXVector3, rotation: FBXVector3, scale: FBXVector3): Matrix {\r\n const translationM = Matrix.Translation(translation[0], translation[1], translation[2]);\r\n return computeFBXGeometricDeltaMatrix(rotation, scale).multiply(translationM);\r\n}\r\n\r\nexport function computeFBXGeometricDeltaMatrix(rotation: FBXVector3, scale: FBXVector3): Matrix {\r\n const d2r = Math.PI / 180;\r\n const scaleM = Matrix.Scaling(scale[0], scale[1], scale[2]);\r\n const rotationM = eulerToMatrixXYZ(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r);\r\n return scaleM.multiply(rotationM);\r\n}\r\n\r\nexport function computeFBXGeometricNormalMatrix(rotation: FBXVector3, scale: FBXVector3): Matrix {\r\n const d2r = Math.PI / 180;\r\n const inverseScaleM = Matrix.Scaling(scale[0] === 0 ? 0 : 1 / scale[0], scale[1] === 0 ? 0 : 1 / scale[1], scale[2] === 0 ? 0 : 1 / scale[2]);\r\n const rotationM = eulerToMatrixXYZ(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r);\r\n return inverseScaleM.multiply(rotationM);\r\n}\r\n\r\nexport function computeFBXLocalMatrix(components: FBXTransformComponents): Matrix {\r\n const { translation, rotation, scale, preRotation, postRotation, rotationPivot, scalingPivot, rotationOffset, scalingOffset, rotationOrder } = components;\r\n const d2r = Math.PI / 180;\r\n\r\n const hasPivots = rotationPivot[0] !== 0 || rotationPivot[1] !== 0 || rotationPivot[2] !== 0 || scalingPivot[0] !== 0 || scalingPivot[1] !== 0 || scalingPivot[2] !== 0;\r\n const hasOffsets = rotationOffset[0] !== 0 || rotationOffset[1] !== 0 || rotationOffset[2] !== 0 || scalingOffset[0] !== 0 || scalingOffset[1] !== 0 || scalingOffset[2] !== 0;\r\n const hasPostRot = postRotation[0] !== 0 || postRotation[1] !== 0 || postRotation[2] !== 0;\r\n\r\n if (!hasPivots && !hasOffsets && !hasPostRot) {\r\n const preRotM = eulerToMatrixXYZ(preRotation[0] * d2r, preRotation[1] * d2r, preRotation[2] * d2r);\r\n const lclRotM = eulerToMatrix(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r, rotationOrder);\r\n const translationM = Matrix.Translation(translation[0], translation[1], translation[2]);\r\n const rotationM = lclRotM.multiply(preRotM);\r\n const scaleM = Matrix.Scaling(scale[0], scale[1], scale[2]);\r\n return scaleM.multiply(rotationM).multiply(translationM);\r\n }\r\n\r\n const T = Matrix.Translation(translation[0], translation[1], translation[2]);\r\n const Roff = Matrix.Translation(rotationOffset[0], rotationOffset[1], rotationOffset[2]);\r\n const Rp = Matrix.Translation(rotationPivot[0], rotationPivot[1], rotationPivot[2]);\r\n const RpInv = Matrix.Translation(-rotationPivot[0], -rotationPivot[1], -rotationPivot[2]);\r\n const Soff = Matrix.Translation(scalingOffset[0], scalingOffset[1], scalingOffset[2]);\r\n const Sp = Matrix.Translation(scalingPivot[0], scalingPivot[1], scalingPivot[2]);\r\n const SpInv = Matrix.Translation(-scalingPivot[0], -scalingPivot[1], -scalingPivot[2]);\r\n\r\n const Rpre = eulerToMatrixXYZ(preRotation[0] * d2r, preRotation[1] * d2r, preRotation[2] * d2r);\r\n const R = eulerToMatrix(rotation[0] * d2r, rotation[1] * d2r, rotation[2] * d2r, rotationOrder);\r\n const S = Matrix.Scaling(scale[0], scale[1], scale[2]);\r\n\r\n let RpostInv: Matrix;\r\n if (hasPostRot) {\r\n const Rpost = eulerToMatrixXYZ(postRotation[0] * d2r, postRotation[1] * d2r, postRotation[2] * d2r);\r\n RpostInv = new Matrix();\r\n Rpost.invertToRef(RpostInv);\r\n } else {\r\n RpostInv = Matrix.Identity();\r\n }\r\n\r\n let result = SpInv;\r\n result = result.multiply(S);\r\n result = result.multiply(Sp);\r\n result = result.multiply(Soff);\r\n result = result.multiply(RpInv);\r\n result = result.multiply(RpostInv);\r\n result = result.multiply(R);\r\n result = result.multiply(Rpre);\r\n result = result.multiply(Rp);\r\n result = result.multiply(Roff);\r\n result = result.multiply(T);\r\n return result;\r\n}\r\n"]}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse an ASCII FBX file into an FBXDocument.
|
|
3
|
+
*/
|
|
4
|
+
export function parseAsciiFBX(text) {
|
|
5
|
+
const tokenizer = new Tokenizer(text);
|
|
6
|
+
const version = parseVersion(text);
|
|
7
|
+
const nodes = [];
|
|
8
|
+
while (!tokenizer.isEOF()) {
|
|
9
|
+
tokenizer.skipWhitespaceAndComments();
|
|
10
|
+
if (tokenizer.isEOF()) {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
const node = parseNodeFromTokens(tokenizer);
|
|
14
|
+
if (node) {
|
|
15
|
+
nodes.push(node);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { version, nodes };
|
|
19
|
+
}
|
|
20
|
+
/** Extract FBX version from the header comment (e.g. "; FBX 7.7.0 project file") */
|
|
21
|
+
function parseVersion(text) {
|
|
22
|
+
const match = text.match(/;\s*FBX\s+(\d+)\.(\d+)\.(\d+)/);
|
|
23
|
+
if (!match) {
|
|
24
|
+
throw new Error("Cannot determine FBX version from ASCII header");
|
|
25
|
+
}
|
|
26
|
+
return parseInt(match[1]) * 1000 + parseInt(match[2]) * 100 + parseInt(match[3]);
|
|
27
|
+
}
|
|
28
|
+
// ── Tokenizer ──────────────────────────────────────────────────────────────────
|
|
29
|
+
var TokenType;
|
|
30
|
+
(function (TokenType) {
|
|
31
|
+
TokenType[TokenType["Identifier"] = 0] = "Identifier";
|
|
32
|
+
TokenType[TokenType["Number"] = 1] = "Number";
|
|
33
|
+
TokenType[TokenType["String"] = 2] = "String";
|
|
34
|
+
TokenType[TokenType["OpenBrace"] = 3] = "OpenBrace";
|
|
35
|
+
TokenType[TokenType["CloseBrace"] = 4] = "CloseBrace";
|
|
36
|
+
TokenType[TokenType["Colon"] = 5] = "Colon";
|
|
37
|
+
TokenType[TokenType["Comma"] = 6] = "Comma";
|
|
38
|
+
TokenType[TokenType["Star"] = 7] = "Star";
|
|
39
|
+
TokenType[TokenType["EOF"] = 8] = "EOF";
|
|
40
|
+
})(TokenType || (TokenType = {}));
|
|
41
|
+
class Tokenizer {
|
|
42
|
+
constructor(text) {
|
|
43
|
+
this.text = text;
|
|
44
|
+
this.pos = 0;
|
|
45
|
+
this.len = text.length;
|
|
46
|
+
}
|
|
47
|
+
isEOF() {
|
|
48
|
+
this.skipWhitespaceAndComments();
|
|
49
|
+
return this.pos >= this.len;
|
|
50
|
+
}
|
|
51
|
+
peek() {
|
|
52
|
+
const saved = this.pos;
|
|
53
|
+
const tok = this.next();
|
|
54
|
+
this.pos = saved;
|
|
55
|
+
return tok;
|
|
56
|
+
}
|
|
57
|
+
next() {
|
|
58
|
+
this.skipWhitespaceAndComments();
|
|
59
|
+
if (this.pos >= this.len) {
|
|
60
|
+
return { type: 8 /* TokenType.EOF */, value: "", pos: this.pos };
|
|
61
|
+
}
|
|
62
|
+
const ch = this.text[this.pos];
|
|
63
|
+
const startPos = this.pos;
|
|
64
|
+
switch (ch) {
|
|
65
|
+
case "{":
|
|
66
|
+
this.pos++;
|
|
67
|
+
return { type: 3 /* TokenType.OpenBrace */, value: "{", pos: startPos };
|
|
68
|
+
case "}":
|
|
69
|
+
this.pos++;
|
|
70
|
+
return { type: 4 /* TokenType.CloseBrace */, value: "}", pos: startPos };
|
|
71
|
+
case ":":
|
|
72
|
+
this.pos++;
|
|
73
|
+
return { type: 5 /* TokenType.Colon */, value: ":", pos: startPos };
|
|
74
|
+
case ",":
|
|
75
|
+
this.pos++;
|
|
76
|
+
return { type: 6 /* TokenType.Comma */, value: ",", pos: startPos };
|
|
77
|
+
case "*":
|
|
78
|
+
this.pos++;
|
|
79
|
+
return { type: 7 /* TokenType.Star */, value: "*", pos: startPos };
|
|
80
|
+
case '"':
|
|
81
|
+
return this.readString();
|
|
82
|
+
default:
|
|
83
|
+
if (this.isNumberStart(ch)) {
|
|
84
|
+
return this.readNumber();
|
|
85
|
+
}
|
|
86
|
+
if (this.isIdentStart(ch)) {
|
|
87
|
+
return this.readIdentifier();
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Unexpected character '${ch}' at position ${this.pos}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
expect(type) {
|
|
93
|
+
const tok = this.next();
|
|
94
|
+
if (tok.type !== type) {
|
|
95
|
+
throw new Error(`Expected token type ${type} but got ${tok.type} ('${tok.value}') at pos ${tok.pos}`);
|
|
96
|
+
}
|
|
97
|
+
return tok;
|
|
98
|
+
}
|
|
99
|
+
/** Look ahead to see if the next identifier + colon is a child node start */
|
|
100
|
+
isNextNodeStart() {
|
|
101
|
+
const saved = this.pos;
|
|
102
|
+
this.skipWhitespaceAndComments();
|
|
103
|
+
// Read the identifier
|
|
104
|
+
if (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {
|
|
105
|
+
while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {
|
|
106
|
+
this.pos++;
|
|
107
|
+
}
|
|
108
|
+
// Skip whitespace between identifier and potential colon
|
|
109
|
+
while (this.pos < this.len && (this.text[this.pos] === " " || this.text[this.pos] === "\t")) {
|
|
110
|
+
this.pos++;
|
|
111
|
+
}
|
|
112
|
+
const isNode = this.pos < this.len && this.text[this.pos] === ":";
|
|
113
|
+
this.pos = saved;
|
|
114
|
+
return isNode;
|
|
115
|
+
}
|
|
116
|
+
this.pos = saved;
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
skipWhitespaceAndComments() {
|
|
120
|
+
while (this.pos < this.len) {
|
|
121
|
+
const ch = this.text[this.pos];
|
|
122
|
+
if (ch === " " || ch === "\t" || ch === "\r" || ch === "\n") {
|
|
123
|
+
this.pos++;
|
|
124
|
+
}
|
|
125
|
+
else if (ch === ";") {
|
|
126
|
+
// Skip comment to end of line
|
|
127
|
+
while (this.pos < this.len && this.text[this.pos] !== "\n") {
|
|
128
|
+
this.pos++;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
readString() {
|
|
137
|
+
const startPos = this.pos;
|
|
138
|
+
this.pos++; // skip opening quote
|
|
139
|
+
let value = "";
|
|
140
|
+
while (this.pos < this.len && this.text[this.pos] !== '"') {
|
|
141
|
+
if (this.text[this.pos] === "\\" && this.pos + 1 < this.len) {
|
|
142
|
+
this.pos++;
|
|
143
|
+
value += this.text[this.pos];
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
value += this.text[this.pos];
|
|
147
|
+
}
|
|
148
|
+
this.pos++;
|
|
149
|
+
}
|
|
150
|
+
if (this.pos < this.len) {
|
|
151
|
+
this.pos++; // skip closing quote
|
|
152
|
+
}
|
|
153
|
+
return { type: 2 /* TokenType.String */, value, pos: startPos };
|
|
154
|
+
}
|
|
155
|
+
readNumber() {
|
|
156
|
+
const startPos = this.pos;
|
|
157
|
+
// Handle leading sign
|
|
158
|
+
if (this.text[this.pos] === "-" || this.text[this.pos] === "+") {
|
|
159
|
+
this.pos++;
|
|
160
|
+
}
|
|
161
|
+
while (this.pos < this.len && this.isDigit(this.text[this.pos])) {
|
|
162
|
+
this.pos++;
|
|
163
|
+
}
|
|
164
|
+
if (this.pos < this.len && this.text[this.pos] === ".") {
|
|
165
|
+
this.pos++;
|
|
166
|
+
while (this.pos < this.len && this.isDigit(this.text[this.pos])) {
|
|
167
|
+
this.pos++;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Scientific notation
|
|
171
|
+
if (this.pos < this.len && (this.text[this.pos] === "e" || this.text[this.pos] === "E")) {
|
|
172
|
+
this.pos++;
|
|
173
|
+
if (this.pos < this.len && (this.text[this.pos] === "+" || this.text[this.pos] === "-")) {
|
|
174
|
+
this.pos++;
|
|
175
|
+
}
|
|
176
|
+
while (this.pos < this.len && this.isDigit(this.text[this.pos])) {
|
|
177
|
+
this.pos++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { type: 1 /* TokenType.Number */, value: this.text.substring(startPos, this.pos), pos: startPos };
|
|
181
|
+
}
|
|
182
|
+
readIdentifier() {
|
|
183
|
+
const startPos = this.pos;
|
|
184
|
+
while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {
|
|
185
|
+
this.pos++;
|
|
186
|
+
}
|
|
187
|
+
return { type: 0 /* TokenType.Identifier */, value: this.text.substring(startPos, this.pos), pos: startPos };
|
|
188
|
+
}
|
|
189
|
+
isDigit(ch) {
|
|
190
|
+
return ch >= "0" && ch <= "9";
|
|
191
|
+
}
|
|
192
|
+
isNumberStart(ch) {
|
|
193
|
+
if (this.isDigit(ch)) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if ((ch === "-" || ch === "+") && this.pos + 1 < this.len) {
|
|
197
|
+
return this.isDigit(this.text[this.pos + 1]) || this.text[this.pos + 1] === ".";
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
isIdentStart(ch) {
|
|
202
|
+
return (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") || ch === "_";
|
|
203
|
+
}
|
|
204
|
+
isIdentChar(ch) {
|
|
205
|
+
return this.isIdentStart(ch) || this.isDigit(ch) || ch === "|";
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// ── Node Parsing ───────────────────────────────────────────────────────────────
|
|
209
|
+
function parseNodeFromTokens(tokenizer) {
|
|
210
|
+
const nameTok = tokenizer.peek();
|
|
211
|
+
if (nameTok.type === 4 /* TokenType.CloseBrace */ || nameTok.type === 8 /* TokenType.EOF */) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
// Node name
|
|
215
|
+
const identTok = tokenizer.next();
|
|
216
|
+
if (identTok.type !== 0 /* TokenType.Identifier */) {
|
|
217
|
+
throw new Error(`Expected identifier for node name, got '${identTok.value}' at pos ${identTok.pos}`);
|
|
218
|
+
}
|
|
219
|
+
const name = identTok.value;
|
|
220
|
+
tokenizer.expect(5 /* TokenType.Colon */);
|
|
221
|
+
// Parse properties until we hit '{' or end-of-line content
|
|
222
|
+
const properties = [];
|
|
223
|
+
const children = [];
|
|
224
|
+
// Check for array shorthand: *count { a: ... }
|
|
225
|
+
let peek = tokenizer.peek();
|
|
226
|
+
if (peek.type === 7 /* TokenType.Star */) {
|
|
227
|
+
// Array node like "Vertices: *25959 {"
|
|
228
|
+
tokenizer.next(); // consume *
|
|
229
|
+
const countTok = tokenizer.expect(1 /* TokenType.Number */);
|
|
230
|
+
const count = parseInt(countTok.value);
|
|
231
|
+
tokenizer.expect(3 /* TokenType.OpenBrace */);
|
|
232
|
+
// Expect "a:" followed by comma-separated values
|
|
233
|
+
const aTok = tokenizer.next();
|
|
234
|
+
if (aTok.type === 0 /* TokenType.Identifier */ && aTok.value === "a") {
|
|
235
|
+
tokenizer.expect(5 /* TokenType.Colon */);
|
|
236
|
+
const values = parseArrayValues(tokenizer, count);
|
|
237
|
+
properties.push({ type: "float64[]", value: new Float64Array(values) });
|
|
238
|
+
}
|
|
239
|
+
tokenizer.expect(4 /* TokenType.CloseBrace */);
|
|
240
|
+
return { name, properties, children };
|
|
241
|
+
}
|
|
242
|
+
// Parse inline properties (comma-separated values on the same logical line)
|
|
243
|
+
// Values can be: numbers, strings, or bare identifiers (e.g. "T", "Y", "CullingOff")
|
|
244
|
+
peek = tokenizer.peek();
|
|
245
|
+
while (peek.type !== 3 /* TokenType.OpenBrace */ && peek.type !== 4 /* TokenType.CloseBrace */ && peek.type !== 8 /* TokenType.EOF */) {
|
|
246
|
+
if (peek.type === 1 /* TokenType.Number */) {
|
|
247
|
+
const tok = tokenizer.next();
|
|
248
|
+
const numVal = parseNumericValue(tok.value);
|
|
249
|
+
if (Number.isInteger(numVal) && !tok.value.includes(".") && !tok.value.includes("e") && !tok.value.includes("E")) {
|
|
250
|
+
properties.push({ type: isInt32(numVal) ? "int32" : "int64", value: numVal });
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
properties.push({ type: "float64", value: numVal });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else if (peek.type === 2 /* TokenType.String */) {
|
|
257
|
+
const tok = tokenizer.next();
|
|
258
|
+
properties.push({ type: "string", value: tok.value });
|
|
259
|
+
}
|
|
260
|
+
else if (peek.type === 0 /* TokenType.Identifier */) {
|
|
261
|
+
// Check if this is a property value or the start of a new child node.
|
|
262
|
+
// If the next non-whitespace after the identifier is ':', it's a child node name — stop.
|
|
263
|
+
if (tokenizer.isNextNodeStart()) {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
// Bare identifier as a property value (e.g. "T", "Y", "CullingOff")
|
|
267
|
+
const tok = tokenizer.next();
|
|
268
|
+
properties.push({ type: "string", value: tok.value });
|
|
269
|
+
}
|
|
270
|
+
else if (peek.type === 6 /* TokenType.Comma */) {
|
|
271
|
+
tokenizer.next(); // consume comma
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
peek = tokenizer.peek();
|
|
277
|
+
}
|
|
278
|
+
// Check for block body { ... }
|
|
279
|
+
peek = tokenizer.peek();
|
|
280
|
+
if (peek.type === 3 /* TokenType.OpenBrace */) {
|
|
281
|
+
tokenizer.next(); // consume '{'
|
|
282
|
+
// Parse child nodes
|
|
283
|
+
while (true) {
|
|
284
|
+
peek = tokenizer.peek();
|
|
285
|
+
if (peek.type === 4 /* TokenType.CloseBrace */ || peek.type === 8 /* TokenType.EOF */) {
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
const child = parseNodeFromTokens(tokenizer);
|
|
289
|
+
if (child) {
|
|
290
|
+
children.push(child);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
tokenizer.expect(4 /* TokenType.CloseBrace */);
|
|
297
|
+
}
|
|
298
|
+
return { name, properties, children };
|
|
299
|
+
}
|
|
300
|
+
function parseArrayValues(tokenizer, count) {
|
|
301
|
+
const values = [];
|
|
302
|
+
while (true) {
|
|
303
|
+
const peek = tokenizer.peek();
|
|
304
|
+
if (peek.type === 4 /* TokenType.CloseBrace */ || peek.type === 8 /* TokenType.EOF */) {
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
if (peek.type === 6 /* TokenType.Comma */) {
|
|
308
|
+
tokenizer.next();
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (peek.type === 1 /* TokenType.Number */) {
|
|
312
|
+
const tok = tokenizer.next();
|
|
313
|
+
values.push(Number(tok.value));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (values.length !== count) {
|
|
320
|
+
throw new Error(`ASCII FBX array declared ${count} values but parsed ${values.length}`);
|
|
321
|
+
}
|
|
322
|
+
return values;
|
|
323
|
+
}
|
|
324
|
+
function parseNumericValue(str) {
|
|
325
|
+
return Number(str);
|
|
326
|
+
}
|
|
327
|
+
function isInt32(value) {
|
|
328
|
+
return value >= -2147483648 && value <= 2147483647;
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=fbxAsciiParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fbxAsciiParser.js","sourceRoot":"","sources":["../../../../../dev/loaders/src/FBX/parsers/fbxAsciiParser.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention, jsdoc/require-param, jsdoc/require-returns */\r\nimport { type FBXDocument, type FBXNode, type FBXProperty } from \"../types/fbxTypes\";\r\n\r\n/**\r\n * Parse an ASCII FBX file into an FBXDocument.\r\n */\r\nexport function parseAsciiFBX(text: string): FBXDocument {\r\n const tokenizer = new Tokenizer(text);\r\n const version = parseVersion(text);\r\n const nodes: FBXNode[] = [];\r\n\r\n while (!tokenizer.isEOF()) {\r\n tokenizer.skipWhitespaceAndComments();\r\n if (tokenizer.isEOF()) {\r\n break;\r\n }\r\n const node = parseNodeFromTokens(tokenizer);\r\n if (node) {\r\n nodes.push(node);\r\n }\r\n }\r\n\r\n return { version, nodes };\r\n}\r\n\r\n/** Extract FBX version from the header comment (e.g. \"; FBX 7.7.0 project file\") */\r\nfunction parseVersion(text: string): number {\r\n const match = text.match(/;\\s*FBX\\s+(\\d+)\\.(\\d+)\\.(\\d+)/);\r\n if (!match) {\r\n throw new Error(\"Cannot determine FBX version from ASCII header\");\r\n }\r\n return parseInt(match[1]) * 1000 + parseInt(match[2]) * 100 + parseInt(match[3]);\r\n}\r\n\r\n// ── Tokenizer ──────────────────────────────────────────────────────────────────\r\n\r\nconst enum TokenType {\r\n Identifier,\r\n Number,\r\n String,\r\n OpenBrace,\r\n CloseBrace,\r\n Colon,\r\n Comma,\r\n Star,\r\n EOF,\r\n}\r\n\r\ninterface Token {\r\n type: TokenType;\r\n value: string;\r\n pos: number;\r\n}\r\n\r\nclass Tokenizer {\r\n private pos = 0;\r\n private readonly len: number;\r\n\r\n constructor(private readonly text: string) {\r\n this.len = text.length;\r\n }\r\n\r\n isEOF(): boolean {\r\n this.skipWhitespaceAndComments();\r\n return this.pos >= this.len;\r\n }\r\n\r\n peek(): Token {\r\n const saved = this.pos;\r\n const tok = this.next();\r\n this.pos = saved;\r\n return tok;\r\n }\r\n\r\n next(): Token {\r\n this.skipWhitespaceAndComments();\r\n if (this.pos >= this.len) {\r\n return { type: TokenType.EOF, value: \"\", pos: this.pos };\r\n }\r\n\r\n const ch = this.text[this.pos];\r\n const startPos = this.pos;\r\n\r\n switch (ch) {\r\n case \"{\":\r\n this.pos++;\r\n return { type: TokenType.OpenBrace, value: \"{\", pos: startPos };\r\n case \"}\":\r\n this.pos++;\r\n return { type: TokenType.CloseBrace, value: \"}\", pos: startPos };\r\n case \":\":\r\n this.pos++;\r\n return { type: TokenType.Colon, value: \":\", pos: startPos };\r\n case \",\":\r\n this.pos++;\r\n return { type: TokenType.Comma, value: \",\", pos: startPos };\r\n case \"*\":\r\n this.pos++;\r\n return { type: TokenType.Star, value: \"*\", pos: startPos };\r\n case '\"':\r\n return this.readString();\r\n default:\r\n if (this.isNumberStart(ch)) {\r\n return this.readNumber();\r\n }\r\n if (this.isIdentStart(ch)) {\r\n return this.readIdentifier();\r\n }\r\n throw new Error(`Unexpected character '${ch}' at position ${this.pos}`);\r\n }\r\n }\r\n\r\n expect(type: TokenType): Token {\r\n const tok = this.next();\r\n if (tok.type !== type) {\r\n throw new Error(`Expected token type ${type} but got ${tok.type} ('${tok.value}') at pos ${tok.pos}`);\r\n }\r\n return tok;\r\n }\r\n\r\n /** Look ahead to see if the next identifier + colon is a child node start */\r\n isNextNodeStart(): boolean {\r\n const saved = this.pos;\r\n this.skipWhitespaceAndComments();\r\n // Read the identifier\r\n if (this.pos < this.len && this.isIdentStart(this.text[this.pos])) {\r\n while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {\r\n this.pos++;\r\n }\r\n // Skip whitespace between identifier and potential colon\r\n while (this.pos < this.len && (this.text[this.pos] === \" \" || this.text[this.pos] === \"\\t\")) {\r\n this.pos++;\r\n }\r\n const isNode = this.pos < this.len && this.text[this.pos] === \":\";\r\n this.pos = saved;\r\n return isNode;\r\n }\r\n this.pos = saved;\r\n return false;\r\n }\r\n\r\n skipWhitespaceAndComments(): void {\r\n while (this.pos < this.len) {\r\n const ch = this.text[this.pos];\r\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\r\" || ch === \"\\n\") {\r\n this.pos++;\r\n } else if (ch === \";\") {\r\n // Skip comment to end of line\r\n while (this.pos < this.len && this.text[this.pos] !== \"\\n\") {\r\n this.pos++;\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n private readString(): Token {\r\n const startPos = this.pos;\r\n this.pos++; // skip opening quote\r\n let value = \"\";\r\n while (this.pos < this.len && this.text[this.pos] !== '\"') {\r\n if (this.text[this.pos] === \"\\\\\" && this.pos + 1 < this.len) {\r\n this.pos++;\r\n value += this.text[this.pos];\r\n } else {\r\n value += this.text[this.pos];\r\n }\r\n this.pos++;\r\n }\r\n if (this.pos < this.len) {\r\n this.pos++; // skip closing quote\r\n }\r\n return { type: TokenType.String, value, pos: startPos };\r\n }\r\n\r\n private readNumber(): Token {\r\n const startPos = this.pos;\r\n // Handle leading sign\r\n if (this.text[this.pos] === \"-\" || this.text[this.pos] === \"+\") {\r\n this.pos++;\r\n }\r\n while (this.pos < this.len && this.isDigit(this.text[this.pos])) {\r\n this.pos++;\r\n }\r\n if (this.pos < this.len && this.text[this.pos] === \".\") {\r\n this.pos++;\r\n while (this.pos < this.len && this.isDigit(this.text[this.pos])) {\r\n this.pos++;\r\n }\r\n }\r\n // Scientific notation\r\n if (this.pos < this.len && (this.text[this.pos] === \"e\" || this.text[this.pos] === \"E\")) {\r\n this.pos++;\r\n if (this.pos < this.len && (this.text[this.pos] === \"+\" || this.text[this.pos] === \"-\")) {\r\n this.pos++;\r\n }\r\n while (this.pos < this.len && this.isDigit(this.text[this.pos])) {\r\n this.pos++;\r\n }\r\n }\r\n return { type: TokenType.Number, value: this.text.substring(startPos, this.pos), pos: startPos };\r\n }\r\n\r\n private readIdentifier(): Token {\r\n const startPos = this.pos;\r\n while (this.pos < this.len && this.isIdentChar(this.text[this.pos])) {\r\n this.pos++;\r\n }\r\n return { type: TokenType.Identifier, value: this.text.substring(startPos, this.pos), pos: startPos };\r\n }\r\n\r\n private isDigit(ch: string): boolean {\r\n return ch >= \"0\" && ch <= \"9\";\r\n }\r\n\r\n private isNumberStart(ch: string): boolean {\r\n if (this.isDigit(ch)) {\r\n return true;\r\n }\r\n if ((ch === \"-\" || ch === \"+\") && this.pos + 1 < this.len) {\r\n return this.isDigit(this.text[this.pos + 1]) || this.text[this.pos + 1] === \".\";\r\n }\r\n return false;\r\n }\r\n\r\n private isIdentStart(ch: string): boolean {\r\n return (ch >= \"a\" && ch <= \"z\") || (ch >= \"A\" && ch <= \"Z\") || ch === \"_\";\r\n }\r\n\r\n private isIdentChar(ch: string): boolean {\r\n return this.isIdentStart(ch) || this.isDigit(ch) || ch === \"|\";\r\n }\r\n}\r\n\r\n// ── Node Parsing ───────────────────────────────────────────────────────────────\r\n\r\nfunction parseNodeFromTokens(tokenizer: Tokenizer): FBXNode | null {\r\n const nameTok = tokenizer.peek();\r\n if (nameTok.type === TokenType.CloseBrace || nameTok.type === TokenType.EOF) {\r\n return null;\r\n }\r\n\r\n // Node name\r\n const identTok = tokenizer.next();\r\n if (identTok.type !== TokenType.Identifier) {\r\n throw new Error(`Expected identifier for node name, got '${identTok.value}' at pos ${identTok.pos}`);\r\n }\r\n const name = identTok.value;\r\n tokenizer.expect(TokenType.Colon);\r\n\r\n // Parse properties until we hit '{' or end-of-line content\r\n const properties: FBXProperty[] = [];\r\n const children: FBXNode[] = [];\r\n\r\n // Check for array shorthand: *count { a: ... }\r\n let peek = tokenizer.peek();\r\n if (peek.type === TokenType.Star) {\r\n // Array node like \"Vertices: *25959 {\"\r\n tokenizer.next(); // consume *\r\n const countTok = tokenizer.expect(TokenType.Number);\r\n const count = parseInt(countTok.value);\r\n tokenizer.expect(TokenType.OpenBrace);\r\n\r\n // Expect \"a:\" followed by comma-separated values\r\n const aTok = tokenizer.next();\r\n if (aTok.type === TokenType.Identifier && aTok.value === \"a\") {\r\n tokenizer.expect(TokenType.Colon);\r\n const values = parseArrayValues(tokenizer, count);\r\n properties.push({ type: \"float64[]\", value: new Float64Array(values) });\r\n }\r\n\r\n tokenizer.expect(TokenType.CloseBrace);\r\n return { name, properties, children };\r\n }\r\n\r\n // Parse inline properties (comma-separated values on the same logical line)\r\n // Values can be: numbers, strings, or bare identifiers (e.g. \"T\", \"Y\", \"CullingOff\")\r\n peek = tokenizer.peek();\r\n while (peek.type !== TokenType.OpenBrace && peek.type !== TokenType.CloseBrace && peek.type !== TokenType.EOF) {\r\n if (peek.type === TokenType.Number) {\r\n const tok = tokenizer.next();\r\n const numVal = parseNumericValue(tok.value);\r\n if (Number.isInteger(numVal) && !tok.value.includes(\".\") && !tok.value.includes(\"e\") && !tok.value.includes(\"E\")) {\r\n properties.push({ type: isInt32(numVal) ? \"int32\" : \"int64\", value: numVal });\r\n } else {\r\n properties.push({ type: \"float64\", value: numVal });\r\n }\r\n } else if (peek.type === TokenType.String) {\r\n const tok = tokenizer.next();\r\n properties.push({ type: \"string\", value: tok.value });\r\n } else if (peek.type === TokenType.Identifier) {\r\n // Check if this is a property value or the start of a new child node.\r\n // If the next non-whitespace after the identifier is ':', it's a child node name — stop.\r\n if (tokenizer.isNextNodeStart()) {\r\n break;\r\n }\r\n // Bare identifier as a property value (e.g. \"T\", \"Y\", \"CullingOff\")\r\n const tok = tokenizer.next();\r\n properties.push({ type: \"string\", value: tok.value });\r\n } else if (peek.type === TokenType.Comma) {\r\n tokenizer.next(); // consume comma\r\n } else {\r\n break;\r\n }\r\n peek = tokenizer.peek();\r\n }\r\n\r\n // Check for block body { ... }\r\n peek = tokenizer.peek();\r\n if (peek.type === TokenType.OpenBrace) {\r\n tokenizer.next(); // consume '{'\r\n // Parse child nodes\r\n while (true) {\r\n peek = tokenizer.peek();\r\n if (peek.type === TokenType.CloseBrace || peek.type === TokenType.EOF) {\r\n break;\r\n }\r\n const child = parseNodeFromTokens(tokenizer);\r\n if (child) {\r\n children.push(child);\r\n } else {\r\n break;\r\n }\r\n }\r\n tokenizer.expect(TokenType.CloseBrace);\r\n }\r\n\r\n return { name, properties, children };\r\n}\r\n\r\nfunction parseArrayValues(tokenizer: Tokenizer, count: number): number[] {\r\n const values: number[] = [];\r\n while (true) {\r\n const peek = tokenizer.peek();\r\n if (peek.type === TokenType.CloseBrace || peek.type === TokenType.EOF) {\r\n break;\r\n }\r\n if (peek.type === TokenType.Comma) {\r\n tokenizer.next();\r\n continue;\r\n }\r\n if (peek.type === TokenType.Number) {\r\n const tok = tokenizer.next();\r\n values.push(Number(tok.value));\r\n } else {\r\n break;\r\n }\r\n }\r\n if (values.length !== count) {\r\n throw new Error(`ASCII FBX array declared ${count} values but parsed ${values.length}`);\r\n }\r\n return values;\r\n}\r\n\r\nfunction parseNumericValue(str: string): number {\r\n return Number(str);\r\n}\r\n\r\nfunction isInt32(value: number): boolean {\r\n return value >= -2147483648 && value <= 2147483647;\r\n}\r\n"]}
|