(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports"], factory); } else if (typeof exports !== "undefined") { factory(exports); } else { var mod = { exports: {} }; factory(mod.exports); global.LWO2Parser = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.LWO2Parser = LWO2Parser; function LWO2Parser(IFFParser) { this.IFF = IFFParser; } LWO2Parser.prototype = { constructor: LWO2Parser, parseBlock: function parseBlock() { this.IFF.debugger.offset = this.IFF.reader.offset; this.IFF.debugger.closeForms(); var blockID = this.IFF.reader.getIDTag(); var length = this.IFF.reader.getUint32(); // size of data in bytes if (length > this.IFF.reader.dv.byteLength - this.IFF.reader.offset) { this.IFF.reader.offset -= 4; length = this.IFF.reader.getUint16(); } this.IFF.debugger.dataOffset = this.IFF.reader.offset; this.IFF.debugger.length = length; // Data types may be found in either LWO2 OR LWO3 spec switch (blockID) { case 'FORM': // form blocks may consist of sub -chunks or sub-forms this.IFF.parseForm(length); break; // SKIPPED CHUNKS // if break; is called directly, the position in the lwoTree is not created // any sub chunks and forms are added to the parent form instead // MISC skipped case 'ICON': // Thumbnail Icon Image case 'VMPA': // Vertex Map Parameter case 'BBOX': // bounding box // case 'VMMD': // case 'VTYP': // normal maps can be specified, normally on models imported from other applications. Currently ignored case 'NORM': // ENVL FORM skipped case 'PRE ': case 'POST': case 'KEY ': case 'SPAN': // CLIP FORM skipped case 'TIME': case 'CLRS': case 'CLRA': case 'FILT': case 'DITH': case 'CONT': case 'BRIT': case 'SATR': case 'HUE ': case 'GAMM': case 'NEGA': case 'IFLT': case 'PFLT': // Image Map Layer skipped case 'PROJ': case 'AXIS': case 'AAST': case 'PIXB': case 'AUVO': case 'STCK': // Procedural Textures skipped case 'PROC': case 'VALU': case 'FUNC': // Gradient Textures skipped case 'PNAM': case 'INAM': case 'GRST': case 'GREN': case 'GRPT': case 'FKEY': case 'IKEY': // Texture Mapping Form skipped case 'CSYS': // Surface CHUNKs skipped case 'OPAQ': // top level 'opacity' checkbox case 'CMAP': // clip map // Surface node CHUNKS skipped // These mainly specify the node editor setup in LW case 'NLOC': case 'NZOM': case 'NVER': case 'NSRV': case 'NVSK': // unknown case 'NCRD': case 'WRPW': // image wrap w ( for cylindrical and spherical projections) case 'WRPH': // image wrap h case 'NMOD': case 'NSEL': case 'NPRW': case 'NPLA': case 'NODS': case 'VERS': case 'ENUM': case 'TAG ': case 'OPAC': // Car Material CHUNKS case 'CGMD': case 'CGTY': case 'CGST': case 'CGEN': case 'CGTS': case 'CGTE': case 'OSMP': case 'OMDE': case 'OUTR': case 'FLAG': case 'TRNL': case 'GLOW': case 'GVAL': // glow intensity case 'SHRP': case 'RFOP': case 'RSAN': case 'TROP': case 'RBLR': case 'TBLR': case 'CLRH': case 'CLRF': case 'ADTR': case 'LINE': case 'ALPH': case 'VCOL': case 'ENAB': this.IFF.debugger.skipped = true; this.IFF.reader.skip(length); break; case 'SURF': this.IFF.parseSurfaceLwo2(length); break; case 'CLIP': this.IFF.parseClipLwo2(length); break; // Texture node chunks (not in spec) case 'IPIX': // usePixelBlending case 'IMIP': // useMipMaps case 'IMOD': // imageBlendingMode case 'AMOD': // unknown case 'IINV': // imageInvertAlpha case 'INCR': // imageInvertColor case 'IAXS': // imageAxis ( for non-UV maps) case 'IFOT': // imageFallofType case 'ITIM': // timing for animated textures case 'IWRL': case 'IUTI': case 'IINX': case 'IINY': case 'IINZ': case 'IREF': // possibly a VX for reused texture nodes if (length === 4) this.IFF.currentNode[blockID] = this.IFF.reader.getInt32();else this.IFF.reader.skip(length); break; case 'OTAG': this.IFF.parseObjectTag(); break; case 'LAYR': this.IFF.parseLayer(length); break; case 'PNTS': this.IFF.parsePoints(length); break; case 'VMAP': this.IFF.parseVertexMapping(length); break; case 'AUVU': case 'AUVN': this.IFF.reader.skip(length - 1); this.IFF.reader.getVariableLengthIndex(); // VX break; case 'POLS': this.IFF.parsePolygonList(length); break; case 'TAGS': this.IFF.parseTagStrings(length); break; case 'PTAG': this.IFF.parsePolygonTagMapping(length); break; case 'VMAD': this.IFF.parseVertexMapping(length, true); break; // Misc CHUNKS case 'DESC': // Description Line this.IFF.currentForm.description = this.IFF.reader.getString(); break; case 'TEXT': case 'CMNT': case 'NCOM': this.IFF.currentForm.comment = this.IFF.reader.getString(); break; // Envelope Form case 'NAME': this.IFF.currentForm.channelName = this.IFF.reader.getString(); break; // Image Map Layer case 'WRAP': this.IFF.currentForm.wrap = { w: this.IFF.reader.getUint16(), h: this.IFF.reader.getUint16() }; break; case 'IMAG': var index = this.IFF.reader.getVariableLengthIndex(); this.IFF.currentForm.imageIndex = index; break; // Texture Mapping Form case 'OREF': this.IFF.currentForm.referenceObject = this.IFF.reader.getString(); break; case 'ROID': this.IFF.currentForm.referenceObjectID = this.IFF.reader.getUint32(); break; // Surface Blocks case 'SSHN': this.IFF.currentSurface.surfaceShaderName = this.IFF.reader.getString(); break; case 'AOVN': this.IFF.currentSurface.surfaceCustomAOVName = this.IFF.reader.getString(); break; // Nodal Blocks case 'NSTA': this.IFF.currentForm.disabled = this.IFF.reader.getUint16(); break; case 'NRNM': this.IFF.currentForm.realName = this.IFF.reader.getString(); break; case 'NNME': this.IFF.currentForm.refName = this.IFF.reader.getString(); this.IFF.currentSurface.nodes[this.IFF.currentForm.refName] = this.IFF.currentForm; break; // Nodal Blocks : connections case 'INME': if (!this.IFF.currentForm.nodeName) this.IFF.currentForm.nodeName = []; this.IFF.currentForm.nodeName.push(this.IFF.reader.getString()); break; case 'IINN': if (!this.IFF.currentForm.inputNodeName) this.IFF.currentForm.inputNodeName = []; this.IFF.currentForm.inputNodeName.push(this.IFF.reader.getString()); break; case 'IINM': if (!this.IFF.currentForm.inputName) this.IFF.currentForm.inputName = []; this.IFF.currentForm.inputName.push(this.IFF.reader.getString()); break; case 'IONM': if (!this.IFF.currentForm.inputOutputName) this.IFF.currentForm.inputOutputName = []; this.IFF.currentForm.inputOutputName.push(this.IFF.reader.getString()); break; case 'FNAM': this.IFF.currentForm.fileName = this.IFF.reader.getString(); break; case 'CHAN': // NOTE: ENVL Forms may also have CHAN chunk, however ENVL is currently ignored if (length === 4) this.IFF.currentForm.textureChannel = this.IFF.reader.getIDTag();else this.IFF.reader.skip(length); break; // LWO2 Spec chunks: these are needed since the SURF FORMs are often in LWO2 format case 'SMAN': var maxSmoothingAngle = this.IFF.reader.getFloat32(); this.IFF.currentSurface.attributes.smooth = maxSmoothingAngle < 0 ? false : true; break; // LWO2: Basic Surface Parameters case 'COLR': this.IFF.currentSurface.attributes.Color = { value: this.IFF.reader.getFloat32Array(3) }; this.IFF.reader.skip(2); // VX: envelope break; case 'LUMI': this.IFF.currentSurface.attributes.Luminosity = { value: this.IFF.reader.getFloat32() }; this.IFF.reader.skip(2); break; case 'SPEC': this.IFF.currentSurface.attributes.Specular = { value: this.IFF.reader.getFloat32() }; this.IFF.reader.skip(2); break; case 'DIFF': this.IFF.currentSurface.attributes.Diffuse = { value: this.IFF.reader.getFloat32() }; this.IFF.reader.skip(2); break; case 'REFL': this.IFF.currentSurface.attributes.Reflection = { value: this.IFF.reader.getFloat32() }; this.IFF.reader.skip(2); break; case 'GLOS': this.IFF.currentSurface.attributes.Glossiness = { value: this.IFF.reader.getFloat32() }; this.IFF.reader.skip(2); break; case 'TRAN': this.IFF.currentSurface.attributes.opacity = this.IFF.reader.getFloat32(); this.IFF.reader.skip(2); break; case 'BUMP': this.IFF.currentSurface.attributes.bumpStrength = this.IFF.reader.getFloat32(); this.IFF.reader.skip(2); break; case 'SIDE': this.IFF.currentSurface.attributes.side = this.IFF.reader.getUint16(); break; case 'RIMG': this.IFF.currentSurface.attributes.reflectionMap = this.IFF.reader.getVariableLengthIndex(); break; case 'RIND': this.IFF.currentSurface.attributes.refractiveIndex = this.IFF.reader.getFloat32(); this.IFF.reader.skip(2); break; case 'TIMG': this.IFF.currentSurface.attributes.refractionMap = this.IFF.reader.getVariableLengthIndex(); break; case 'IMAP': this.IFF.reader.skip(2); break; case 'TMAP': this.IFF.debugger.skipped = true; this.IFF.reader.skip(length); // needs implementing break; case 'IUVI': // uv channel name this.IFF.currentNode.UVChannel = this.IFF.reader.getString(length); break; case 'IUTL': // widthWrappingMode: 0 = Reset, 1 = Repeat, 2 = Mirror, 3 = Edge this.IFF.currentNode.widthWrappingMode = this.IFF.reader.getUint32(); break; case 'IVTL': // heightWrappingMode this.IFF.currentNode.heightWrappingMode = this.IFF.reader.getUint32(); break; // LWO2 USE case 'BLOK': // skip break; default: this.IFF.parseUnknownCHUNK(blockID, length); } if (blockID != 'FORM') { this.IFF.debugger.node = 1; this.IFF.debugger.nodeID = blockID; this.IFF.debugger.log(); } if (this.IFF.reader.offset >= this.IFF.currentFormEnd) { this.IFF.currentForm = this.IFF.parentForm; } } }; });