mdx-m3-viewer
Version:
A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.
178 lines (141 loc) • 5.47 kB
text/typescript
import Reference from '../../../parsers/m3/reference';
import Layer from '../../../parsers/m3/layer';
import Texture from '../../texture';
import ShaderProgram from '../../gl/program';
import { M3StandardMaterial, STANDARD_MATERIAL_OFFSET } from './standardmaterial';
import M3Model from './model';
import M3Texture from './texture';
const layerTypeToTextureUnit = {
diffuse: 1,
decal: 2,
specular: 3,
gloss: 4,
emissive: 5,
emissive2: 6,
evio: 7,
evioMask: 8,
alphaMask: 9,
alphaMask2: 10,
normal: 11,
heightMap: 12,
lightMap: 13,
ao: 14,
};
/**
* An M3 layer.
*/
export default class M3Layer {
model: M3Model;
material: M3StandardMaterial;
index: number;
active: number = 0;
layer: Layer | null = null;
gl: WebGLRenderingContext;
uniformMap: { map: string; enabled: string; op: string; channels: string; teamColorMode: string; invert: string; clampResult: string; uvCoordinate: string; };
source: string = '';
texture: M3Texture | null = null;
flags: number = 0;
colorChannels: number = 0;
type: string = '';
op: number = 0;
uvCoordinate: number = 0;
textureUnit: number = 0;
invert: number = 0;
clampResult: number = 0;
teamColorMode: number = 0;
constructor(material: M3StandardMaterial, index: number, layerReference: Reference | null, type: string, op: number) {
let model = material.model;
this.model = model;
this.material = material;
this.gl = material.gl;
this.index = index;
let uniform = 'u_' + type;
let settings = uniform + 'LayerSettings.';
this.uniformMap = {
map: uniform + 'Map',
enabled: settings + 'enabled',
op: settings + 'op',
channels: settings + 'channels',
teamColorMode: settings + 'teamColorMode',
invert: settings + 'invert',
clampResult: settings + 'clampResult',
uvCoordinate: settings + 'uvCoordinate',
};
// Since Gloss doesn't exist in all versions
if (layerReference) {
let layer = <Layer>layerReference.first();
this.layer = layer;
let pathSolver = model.pathSolver;
let source = (<string>layer.imagePath.get()).toLowerCase();
if (source.length) {
this.source = source;
this.active = 1;
let uvSource = layer.uvSource;
let flags = layer.flags;
this.flags = flags;
this.colorChannels = layer.colorChannelSetting;
this.model = model;
this.type = type;
this.op = op;
let uvCoordinate = 0;
if (uvSource === 1) {
uvCoordinate = 1;
} else if (uvSource === 9) {
uvCoordinate = 2;
} else if (uvSource === 10) {
uvCoordinate = 3;
}
this.uvCoordinate = uvCoordinate;
this.textureUnit = layerTypeToTextureUnit[type];
this.invert = flags & 0x10;
this.clampResult = flags & 0x20;
// I am not sure if the emissive team color mode is even used, since so far combineColors takes care of it.
if (type === 'diffuse') {
this.teamColorMode = 1;
}
let m3Texture = new M3Texture(!!(flags & 0x4), !!(flags & 0x8));
model.viewer.load(source, pathSolver)
.then((texture) => {
if (texture) {
m3Texture.texture = <Texture>texture;
}
});
this.texture = m3Texture;
}
}
}
bind(shader: ShaderProgram, textureOverrides: Map<number, Texture>) {
let gl = this.gl;
let uniformMap = this.uniformMap;
let uniforms = shader.uniforms;
let active = this.active;
gl.uniform1f(uniforms[uniformMap.enabled], active);
if (active) {
let m3Texture = <M3Texture>this.texture;
let texture = textureOverrides.get(this.material.index * STANDARD_MATERIAL_OFFSET + this.index) || m3Texture.texture;
let textureUnit = this.textureUnit;
gl.uniform1i(uniforms[uniformMap.map], textureUnit);
this.model.viewer.webgl.bindTextureAndWrap(texture, textureUnit, m3Texture.wrapS, m3Texture.wrapT);
gl.uniform1f(uniforms[uniformMap.op], this.op);
gl.uniform1f(uniforms[uniformMap.channels], this.colorChannels);
gl.uniform1f(uniforms[uniformMap.teamColorMode], this.teamColorMode);
// Alpha is probably unknown12. Can this be confirmed?
// Many of these flags seem to be incorrect
// gl.setParameter(uniform + 'multAddAlpha', [this.model.getValue(this.rgbMultiply, sequence, frame), this.model.getValue(this.rgbAdd, sequence, frame), 0]);
// gl.setParameter(uniform + 'useAlphaFactor', 0);
gl.uniform1f(uniforms[uniformMap.invert], this.invert);
// gl.setParameter(uniform + 'multColor', 0);
// gl.setParameter(uniform + 'addColor', 0);
gl.uniform1f(uniforms[uniformMap.clampResult], this.clampResult);
// gl.setParameter(uniform + 'useConstantColor', this.flags && 0x400);
// gl.setParameter(uniform + 'constantColor', this.model.getValue(this.color, sequence, frame));
// gl.setParameter(settings + 'uvSource', this.uvSource);
gl.uniform1f(uniforms[uniformMap.uvCoordinate], this.uvCoordinate);
}
}
unbind(shader: ShaderProgram) {
if (this.active) {
this.gl.uniform1f(shader.uniforms[this.uniformMap.enabled], 0);
}
}
}