UNPKG

mdx-m3-viewer

Version:

A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.

229 lines (196 loc) 6.83 kB
import BinaryStream from '../../common/binarystream'; import TokenStream from './tokenstream'; import AnimatedObject from './animatedobject'; const filterModeToMdx = { None: 0, Transparent: 1, Blend: 2, Additive: 3, AddAlpha: 4, Modulate: 5, Modulate2x: 6, }; const filterModeToMdl = { 0: 'None', 1: 'Transparent', 2: 'Blend', 3: 'Additive', 4: 'AddAlpha', 5: 'Modulate', 6: 'Modulate2x', }; /** * A layer. */ export default class Layer extends AnimatedObject { filterMode: number = 0; flags: number = 0; textureId: number = -1; textureAnimationId: number = -1; coordId: number = 0; alpha: number = 1; /** * @since 900 */ emissiveGain: number = 1; /** * @since 1000 */ fresnelColor: Float32Array = new Float32Array([1, 1, 1]); /** * @since 1000 */ fresnelOpacity: number = 0; /** * @since 1000 */ fresnelTeamColor: number = 0; readMdx(stream: BinaryStream, version: number) { const start = stream.index; const size = stream.readUint32(); this.filterMode = stream.readUint32(); this.flags = stream.readUint32(); this.textureId = stream.readInt32(); this.textureAnimationId = stream.readInt32(); this.coordId = stream.readUint32(); this.alpha = stream.readFloat32(); // Note that even though these fields were introduced in versions 900 and 1000 separately, the game does not offer backwards compatibility. if (version > 800) { this.emissiveGain = stream.readFloat32(); stream.readFloat32Array(this.fresnelColor); this.fresnelOpacity = stream.readFloat32(); this.fresnelTeamColor = stream.readFloat32(); } this.readAnimations(stream, size - (stream.index - start)); } writeMdx(stream: BinaryStream, version: number) { stream.writeUint32(this.getByteLength(version)); stream.writeUint32(this.filterMode); stream.writeUint32(this.flags); stream.writeInt32(this.textureId); stream.writeInt32(this.textureAnimationId); stream.writeUint32(this.coordId); stream.writeFloat32(this.alpha); // See note above in readMdx. if (version > 800) { stream.writeFloat32(this.emissiveGain); stream.writeFloat32Array(this.fresnelColor); stream.writeFloat32(this.fresnelOpacity); stream.writeFloat32(this.fresnelTeamColor); } this.writeAnimations(stream); } readMdl(stream: TokenStream) { for (let token of super.readAnimatedBlock(stream)) { if (token === 'FilterMode') { this.filterMode = filterModeToMdx[stream.read()]; } else if (token === 'Unshaded') { this.flags |= 0x1; } else if (token === 'SphereEnvMap') { this.flags |= 0x2; } else if (token === 'TwoSided') { this.flags |= 0x10; } else if (token === 'Unfogged') { this.flags |= 0x20; } else if (token === 'NoDepthTest') { this.flags |= 0x40; } else if (token === 'NoDepthSet') { this.flags |= 0x80; } else if (token === 'Unlit') { this.flags |= 0x100; } else if (token === 'static TextureID') { this.textureId = stream.readInt(); } else if (token === 'TextureID') { this.readAnimation(stream, 'KMTF'); } else if (token === 'TVertexAnimId') { this.textureAnimationId = stream.readInt(); } else if (token === 'CoordId') { this.coordId = stream.readInt(); } else if (token === 'static Alpha') { this.alpha = stream.readFloat(); } else if (token === 'Alpha') { this.readAnimation(stream, 'KMTA'); } else if (token === 'static EmissiveGain') { this.emissiveGain = stream.readFloat(); } else if (token === 'EmissiveGain') { this.readAnimation(stream, 'KMTE') } else if (token === 'static FresnelColor') { stream.readVector(this.fresnelColor); } else if (token === 'FresnelColor') { this.readAnimation(stream, 'KFC3') } else if (token === 'static FresnelOpacity') { this.fresnelOpacity = stream.readFloat(); } else if (token === 'FresnelOpacity') { this.readAnimation(stream, 'KFCA') } else if (token === 'static FresnelTeamColor') { this.fresnelTeamColor = stream.readFloat(); } else if (token === 'FresnelTeamColor') { this.readAnimation(stream, 'KFTC') } else { throw new Error(`Unknown token in Layer: "${token}"`); } } } writeMdl(stream: TokenStream, version: number) { stream.startBlock('Layer'); stream.writeFlagAttrib('FilterMode', filterModeToMdl[this.filterMode]); if (this.flags & 0x1) { stream.writeFlag('Unshaded'); } if (this.flags & 0x2) { stream.writeFlag('SphereEnvMap'); } if (this.flags & 0x10) { stream.writeFlag('TwoSided'); } if (this.flags & 0x20) { stream.writeFlag('Unfogged'); } if (this.flags & 0x40) { stream.writeFlag('NoDepthTest'); } if (this.flags & 0x80) { stream.writeFlag('NoDepthSet'); } if (version > 800) { if (this.flags & 0x100) { stream.writeFlag('Unlit'); } } if (!this.writeAnimation(stream, 'KMTF')) { stream.writeNumberAttrib('static TextureID', this.textureId); } if (this.textureAnimationId !== -1) { stream.writeNumberAttrib('TVertexAnimId', this.textureAnimationId); } if (this.coordId !== 0) { stream.writeNumberAttrib('CoordId', this.coordId); } if (!this.writeAnimation(stream, 'KMTA') && this.alpha !== 1) { stream.writeNumberAttrib('static Alpha', this.alpha); } if (version > 800) { if (!this.writeAnimation(stream, 'KMTE') && this.emissiveGain !== 1) { stream.writeNumberAttrib('static EmissiveGain', this.emissiveGain); } if (!this.writeAnimation(stream, 'KFC3') && (this.fresnelColor[0] !== 1 || this.fresnelColor[1] !== 1 || this.fresnelColor[2] !== 1)) { stream.writeVectorAttrib('static FresnelColor', this.fresnelColor); } if (!this.writeAnimation(stream, 'KFCA') && this.fresnelOpacity !== 0) { stream.writeNumberAttrib('static FresnelOpacity', this.fresnelOpacity); } if (!this.writeAnimation(stream, 'KFTC') && this.fresnelTeamColor !== 0) { stream.writeNumberAttrib('static FresnelTeamColor', this.fresnelTeamColor); } } stream.endBlock(); } getByteLength(version: number) { let size = 28 + super.getByteLength(); // See note above in readMdx. if (version > 800) { size += 24; } return size; } }