UNPKG

source-mdl

Version:

This package can read source engines MDL files. To parse a model, it needs the VTX, VVD and MDL file.

122 lines (108 loc) 4.2 kB
// xmodel_export specification: https://wiki.zeroy.com/index.php?title=Call_of_Duty:_XMODEL_formats module.exports = function(mdl) { const LOD = 0; const vertices = mdl.vertices[LOD]; const meshes = mdl.meshes[LOD]; const data = { 'vertices': [], 'normals': [], 'uvs': [], 'materials': [], 'faces': [], }; for(let i = 0; i < vertices.length; i++) { let vert = vertices[i]; // Cod's model converter doesn't like decimal points longer than six digits most of the time. data.vertices[i] = {'x': vert.position[0].toFixed(6), 'y': vert.position[1].toFixed(6), 'z': vert.position[2].toFixed(6)}; data.normals[i] = {'x': vert.normal[0].toFixed(6), 'y': vert.normal[1].toFixed(6), 'z': vert.normal[2].toFixed(6)}; data.uvs[i] = {'u': vert.texCoords[0].toFixed(6), 'v': vert.texCoords[1].toFixed(6)}; } let face = 0; for(let m = 0; m < meshes.length; m++) { let mesh = meshes[m]; for(let i = 0; i < mesh.indices.length; i += 3) { data.faces[face] = { 'object': m, 'material': mesh.material, 'tris': [] }; for(let j = 0; j < 3; j++) { let index = mesh.indices[i + j]; // For some reason, some verts don't have normals or uv's defined with the same index. if(typeof data.normals[index] == "undefined" || typeof data.normals[index] == "undefined") continue; data.faces[face].tris.push({ 'vert': index, 'normal': data.normals[index], 'uv': data.uvs[index], }); } // Unlike the OBJ format, xmodel_export doesn't tolerate tris with less than 3 points or tris with invalid verts/normals. // So, we gotta make sure that invalid triangles with 2 or 1 vertices are skipped. if(data.faces[face].tris.length == 3) face++; } } let time = new Date().toString(); // model header let result = "// File generated by source-mdl | https://github.com/LordVonAdel/source-mdl\n" + "// xmodel exporter written by johndoe | https://github.com/myuce\n" + `// original filename: ${mdl.name}\n` + `// Export time: ${time}\n\n` + "MODEL\n" + "VERSION 6\n\n" + "NUMBONES 1\n" + "BONE 0 -1 \"tag_origin\"\n\n" + "BONE 0\n" + "OFFSET 0.000000 0.000000 0.000000\n" + "SCALE 1.000000 1.000000 1.000000\n" + "X 1.000000 0.000000 0.000000\n" + "Y 0.000000 1.000000 0.000000\n" + "Z 0.000000 0.000000 1.000000\n\n"; // Verts result += `NUMVERTS ${data.vertices.length}\n`; for(let i = 0; i < data.vertices.length; i++) { let vert = data.vertices[i]; result += `VERT ${i}\n` + `OFFSET ${vert.x} ${vert.y} ${vert.z}\n` + "BONES 1\n" + "BONE 0 1.000000\n\n"; } // Faces result += `NUMFACES ${data.faces.length}\n`; for(face of data.faces) { result += `TRI ${face.object} ${face.material} 0 0\n`; // Face index order doesn't work the same as the OBJ format in xmodel_export let tris = [face.tris[0], face.tris[2], face.tris[1]]; for(tri of tris) { result += `VERT ${tri.vert}\n` + `NORMAL ${tri.normal.x} ${tri.normal.y} ${tri.normal.z}\n` + "COLOR 1.000000 1.000000 1.000000 1.000000\n" + `UV 1 ${tri.uv.u} ${tri.uv.v}\n\n`; } } // Object groups result += `NUMOBJECTS ${meshes.length}\n`; for(let i = 0; i < meshes.length; i++) { result += `OBJECT ${i} johndoeMesh_${i}\n`; } result += "\n"; // Materials result += `NUMMATERIALS ${mdl.textures.length}\n`; for(let i = 0; i < mdl.textures.length; i++) { result += `MATERIAL ${i} "${mdl.textures[i]}" "Phong" "404.tga"\n` + "COLOR 0.000000 0.000000 0.000000 1.000000\n" + "TRANSPARENCY 0.000000 0.000000 0.000000 1.000000\n" + "AMBIENTCOLOR 0.000000 0.000000 0.000000 1.000000\n" + "INCANDESCENCE 0.000000 0.000000 0.000000 1.000000\n" + "COEFFS 0.800000 0.000000\n" + "GLOW 0.000000 0\n" + "REFRACTIVE 6 1.000000\n" + "SPECULARCOLOR -1.000000 -1.000000 -1.000000 1.000000\n" + "REFLECTIVECOLOR -1.000000 -1.000000 -1.000000 1.000000\n" + "REFLECTIVE -1 1.000000\n" + "BLINN -1.000000 -1.000000\n" + "PHONG -1.000000\n\n"; } return result; }