war3-model-docs
Version:
Warcraft 3 model parser, generator, convertor and previewer
1,395 lines (1,389 loc) • 329 kB
JavaScript
/*!
war3-model v2.2.1-1
https://github.com/4eb0da/war3-model
Released under the MIT License.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var glMatrix = require('gl-matrix');
var TextureFlags;
(function (TextureFlags) {
TextureFlags[TextureFlags["WrapWidth"] = 1] = "WrapWidth";
TextureFlags[TextureFlags["WrapHeight"] = 2] = "WrapHeight";
})(TextureFlags || (TextureFlags = {}));
var FilterMode;
(function (FilterMode) {
FilterMode[FilterMode["None"] = 0] = "None";
FilterMode[FilterMode["Transparent"] = 1] = "Transparent";
FilterMode[FilterMode["Blend"] = 2] = "Blend";
FilterMode[FilterMode["Additive"] = 3] = "Additive";
FilterMode[FilterMode["AddAlpha"] = 4] = "AddAlpha";
FilterMode[FilterMode["Modulate"] = 5] = "Modulate";
FilterMode[FilterMode["Modulate2x"] = 6] = "Modulate2x";
})(FilterMode || (FilterMode = {}));
var LineType;
(function (LineType) {
LineType[LineType["DontInterp"] = 0] = "DontInterp";
LineType[LineType["Linear"] = 1] = "Linear";
LineType[LineType["Hermite"] = 2] = "Hermite";
LineType[LineType["Bezier"] = 3] = "Bezier";
})(LineType || (LineType = {}));
var LayerShading;
(function (LayerShading) {
LayerShading[LayerShading["Unshaded"] = 1] = "Unshaded";
LayerShading[LayerShading["SphereEnvMap"] = 2] = "SphereEnvMap";
LayerShading[LayerShading["TwoSided"] = 16] = "TwoSided";
LayerShading[LayerShading["Unfogged"] = 32] = "Unfogged";
LayerShading[LayerShading["NoDepthTest"] = 64] = "NoDepthTest";
LayerShading[LayerShading["NoDepthSet"] = 128] = "NoDepthSet";
})(LayerShading || (LayerShading = {}));
var MaterialRenderMode;
(function (MaterialRenderMode) {
MaterialRenderMode[MaterialRenderMode["ConstantColor"] = 1] = "ConstantColor";
MaterialRenderMode[MaterialRenderMode["SortPrimsFarZ"] = 16] = "SortPrimsFarZ";
MaterialRenderMode[MaterialRenderMode["FullResolution"] = 32] = "FullResolution";
})(MaterialRenderMode || (MaterialRenderMode = {}));
var GeosetAnimFlags;
(function (GeosetAnimFlags) {
GeosetAnimFlags[GeosetAnimFlags["DropShadow"] = 1] = "DropShadow";
GeosetAnimFlags[GeosetAnimFlags["Color"] = 2] = "Color";
})(GeosetAnimFlags || (GeosetAnimFlags = {}));
var NodeFlags;
(function (NodeFlags) {
NodeFlags[NodeFlags["DontInheritTranslation"] = 1] = "DontInheritTranslation";
NodeFlags[NodeFlags["DontInheritRotation"] = 2] = "DontInheritRotation";
NodeFlags[NodeFlags["DontInheritScaling"] = 4] = "DontInheritScaling";
NodeFlags[NodeFlags["Billboarded"] = 8] = "Billboarded";
NodeFlags[NodeFlags["BillboardedLockX"] = 16] = "BillboardedLockX";
NodeFlags[NodeFlags["BillboardedLockY"] = 32] = "BillboardedLockY";
NodeFlags[NodeFlags["BillboardedLockZ"] = 64] = "BillboardedLockZ";
NodeFlags[NodeFlags["CameraAnchored"] = 128] = "CameraAnchored";
})(NodeFlags || (NodeFlags = {}));
var NodeType;
(function (NodeType) {
NodeType[NodeType["Helper"] = 0] = "Helper";
NodeType[NodeType["Bone"] = 256] = "Bone";
NodeType[NodeType["Light"] = 512] = "Light";
NodeType[NodeType["EventObject"] = 1024] = "EventObject";
NodeType[NodeType["Attachment"] = 2048] = "Attachment";
NodeType[NodeType["ParticleEmitter"] = 4096] = "ParticleEmitter";
NodeType[NodeType["CollisionShape"] = 8192] = "CollisionShape";
NodeType[NodeType["RibbonEmitter"] = 16384] = "RibbonEmitter";
})(NodeType || (NodeType = {}));
var CollisionShapeType;
(function (CollisionShapeType) {
CollisionShapeType[CollisionShapeType["Box"] = 0] = "Box";
CollisionShapeType[CollisionShapeType["Sphere"] = 2] = "Sphere";
})(CollisionShapeType || (CollisionShapeType = {}));
var ParticleEmitterFlags;
(function (ParticleEmitterFlags) {
ParticleEmitterFlags[ParticleEmitterFlags["EmitterUsesMDL"] = 32768] = "EmitterUsesMDL";
ParticleEmitterFlags[ParticleEmitterFlags["EmitterUsesTGA"] = 65536] = "EmitterUsesTGA";
})(ParticleEmitterFlags || (ParticleEmitterFlags = {}));
var ParticleEmitter2Flags;
(function (ParticleEmitter2Flags) {
ParticleEmitter2Flags[ParticleEmitter2Flags["Unshaded"] = 32768] = "Unshaded";
ParticleEmitter2Flags[ParticleEmitter2Flags["SortPrimsFarZ"] = 65536] = "SortPrimsFarZ";
ParticleEmitter2Flags[ParticleEmitter2Flags["LineEmitter"] = 131072] = "LineEmitter";
ParticleEmitter2Flags[ParticleEmitter2Flags["Unfogged"] = 262144] = "Unfogged";
ParticleEmitter2Flags[ParticleEmitter2Flags["ModelSpace"] = 524288] = "ModelSpace";
ParticleEmitter2Flags[ParticleEmitter2Flags["XYQuad"] = 1048576] = "XYQuad";
})(ParticleEmitter2Flags || (ParticleEmitter2Flags = {}));
var ParticleEmitter2FilterMode;
(function (ParticleEmitter2FilterMode) {
ParticleEmitter2FilterMode[ParticleEmitter2FilterMode["Blend"] = 0] = "Blend";
ParticleEmitter2FilterMode[ParticleEmitter2FilterMode["Additive"] = 1] = "Additive";
ParticleEmitter2FilterMode[ParticleEmitter2FilterMode["Modulate"] = 2] = "Modulate";
ParticleEmitter2FilterMode[ParticleEmitter2FilterMode["Modulate2x"] = 3] = "Modulate2x";
ParticleEmitter2FilterMode[ParticleEmitter2FilterMode["AlphaKey"] = 4] = "AlphaKey";
})(ParticleEmitter2FilterMode || (ParticleEmitter2FilterMode = {}));
// Not actually mapped to mdx flags (0: Head, 1: Tail, 2: Both)
var ParticleEmitter2FramesFlags;
(function (ParticleEmitter2FramesFlags) {
ParticleEmitter2FramesFlags[ParticleEmitter2FramesFlags["Head"] = 1] = "Head";
ParticleEmitter2FramesFlags[ParticleEmitter2FramesFlags["Tail"] = 2] = "Tail";
})(ParticleEmitter2FramesFlags || (ParticleEmitter2FramesFlags = {}));
var LightType;
(function (LightType) {
LightType[LightType["Omnidirectional"] = 0] = "Omnidirectional";
LightType[LightType["Directional"] = 1] = "Directional";
LightType[LightType["Ambient"] = 2] = "Ambient";
})(LightType || (LightType = {}));
var ParticleEmitterPopcornFlags;
(function (ParticleEmitterPopcornFlags) {
ParticleEmitterPopcornFlags[ParticleEmitterPopcornFlags["Unshaded"] = 32768] = "Unshaded";
ParticleEmitterPopcornFlags[ParticleEmitterPopcornFlags["SortPrimsFarZ"] = 65536] = "SortPrimsFarZ";
ParticleEmitterPopcornFlags[ParticleEmitterPopcornFlags["Unfogged"] = 262144] = "Unfogged";
})(ParticleEmitterPopcornFlags || (ParticleEmitterPopcornFlags = {}));
var model = /*#__PURE__*/Object.freeze({
__proto__: null,
get TextureFlags () { return TextureFlags; },
get FilterMode () { return FilterMode; },
get LineType () { return LineType; },
get LayerShading () { return LayerShading; },
get MaterialRenderMode () { return MaterialRenderMode; },
get GeosetAnimFlags () { return GeosetAnimFlags; },
get NodeFlags () { return NodeFlags; },
get NodeType () { return NodeType; },
get CollisionShapeType () { return CollisionShapeType; },
get ParticleEmitterFlags () { return ParticleEmitterFlags; },
get ParticleEmitter2Flags () { return ParticleEmitter2Flags; },
get ParticleEmitter2FilterMode () { return ParticleEmitter2FilterMode; },
get ParticleEmitter2FramesFlags () { return ParticleEmitter2FramesFlags; },
get LightType () { return LightType; },
get ParticleEmitterPopcornFlags () { return ParticleEmitterPopcornFlags; }
});
var _a$2;
var State$1 = /** @class */ (function () {
function State(str) {
this.str = str;
this.pos = 0;
}
State.prototype.char = function () {
if (this.pos >= this.str.length) {
throwError(this, 'incorrect model data');
}
return this.str[this.pos];
};
return State;
}());
function throwError(state, str) {
if (str === void 0) { str = ''; }
throw new Error("SyntaxError, near " + state.pos + (str ? ', ' + str : ''));
}
function parseComment(state) {
if (state.char() === '/' && state.str[state.pos + 1] === '/') {
state.pos += 2;
while (state.pos < state.str.length && state.str[++state.pos] !== '\n')
;
++state.pos;
return true;
}
return false;
}
var spaceRE = /\s/i;
function parseSpace(state) {
while (state.pos < state.str.length && spaceRE.test(state.char())) {
++state.pos;
}
}
var keywordFirstCharRE = /[a-z]/i;
var keywordOtherCharRE = /[a-z0-9]/i;
function parseKeyword(state) {
if (!keywordFirstCharRE.test(state.char())) {
return null;
}
var keyword = state.char();
++state.pos;
while (keywordOtherCharRE.test(state.char())) {
keyword += state.str[state.pos++];
}
parseSpace(state);
return keyword;
}
function parseSymbol(state, symbol) {
if (state.char() === symbol) {
++state.pos;
parseSpace(state);
}
}
function strictParseSymbol(state, symbol) {
if (state.char() !== symbol) {
throwError(state, "extected " + symbol);
}
++state.pos;
parseSpace(state);
}
function parseString(state) {
if (state.char() === '"') {
var start = ++state.pos; // "
while (state.char() !== '"') {
++state.pos;
}
++state.pos; // "
var res = state.str.substring(start, state.pos - 1);
parseSpace(state);
return res;
}
return null;
}
var numberFirstCharRE = /[-0-9]/;
var numberOtherCharRE = /[-+.0-9e]/i;
function parseNumber(state) {
if (numberFirstCharRE.test(state.char())) {
var start = state.pos;
++state.pos;
while (numberOtherCharRE.test(state.char())) {
++state.pos;
}
var res = parseFloat(state.str.substring(start, state.pos));
parseSpace(state);
return res;
}
return null;
}
function parseArray(state, arr, pos) {
if (state.char() !== '{') {
return null;
}
if (!arr) {
arr = [];
pos = 0;
}
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var num = parseNumber(state);
if (num === null) {
throwError(state, 'expected number');
}
arr[pos++] = num;
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
return arr;
}
function parseArrayOrSingleItem(state, arr) {
if (state.char() !== '{') {
arr[0] = parseNumber(state);
return arr;
}
var pos = 0;
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var num = parseNumber(state);
if (num === null) {
throwError(state, 'expected number');
}
arr[pos++] = num;
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
return arr;
}
function parseObject(state) {
var prefix = null;
var obj = {};
if (state.char() !== '{') {
prefix = parseString(state);
if (prefix === null) {
prefix = parseNumber(state);
}
if (prefix === null) {
throwError(state, 'expected string or number');
}
}
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Interval') {
var array = new Uint32Array(2);
obj[keyword] = parseArray(state, array, 0);
}
else if (keyword === 'MinimumExtent' || keyword === 'MaximumExtent') {
var array = new Float32Array(3);
obj[keyword] = parseArray(state, array, 0);
}
else {
obj[keyword] = parseArray(state) || parseString(state);
if (obj[keyword] === null) {
obj[keyword] = parseNumber(state);
}
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
return [prefix, obj];
}
function parseVersion$1(state, model) {
var _a = parseObject(state); _a[0]; var obj = _a[1];
if (obj.FormatVersion) {
model.Version = obj.FormatVersion;
}
}
function parseModelInfo$1(state, model) {
var _a = parseObject(state), name = _a[0], obj = _a[1];
model.Info = obj;
model.Info.Name = name;
}
function parseSequences$1(state, model) {
parseNumber(state); // count, not used
strictParseSymbol(state, '{');
var res = [];
while (state.char() !== '}') {
parseKeyword(state); // Anim
var _a = parseObject(state), name_1 = _a[0], obj = _a[1];
obj.Name = name_1;
obj.NonLooping = 'NonLooping' in obj;
obj.MoveSpeed = obj.MoveSpeed || 0;
obj.Rarity = obj.Rarity || 0;
res.push(obj);
}
strictParseSymbol(state, '}');
model.Sequences = res;
}
function parseTextures$1(state, model) {
var res = [];
parseNumber(state); // count, not used
strictParseSymbol(state, '{');
while (state.char() !== '}') {
parseKeyword(state); // Bitmap
var _a = parseObject(state); _a[0]; var obj = _a[1];
obj.Flags = 0;
if ('WrapWidth' in obj) {
obj.Flags += TextureFlags.WrapWidth;
delete obj.WrapWidth;
}
if ('WrapHeight' in obj) {
obj.Flags += TextureFlags.WrapHeight;
delete obj.WrapHeight;
}
res.push(obj);
}
strictParseSymbol(state, '}');
model.Textures = res;
}
var AnimVectorType$2;
(function (AnimVectorType) {
AnimVectorType[AnimVectorType["INT1"] = 0] = "INT1";
AnimVectorType[AnimVectorType["FLOAT1"] = 1] = "FLOAT1";
AnimVectorType[AnimVectorType["FLOAT3"] = 2] = "FLOAT3";
AnimVectorType[AnimVectorType["FLOAT4"] = 3] = "FLOAT4";
})(AnimVectorType$2 || (AnimVectorType$2 = {}));
var animVectorSize$2 = (_a$2 = {},
_a$2[AnimVectorType$2.INT1] = 1,
_a$2[AnimVectorType$2.FLOAT1] = 1,
_a$2[AnimVectorType$2.FLOAT3] = 3,
_a$2[AnimVectorType$2.FLOAT4] = 4,
_a$2);
function parseAnimKeyframe(state, frame, type, lineType) {
var res = {
Frame: frame,
Vector: null
};
var Vector = type === AnimVectorType$2.INT1 ? Int32Array : Float32Array;
var itemCount = animVectorSize$2[type];
res.Vector = parseArrayOrSingleItem(state, new Vector(itemCount));
strictParseSymbol(state, ',');
if (lineType === LineType.Hermite || lineType === LineType.Bezier) {
parseKeyword(state); // InTan
res.InTan = parseArrayOrSingleItem(state, new Vector(itemCount));
strictParseSymbol(state, ',');
parseKeyword(state); // OutTan
res.OutTan = parseArrayOrSingleItem(state, new Vector(itemCount));
strictParseSymbol(state, ',');
}
return res;
}
function parseAnimVector(state, type) {
var animVector = {
LineType: LineType.DontInterp,
GlobalSeqId: null,
Keys: []
};
parseNumber(state); // count, not used
strictParseSymbol(state, '{');
var lineType = parseKeyword(state);
if (lineType === 'DontInterp' || lineType === 'Linear' || lineType === 'Hermite' || lineType === 'Bezier') {
animVector.LineType = LineType[lineType];
}
strictParseSymbol(state, ',');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (keyword === 'GlobalSeqId') {
animVector[keyword] = parseNumber(state);
strictParseSymbol(state, ',');
}
else {
var frame = parseNumber(state);
if (frame === null) {
throwError(state, 'expected frame number or GlobalSeqId');
}
strictParseSymbol(state, ':');
animVector.Keys.push(parseAnimKeyframe(state, frame, type, animVector.LineType));
}
}
strictParseSymbol(state, '}');
return animVector;
}
function parseLayer(state, model) {
var res = {
Alpha: null,
TVertexAnimId: null,
Shading: 0,
CoordId: 0
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (!isStatic && keyword === 'TextureID') {
res[keyword] = parseAnimVector(state, AnimVectorType$2.INT1);
}
else if (!isStatic && (keyword === 'Alpha')) {
res[keyword] = parseAnimVector(state, AnimVectorType$2.FLOAT1);
}
else if (keyword === 'Unshaded' || keyword === 'SphereEnvMap' || keyword === 'TwoSided' ||
keyword === 'Unfogged' || keyword === 'NoDepthTest' || keyword === 'NoDepthSet') {
res.Shading |= LayerShading[keyword];
}
else if (keyword === 'FilterMode') {
var val = parseKeyword(state);
if (val === 'None' || val === 'Transparent' || val === 'Blend' || val === 'Additive' ||
val === 'AddAlpha' || val === 'Modulate' || val === 'Modulate2x') {
res.FilterMode = FilterMode[val];
}
}
else if (keyword === 'TVertexAnimId') {
res.TVertexAnimId = parseNumber(state);
}
else if (model.Version >= 900 && keyword === 'EmissiveGain') {
if (isStatic) {
res[keyword] = parseNumber(state);
}
else {
res[keyword] = parseAnimVector(state, AnimVectorType$2.FLOAT1);
}
}
else if (model.Version >= 1000 && keyword === 'FresnelColor') {
if (isStatic) {
var array = new Float32Array(3);
res[keyword] = parseArray(state, array, 0);
}
else {
res[keyword] = parseAnimVector(state, AnimVectorType$2.FLOAT3);
}
}
else if (model.Version >= 1000 && (keyword === 'FresnelOpacity' || keyword === 'FresnelTeamColor')) {
if (isStatic) {
res[keyword] = parseNumber(state);
}
else {
res[keyword] = parseAnimVector(state, AnimVectorType$2.FLOAT1);
}
}
else {
var val = parseNumber(state);
if (val === null) {
val = parseKeyword(state);
}
res[keyword] = val;
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
return res;
}
function parseMaterials$1(state, model) {
var res = [];
parseNumber(state); // count, not used
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var obj = {
RenderMode: 0,
Layers: []
};
parseKeyword(state); // Material
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Layer') {
obj.Layers.push(parseLayer(state, model));
}
else if (keyword === 'PriorityPlane' || keyword === 'RenderMode') {
obj[keyword] = parseNumber(state);
}
else if (keyword === 'ConstantColor' || keyword === 'SortPrimsFarZ' || keyword === 'FullResolution') {
obj.RenderMode |= MaterialRenderMode[keyword];
}
else if (model.Version >= 900 && keyword === 'Shader') {
obj[keyword] = parseString(state);
}
else {
throw new Error('Unknown material property ' + keyword);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
res.push(obj);
}
strictParseSymbol(state, '}');
model.Materials = res;
}
var GeosetPartType;
(function (GeosetPartType) {
GeosetPartType[GeosetPartType["INT"] = 0] = "INT";
GeosetPartType[GeosetPartType["FLOAT"] = 1] = "FLOAT";
})(GeosetPartType || (GeosetPartType = {}));
function parseGeosetPart(state, countPerObj, type) {
var count = parseNumber(state);
var arr = new (type === GeosetPartType.FLOAT ? Float32Array : Uint8Array)(count * countPerObj);
strictParseSymbol(state, '{');
for (var index = 0; index < count; ++index) {
parseArray(state, arr, index * countPerObj);
strictParseSymbol(state, ',');
}
strictParseSymbol(state, '}');
return arr;
}
function parseGeoset(state, model) {
var res = {
Vertices: null,
Normals: null,
TVertices: [],
VertexGroup: new Uint8Array(0),
Faces: null,
Groups: null,
TotalGroupsCount: null,
MinimumExtent: null,
MaximumExtent: null,
BoundsRadius: 0,
Anims: [],
MaterialID: null,
SelectionGroup: null,
Unselectable: false
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Vertices' || keyword === 'Normals' || keyword === 'TVertices') {
var countPerObj = 3;
if (keyword === 'TVertices') {
countPerObj = 2;
}
var arr = parseGeosetPart(state, countPerObj, GeosetPartType.FLOAT);
if (keyword === 'TVertices') {
res.TVertices.push(arr);
}
else {
res[keyword] = arr;
}
}
else if (keyword === 'VertexGroup') {
res[keyword] = new Uint8Array(res.Vertices.length / 3);
parseArray(state, res[keyword], 0);
}
else if (keyword === 'Faces') {
parseNumber(state); // group count, always 1?
var indexCount = parseNumber(state);
res.Faces = new Uint16Array(indexCount);
strictParseSymbol(state, '{');
parseKeyword(state); // Triangles
strictParseSymbol(state, '{');
parseArray(state, res.Faces, 0);
parseSymbol(state, ',');
strictParseSymbol(state, '}');
strictParseSymbol(state, '}');
}
else if (keyword === 'Groups') {
var groups = [];
parseNumber(state); // groups count, unused
res.TotalGroupsCount = parseNumber(state); // summed in subarrays
strictParseSymbol(state, '{');
while (state.char() !== '}') {
parseKeyword(state); // Matrices
groups.push(parseArray(state));
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
res.Groups = groups;
}
else if (keyword === 'MinimumExtent' || keyword === 'MaximumExtent') {
var arr = new Float32Array(3);
res[keyword] = parseArray(state, arr, 0);
strictParseSymbol(state, ',');
}
else if (keyword === 'BoundsRadius' || keyword === 'MaterialID' || keyword === 'SelectionGroup') {
res[keyword] = parseNumber(state);
strictParseSymbol(state, ',');
}
else if (keyword === 'Anim') {
var _a = parseObject(state); _a[0]; var obj = _a[1];
if (obj.Alpha === undefined) {
obj.Alpha = 1;
}
res.Anims.push(obj);
}
else if (keyword === 'Unselectable') {
res.Unselectable = true;
strictParseSymbol(state, ',');
}
else if (model.Version >= 900) {
if (keyword === 'LevelOfDetail') {
res.LevelOfDetail = parseNumber(state);
strictParseSymbol(state, ',');
}
else if (keyword === 'Name') {
res.Name = parseString(state);
strictParseSymbol(state, ',');
}
else if (keyword === 'Tangents') {
res.Tangents = parseGeosetPart(state, 4, GeosetPartType.FLOAT);
}
else if (keyword === 'SkinWeights') {
var count = parseNumber(state);
var arr = new Uint8Array(count * 4);
res.SkinWeights = parseArray(state, arr, 0);
}
}
}
strictParseSymbol(state, '}');
model.Geosets.push(res);
}
function parseGeosetAnim(state, model) {
var res = {
GeosetId: -1,
Alpha: 1,
Color: null,
Flags: 0
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (keyword === 'Alpha') {
if (isStatic) {
res.Alpha = parseNumber(state);
}
else {
res.Alpha = parseAnimVector(state, AnimVectorType$2.FLOAT1);
}
}
else if (keyword === 'Color') {
if (isStatic) {
var array = new Float32Array(3);
res.Color = parseArray(state, array, 0);
res.Color.reverse();
}
else {
res.Color = parseAnimVector(state, AnimVectorType$2.FLOAT3);
for (var _i = 0, _a = res.Color.Keys; _i < _a.length; _i++) {
var key = _a[_i];
key.Vector.reverse();
if (key.InTan) {
key.InTan.reverse();
key.OutTan.reverse();
}
}
}
}
else if (keyword === 'DropShadow') {
res.Flags |= GeosetAnimFlags[keyword];
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.GeosetAnims.push(res);
}
function parseNode$1(state, type, model) {
var name = parseString(state);
var node = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Flags: NodeType[type]
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Translation' || keyword === 'Rotation' || keyword === 'Scaling' || keyword === 'Visibility') {
var vectorType = AnimVectorType$2.FLOAT3;
if (keyword === 'Rotation') {
vectorType = AnimVectorType$2.FLOAT4;
}
else if (keyword === 'Visibility') {
vectorType = AnimVectorType$2.FLOAT1;
}
node[keyword] = parseAnimVector(state, vectorType);
}
else if (keyword === 'BillboardedLockZ' || keyword === 'BillboardedLockY' || keyword === 'BillboardedLockX' ||
keyword === 'Billboarded' || keyword === 'CameraAnchored') {
node.Flags |= NodeFlags[keyword];
}
else if (keyword === 'DontInherit') {
strictParseSymbol(state, '{');
var val = parseKeyword(state);
if (val === 'Translation') {
node.Flags |= NodeFlags.DontInheritTranslation;
}
else if (val === 'Rotation') {
node.Flags |= NodeFlags.DontInheritRotation;
}
else if (val === 'Scaling') {
node.Flags |= NodeFlags.DontInheritScaling;
}
strictParseSymbol(state, '}');
}
else if (keyword === 'Path') {
node[keyword] = parseString(state);
}
else {
var val = parseKeyword(state) || parseNumber(state);
if (keyword === 'GeosetId' && val === 'Multiple' ||
keyword === 'GeosetAnimId' && val === 'None') {
val = null;
}
node[keyword] = val;
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.Nodes[node.ObjectId] = node;
return node;
}
function parseBone(state, model) {
var node = parseNode$1(state, 'Bone', model);
model.Bones.push(node);
}
function parseHelper(state, model) {
var node = parseNode$1(state, 'Helper', model);
model.Helpers.push(node);
}
function parseAttachment(state, model) {
var node = parseNode$1(state, 'Attachment', model);
model.Attachments.push(node);
}
function parsePivotPoints$1(state, model) {
var count = parseNumber(state);
var res = [];
strictParseSymbol(state, '{');
for (var i = 0; i < count; ++i) {
res.push(parseArray(state, new Float32Array(3), 0));
strictParseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.PivotPoints = res;
}
function parseEventObject(state, model) {
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
EventTrack: null,
Flags: NodeType.EventObject
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'EventTrack') {
var count = parseNumber(state); // EventTrack count
res.EventTrack = parseArray(state, new Uint32Array(count), 0);
}
else if (keyword === 'Translation' || keyword === 'Rotation' || keyword === 'Scaling') {
var type = keyword === 'Rotation' ? AnimVectorType$2.FLOAT4 : AnimVectorType$2.FLOAT3;
res[keyword] = parseAnimVector(state, type);
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.EventObjects.push(res);
model.Nodes.push(res);
}
function parseCollisionShape(state, model) {
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Shape: CollisionShapeType.Box,
Vertices: null,
Flags: NodeType.CollisionShape
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Sphere') {
res.Shape = CollisionShapeType.Sphere;
}
else if (keyword === 'Box') {
res.Shape = CollisionShapeType.Box;
}
else if (keyword === 'Vertices') {
var count = parseNumber(state);
var vertices = new Float32Array(count * 3);
strictParseSymbol(state, '{');
for (var i = 0; i < count; ++i) {
parseArray(state, vertices, i * 3);
strictParseSymbol(state, ',');
}
strictParseSymbol(state, '}');
res.Vertices = vertices;
}
else if (keyword === 'Translation' || keyword === 'Rotation' || keyword === 'Scaling') {
var type = keyword === 'Rotation' ? AnimVectorType$2.FLOAT4 : AnimVectorType$2.FLOAT3;
res[keyword] = parseAnimVector(state, type);
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.CollisionShapes.push(res);
model.Nodes.push(res);
}
function parseGlobalSequences$1(state, model) {
var res = [];
var count = parseNumber(state);
strictParseSymbol(state, '{');
for (var i = 0; i < count; ++i) {
var keyword = parseKeyword(state);
if (keyword === 'Duration') {
res.push(parseNumber(state));
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.GlobalSequences = res;
}
function parseUnknownBlock(state) {
var opened;
while (state.char() !== undefined && state.char() !== '{') {
++state.pos;
}
opened = 1;
++state.pos;
while (state.char() !== undefined && opened > 0) {
if (state.char() === '{') {
++opened;
}
else if (state.char() === '}') {
--opened;
}
++state.pos;
}
parseSpace(state);
}
function parseParticleEmitter(state, model) {
var res = {
ObjectId: null,
Parent: null,
Name: null,
Flags: 0
};
res.Name = parseString(state);
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (keyword === 'ObjectId' || keyword === 'Parent') {
res[keyword] = parseNumber(state);
}
else if (keyword === 'EmitterUsesMDL' || keyword === 'EmitterUsesTGA') {
res.Flags |= ParticleEmitterFlags[keyword];
}
else if (!isStatic && (keyword === 'Visibility' || keyword === 'Translation' || keyword === 'Rotation' ||
keyword === 'Scaling' || keyword === 'EmissionRate' || keyword === 'Gravity' || keyword === 'Longitude' ||
keyword === 'Latitude')) {
var type = AnimVectorType$2.FLOAT3;
if (keyword === 'Visibility' || keyword === 'EmissionRate' || keyword === 'Gravity' ||
keyword === 'Longitude' || keyword === 'Latitude') {
type = AnimVectorType$2.FLOAT1;
}
else if (keyword === 'Rotation') {
type = AnimVectorType$2.FLOAT4;
}
res[keyword] = parseAnimVector(state, type);
}
else if (keyword === 'Particle') {
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword2 = parseKeyword(state);
var isStatic2 = false;
if (keyword2 === 'static') {
isStatic2 = true;
keyword2 = parseKeyword(state);
}
if (!isStatic2 && (keyword2 === 'LifeSpan' || keyword2 === 'InitVelocity')) {
res[keyword2] = parseAnimVector(state, AnimVectorType$2.FLOAT1);
}
else if (keyword2 === 'LifeSpan' || keyword2 === 'InitVelocity') {
res[keyword2] = parseNumber(state);
}
else if (keyword2 === 'Path') {
res.Path = parseString(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.ParticleEmitters.push(res);
}
function parseParticleEmitter2(state, model) {
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Flags: NodeType.ParticleEmitter,
FrameFlags: 0
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (!isStatic && (keyword === 'Speed' || keyword === 'Latitude' || keyword === 'Visibility' ||
keyword === 'EmissionRate' || keyword === 'Width' || keyword === 'Length' || keyword === 'Translation' ||
keyword === 'Rotation' || keyword === 'Scaling' || keyword === 'Gravity' || keyword === 'Variation')) {
var type = AnimVectorType$2.FLOAT3;
switch (keyword) {
case 'Rotation':
type = AnimVectorType$2.FLOAT4;
break;
case 'Speed':
case 'Latitude':
case 'Visibility':
case 'EmissionRate':
case 'Width':
case 'Length':
case 'Gravity':
case 'Variation':
type = AnimVectorType$2.FLOAT1;
break;
}
res[keyword] = parseAnimVector(state, type);
}
else if (keyword === 'Variation' || keyword === 'Gravity') {
res[keyword] = parseNumber(state);
}
else if (keyword === 'SortPrimsFarZ' || keyword === 'Unshaded' || keyword === 'LineEmitter' ||
keyword === 'Unfogged' || keyword === 'ModelSpace' || keyword === 'XYQuad') {
res.Flags |= ParticleEmitter2Flags[keyword];
}
else if (keyword === 'Both') {
res.FrameFlags |= ParticleEmitter2FramesFlags.Head | ParticleEmitter2FramesFlags.Tail;
}
else if (keyword === 'Head' || keyword === 'Tail') {
res.FrameFlags |= ParticleEmitter2FramesFlags[keyword];
}
else if (keyword === 'Squirt') {
res[keyword] = true;
}
else if (keyword === 'DontInherit') {
strictParseSymbol(state, '{');
var val = parseKeyword(state);
if (val === 'Translation') {
res.Flags |= NodeFlags.DontInheritTranslation;
}
else if (val === 'Rotation') {
res.Flags |= NodeFlags.DontInheritRotation;
}
else if (val === 'Scaling') {
res.Flags |= NodeFlags.DontInheritScaling;
}
strictParseSymbol(state, '}');
}
else if (keyword === 'SegmentColor') {
var colors = [];
strictParseSymbol(state, '{');
while (state.char() !== '}') {
parseKeyword(state); // Color
var colorArr = new Float32Array(3);
parseArray(state, colorArr, 0);
// bgr order, inverse from mdx
var temp = colorArr[0];
colorArr[0] = colorArr[2];
colorArr[2] = temp;
colors.push(colorArr);
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
res.SegmentColor = colors;
}
else if (keyword === 'Alpha') {
res.Alpha = new Uint8Array(3);
parseArray(state, res.Alpha, 0);
}
else if (keyword === 'ParticleScaling') {
res[keyword] = new Float32Array(3);
parseArray(state, res[keyword], 0);
}
else if (keyword === 'LifeSpanUVAnim' || keyword === 'DecayUVAnim' || keyword === 'TailUVAnim' ||
keyword === 'TailDecayUVAnim') {
res[keyword] = new Uint32Array(3);
parseArray(state, res[keyword], 0);
}
else if (keyword === 'Transparent' || keyword === 'Blend' || keyword === 'Additive' ||
keyword === 'AlphaKey' || keyword === 'Modulate' || keyword === 'Modulate2x') {
res.FilterMode = ParticleEmitter2FilterMode[keyword];
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.ParticleEmitters2.push(res);
model.Nodes.push(res);
}
function parseCamera(state, model) {
var res = {
Name: null,
Position: null,
FieldOfView: 0,
NearClip: 0,
FarClip: 0,
TargetPosition: null
};
res.Name = parseString(state);
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Position') {
res.Position = new Float32Array(3);
parseArray(state, res.Position, 0);
}
else if (keyword === 'FieldOfView' || keyword === 'NearClip' || keyword === 'FarClip') {
res[keyword] = parseNumber(state);
}
else if (keyword === 'Target') {
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword2 = parseKeyword(state);
if (keyword2 === 'Position') {
res.TargetPosition = new Float32Array(3);
parseArray(state, res.TargetPosition, 0);
}
else if (keyword2 === 'Translation') {
res.TargetTranslation = parseAnimVector(state, AnimVectorType$2.FLOAT3);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
}
else if (keyword === 'Translation' || keyword === 'Rotation') {
res[keyword] = parseAnimVector(state, keyword === 'Rotation' ?
AnimVectorType$2.FLOAT1 :
AnimVectorType$2.FLOAT3);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.Cameras.push(res);
}
function parseLight(state, model) {
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Flags: NodeType.Light,
LightType: 0
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (!isStatic && (keyword === 'Visibility' || keyword === 'Color' || keyword === 'Intensity' ||
keyword === 'AmbIntensity' || keyword === 'AmbColor' || keyword === 'Translation' ||
keyword === 'Rotation' || keyword === 'Scaling' || keyword === 'AttenuationStart' ||
keyword === 'AttenuationEnd')) {
var type = AnimVectorType$2.FLOAT3;
switch (keyword) {
case 'Rotation':
type = AnimVectorType$2.FLOAT4;
break;
case 'Visibility':
case 'Intensity':
case 'AmbIntensity':
case 'AttenuationStart':
case 'AttenuationEnd':
type = AnimVectorType$2.FLOAT1;
break;
}
res[keyword] = parseAnimVector(state, type);
if (keyword === 'Color' || keyword === 'AmbColor') {
for (var _i = 0, _a = res[keyword].Keys; _i < _a.length; _i++) {
var key = _a[_i];
key.Vector.reverse();
if (key.InTan) {
key.InTan.reverse();
key.OutTan.reverse();
}
}
}
}
else if (keyword === 'Omnidirectional' || keyword === 'Directional' || keyword === 'Ambient') {
res.LightType = LightType[keyword];
}
else if (keyword === 'Color' || keyword === 'AmbColor') {
var color = new Float32Array(3);
parseArray(state, color, 0);
// bgr order, inverse from mdx
var temp = color[0];
color[0] = color[2];
color[2] = temp;
res[keyword] = color;
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.Lights.push(res);
model.Nodes.push(res);
}
function parseTextureAnims$1(state, model) {
var res = [];
parseNumber(state); // count, not used
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var obj = {};
parseKeyword(state); // TVertexAnim
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Translation' || keyword === 'Rotation' || keyword === 'Scaling') {
var type = keyword === 'Rotation' ? AnimVectorType$2.FLOAT4 : AnimVectorType$2.FLOAT3;
obj[keyword] = parseAnimVector(state, type);
}
else {
throw new Error('Unknown texture anim property ' + keyword);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
res.push(obj);
}
strictParseSymbol(state, '}');
model.TextureAnims = res;
}
function parseRibbonEmitter(state, model) {
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Flags: NodeType.RibbonEmitter,
HeightAbove: null,
HeightBelow: null,
Alpha: null,
Color: null,
LifeSpan: null,
TextureSlot: null,
EmissionRate: null,
Rows: null,
Columns: null,
MaterialID: null,
Gravity: null,
Visibility: null
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (!isStatic && (keyword === 'Visibility' || keyword === 'HeightAbove' || keyword === 'HeightBelow' ||
keyword === 'Translation' || keyword === 'Rotation' || keyword === 'Scaling' || keyword === 'Alpha' ||
keyword === 'TextureSlot')) {
var type = AnimVectorType$2.FLOAT3;
switch (keyword) {
case 'Rotation':
type = AnimVectorType$2.FLOAT4;
break;
case 'Visibility':
case 'HeightAbove':
case 'HeightBelow':
case 'Alpha':
type = AnimVectorType$2.FLOAT1;
break;
case 'TextureSlot':
type = AnimVectorType$2.INT1;
break;
}
res[keyword] = parseAnimVector(state, type);
}
else if (keyword === 'Color') {
var color = new Float32Array(3);
parseArray(state, color, 0);
// bgr order, inverse from mdx
var temp = color[0];
color[0] = color[2];
color[2] = temp;
res[keyword] = color;
}
else {
res[keyword] = parseNumber(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.RibbonEmitters.push(res);
model.Nodes.push(res);
}
function parseFaceFX$1(state, model) {
if (model.Version < 900) {
throwError(state, 'Unexpected model chunk FaceFX');
}
var name = parseString(state);
var res = {
Name: name,
Path: ''
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
if (!keyword) {
throwError(state);
}
if (keyword === 'Path') {
res.Path = parseString(state);
}
parseSymbol(state, ',');
}
strictParseSymbol(state, '}');
model.FaceFX = model.FaceFX || [];
model.FaceFX.push(res);
}
function parseBindPose$1(state, model) {
if (model.Version < 900) {
throwError(state, 'Unexpected model chunk BindPose');
}
var res = {
Matrices: []
};
strictParseSymbol(state, '{');
parseKeyword(state); // Matrices
var count = parseNumber(state);
strictParseSymbol(state, '{');
for (var i = 0; i < count; ++i) {
var matrix = new Float32Array(12);
parseArray(state, matrix, 0);
res.Matrices.push(matrix);
}
strictParseSymbol(state, '}');
strictParseSymbol(state, '}');
model.BindPoses = model.BindPoses || [];
model.BindPoses.push(res);
}
function parseParticleEmitterPopcorn$1(state, model) {
if (model.Version < 900) {
throwError(state, 'Unexpected model chunk ParticleEmitterPopcorn');
}
var name = parseString(state);
var res = {
Name: name,
ObjectId: null,
Parent: null,
PivotPoint: null,
Flags: NodeType.ParticleEmitter
};
strictParseSymbol(state, '{');
while (state.char() !== '}') {
var keyword = parseKeyword(state);
var isStatic = false;
if (!keyword) {
throwError(state);
}
if (keyword === 'static') {
isStatic = true;
keyword = parseKeyword(state);
}
if (!isStatic && (keyword === 'LifeSpan' || keyword === 'EmissionRate' || keyword === 'Speed' ||
keyword === 'Color' || keyword === 'Alpha' || keyword === 'Visibility' ||
keyword === 'Rotation' || keyword === 'Scaling' || keyword === 'Translation')) {
var type = AnimVectorType$2.FLOAT3;
switch (keyword) {
case 'LifeSpan':
case 'EmissionRate':
case 'Speed':
case 'Alpha':
case 'Visibility':
type = AnimVectorType$2.FLOAT1;
break;
}
res[keyword] = parseAnimVector(state, type);
}
else if (keyword === 'LifeSpan' || keyword === 'EmissionRate' || keyword === 'Speed' || keyword === 'Alpha') {
res[keyword] = parseNumber(state);
}
else if (keyword === 'Color') {
var array = new Float32Array(3);
res[keyword] = parseArray(state, array, 0);
}
else if (keyword === 'ReplaceableId') {
res[keyword] = parseNumber(state);