UNPKG

mdx-m3-viewer

Version:

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

156 lines 7.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const geoset_1 = require("./geoset"); const batch_1 = require("./batch"); function setupGeosets(model, geosets) { if (geosets.length > 0) { const gl = model.viewer.gl; let positionBytes = 0; let normalBytes = 0; let uvBytes = 0; let tangentBytes = 0; let skinBytes = 0; let faceBytes = 0; const skinTypes = []; for (let i = 0, l = geosets.length; i < l; i++) { const geoset = geosets[i]; if (geoset.lod === 0 || geoset.lod === -1) { const vertices = geoset.vertices.length / 3; positionBytes += vertices * 12; normalBytes += vertices * 12; uvBytes += geoset.uvSets.length * vertices * 8; if (geoset.tangents.length) { tangentBytes += vertices * 16; } if (geoset.skin.length) { skinBytes += vertices * 8; skinTypes[i] = batch_1.SkinningType.Skin; } else { let biggestGroup = 0; for (const group of geoset.matrixGroups) { if (group > biggestGroup) { biggestGroup = group; } } if (biggestGroup > 4) { skinBytes += vertices * 9; skinTypes[i] = batch_1.SkinningType.ExtendedVertexGroups; } else { skinBytes += vertices * 5; skinTypes[i] = batch_1.SkinningType.VertexGroups; } } faceBytes += geoset.faces.byteLength; } } let positionOffset = 0; let normalOffset = positionOffset + positionBytes; let uvOffset = normalOffset + normalBytes; let tangentOffset = uvOffset + uvBytes; let skinOffset = tangentOffset + tangentBytes; let faceOffset = 0; let SkinTypedArray = Uint8Array; let skinGlType = gl.UNSIGNED_BYTE; if (model.bones.length > 255) { skinBytes *= 2; SkinTypedArray = Uint16Array; skinGlType = gl.UNSIGNED_SHORT; } model.skinDataType = skinGlType; model.bytesPerSkinElement = SkinTypedArray.BYTES_PER_ELEMENT; model.arrayBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, model.arrayBuffer); gl.bufferData(gl.ARRAY_BUFFER, skinOffset + skinBytes, gl.STATIC_DRAW); model.elementBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.elementBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faceBytes, gl.STATIC_DRAW); for (let i = 0, l = geosets.length; i < l; i++) { const geoset = geosets[i]; if (geoset.lod === 0 || geoset.lod === -1) { const positions = geoset.vertices; const normals = geoset.normals; const uvSets = geoset.uvSets; const tangents = geoset.tangents; const faces = geoset.faces; let skin; const vertices = geoset.vertices.length / 3; const skinType = skinTypes[i]; if (skinType === batch_1.SkinningType.Skin) { skin = geoset.skin; } else { const matrixIndices = geoset.matrixIndices; const vertexGroups = geoset.vertexGroups; const matrixGroups = []; let offset = 0; // Normally the shader supports up to 4 bones per vertex. // This is enough for almost every existing Warcraft 3 model. // That being said, there are a few models with geosets that need more, for example the Water Elemental. // These geosets use a different shader, which support up to 8 bones per vertex. let maxBones = 4; if (skinType === batch_1.SkinningType.ExtendedVertexGroups) { maxBones = 8; } skin = new SkinTypedArray(vertices * (maxBones + 1)); // Slice the matrix groups. for (const size of geoset.matrixGroups) { matrixGroups.push(matrixIndices.subarray(offset, offset + size)); offset += size; } // Parse the skinning. for (let i = 0; i < vertices; i++) { const matrixGroup = matrixGroups[vertexGroups[i]]; offset = i * (maxBones + 1); // Somehow in some bad models a vertex group index refers to an invalid matrix group. // Such models are still loaded by the game. if (matrixGroup) { const bones = Math.min(matrixGroup.length, maxBones); for (let j = 0; j < bones; j++) { skin[offset + j] = matrixGroup[j] + 1; // 1 is added to diffrentiate between matrix 0, and no matrix. } skin[offset + maxBones] = bones; } } } const vGeoset = new geoset_1.default(model, model.geosets.length, positionOffset, normalOffset, uvOffset, tangentOffset, skinOffset, faceOffset, vertices, faces.length, geoset.faceTypeGroups[0]); model.geosets.push(vGeoset); const material = model.materials[geoset.materialId]; const isHd = material.shader === 'Shader_HD_DefaultUnit'; if (isHd) { model.batches.push(new batch_1.Batch(model.batches.length, vGeoset, material, skinType, true)); } else { for (const layer of material.layers) { model.batches.push(new batch_1.Batch(model.batches.length, vGeoset, layer, skinType, false)); } } // Positions. gl.bufferSubData(gl.ARRAY_BUFFER, positionOffset, positions); positionOffset += positions.byteLength; // Normals. gl.bufferSubData(gl.ARRAY_BUFFER, normalOffset, normals); normalOffset += normals.byteLength; // Texture coordinates. for (const uvSet of uvSets) { gl.bufferSubData(gl.ARRAY_BUFFER, uvOffset, uvSet); uvOffset += uvSet.byteLength; } // Tangents. if (tangents.length) { gl.bufferSubData(gl.ARRAY_BUFFER, tangentOffset, tangents); tangentOffset += tangents.byteLength; } // Skin. gl.bufferSubData(gl.ARRAY_BUFFER, skinOffset, skin); skinOffset += skin.byteLength; // Faces. gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, faceOffset, faces); faceOffset += faces.byteLength; } } } } exports.default = setupGeosets; //# sourceMappingURL=setupgeosets.js.map