import { Mesh } from './' import { MeshInstance, MultiMeshInstance } from '../components' import { Material } from './material' import { mat4 } from 'gl-matrix' import Resource from '../resource' let meshCache = {} // Parse an assimp2json formatted mesh file // Supports multiple geometries async function assimp2json (gl, file, dat, pos) { let cleaned = [] let materials = [] for (let mi in dat.meshes) { let mesh = dat.meshes[mi] let material if (mesh.materialindex != null && dat.materials && dat.materials.length) { // Ensure we don't re-create materials with the same index if (materials[mesh.materialindex]) { material = materials[mesh.materialindex] } else { // Load a new material material = new Material() let matdata = dat.materials[mesh.materialindex].properties // Parse material information for (let pi in matdata) { let property = matdata[pi] if (!property || !property.key) continue if (property.key === '?mat.name') material.name = property.value else if (property.key.indexOf('$clr.') === 0) { let dproperty = property.key.substr(5) switch (dproperty) { case 'specular': case 'diffuse': case 'shininess': case 'ambient': case 'reflective': material[dproperty] = property.value break } } else if (property.key.indexOf('$tex.file') === 0) { if (!material.textures) { material.textures = [] } material.textures.push(property.value) } } materials[mesh.materialindex] = material } } cleaned.push({ vertices: mesh.vertices, indices: [].concat.apply([], mesh.faces), uv: mesh.texturecoords ? mesh.texturecoords[0] : null, normals: mesh.normals ? mesh.normals : null, material }) } // Load everything let loadComplete = [] for (let i in cleaned) { let meshdata = cleaned[i] let mesh = Mesh.construct(gl, meshdata.vertices, meshdata.indices, meshdata.uv, meshdata.normals) // Initialize the material's texture if present if (meshdata.material) { mesh.material = meshdata.material // Ensure all textures get loaded before finishing if (meshdata.material.textures) { await meshdata.material.loadTextures(gl) } } loadComplete.push(mesh) } let finished = [] function setChildren (parent, chMeshes, last) { if (!chMeshes.meshes) { if (chMeshes.children) { for (let j in chMeshes.children) { setChildren(null, chMeshes.children[j], chMeshes) } } return } // Transpose the mesh's transform let transform = chMeshes.transformation let meshIndex = chMeshes.meshes[0] let mesh = loadComplete[meshIndex] let meshInstance = new MeshInstance(mesh, parent == null ? pos : null) meshInstance.mesh = mesh if (chMeshes.children) { for (let i in chMeshes.children) { if (!chMeshes.children[i].meshes) continue setChildren(meshInstance, chMeshes.children[i], chMeshes) } } meshInstance.name = chMeshes.name if (parent == null) { // Multiply the last meshless node's transform in order to preserve it finished.push(meshInstance) } else { parent.children.push(meshInstance) meshInstance.parent = parent } meshInstance.setTransformation(transform) } setChildren(null, dat.rootnode) if (!finished.length) throw new Error('Failed to build mesh.') // Cache the mesh meshCache[file] = finished let returnType if (finished.length > 1) { returnType = new MultiMeshInstance(finished) } else { returnType = finished[0] } return returnType } // Parse a collada mesh async function collada (gl, file, dat, pos) { // TODO... } async function loadMesh (gl, file, pos) { file = '/assets/models/' + file + '.json' // Ensure each mesh file is loaded only once if (meshCache[file]) return meshCache[file].length > 1 ? new MultiMeshInstance(meshCache[file], pos) : meshCache[file][0] let dat = await Resource.GET({ type: 'json', url: file }) // Recognize a assimp2json file format if (dat['__metadata__'] && dat['__metadata__'].format === 'assimp2json') { if (!dat.meshes) throw new Error('No geometries found in file ' + file) return assimp2json(gl, file, dat, pos) } throw new Error('Unsupported mesh format.') } export default loadMesh