MeshGeometry* CmodLoader::loadMesh() { char headerData[16]; if (m_inputStream->readRawData(headerData, sizeof(headerData)) != sizeof(headerData)) { setError("Error reading header"); return NULL; } QString header = QString::fromLatin1(headerData, sizeof(headerData)); if (header == "#celmodel__ascii") { setError("ASCII cmod files are not supported"); return NULL; } else if (header != "#celmodel_binary") { setError("Wrong header; file is not a cmod mesh file"); return NULL; } MeshGeometry* mesh = new MeshGeometry(); // Add the default material Material* defaultMaterial = new Material(); defaultMaterial->setDiffuse(Spectrum::Flat(0.8f)); defaultMaterial->setBrdf(Material::Lambert); mesh->addMaterial(defaultMaterial); bool done = false; unsigned int meshCount = 0; while (!done && !error()) { CmodToken token = readCmodToken(); if (m_inputStream->atEnd()) { done = true; } else if (token == CmodMaterial) { if (meshCount > 0) { setError("Materials must be appear before any meshes"); } Material* material = loadMaterial(); if (material) { mesh->addMaterial(material); } } else if (token == CmodMesh) { Submesh* submesh = loadSubmesh(); if (submesh) { mesh->addSubmesh(submesh); } } else { setError("Unrecognized block in cmod (not a mesh or material)"); } } if (error()) { delete mesh; mesh = NULL; } return mesh; }
static MeshGeometry* Convert3DSMesh(Lib3dsFile* meshfile, TextureMapLoader* textureLoader) { MeshGeometry* meshGeometry = new MeshGeometry(); for (int materialIndex = 0; materialIndex < meshfile->nmaterials; ++materialIndex) { Lib3dsMaterial* material = meshfile->materials[materialIndex]; Material* vmaterial = new Material(); // Convert a 3ds material to VESTA material vmaterial->setOpacity(1.0f - material->transparency); vmaterial->setDiffuse(Spectrum(material->diffuse)); if (material->shininess != 0.0f) { vmaterial->setSpecular(Spectrum(material->specular)); vmaterial->setPhongExponent(std::pow(2.0f, 1.0f + 10.0f * material->shininess)); } if (material->self_illum_flag) { vmaterial->setEmission(vmaterial->diffuse() * material->self_illum); } const string baseTextureName(material->texture1_map.name); if (!baseTextureName.empty()) { TextureProperties texProperties; if ((material->texture1_map.flags & LIB3DS_TEXTURE_NO_TILE) != 0) { texProperties.addressS = TextureProperties::Clamp; texProperties.addressT = TextureProperties::Clamp; } if (textureLoader) { TextureMap* baseTexture = textureLoader->loadTexture(baseTextureName, texProperties); vmaterial->setBaseTexture(baseTexture); } } meshGeometry->addMaterial(vmaterial); } for (int meshIndex = 0; meshIndex < meshfile->nmeshes; ++meshIndex) { Lib3dsMesh* mesh = meshfile->meshes[meshIndex]; if (mesh->nfaces > 0) { bool hasTextureCoords = mesh->texcos != 0; // Generate normals for the mesh float* normals = new float[mesh->nfaces * 9]; lib3ds_mesh_calculate_vertex_normals(mesh, (float(*)[3]) normals); VertexPool vertexPool; for (int faceIndex = 0; faceIndex < mesh->nfaces; ++faceIndex) { for (int i = 0; i < 3; i++) { int vertexIndex = mesh->faces[faceIndex].index[i]; vertexPool.addVec3(mesh->vertices[vertexIndex]); vertexPool.addVec3(&normals[(faceIndex * 3 + i) * 3]); if (hasTextureCoords) { // Invert the v texture coordinate, since 3ds uses a texture // coordinate system that is flipped with respect to OpenGL's vertexPool.addVec2(mesh->texcos[vertexIndex][0], 1.0f - mesh->texcos[vertexIndex][1]); } } } delete[] normals; const VertexSpec* vertexSpec = hasTextureCoords ? &VertexSpec::PositionNormalTex : &VertexSpec::PositionNormal; VertexArray* vertexArray = vertexPool.createVertexArray(mesh->nfaces * 3, *vertexSpec); PrimitiveBatch* batch = new PrimitiveBatch(PrimitiveBatch::Triangles, mesh->nfaces); // Get the material for the primitive batch // TODO: This assumes that a single material is applied to the whole mesh; however, // materials can be assigned per-face (but rarely are in most 3ds files.) unsigned int materialIndex = Submesh::DefaultMaterialIndex; if (mesh->nfaces > 0) { // Use the material of the first face materialIndex = mesh->faces[0].material; } Submesh* submesh = new Submesh(vertexArray); submesh->addPrimitiveBatch(batch, materialIndex); meshGeometry->addSubmesh(submesh); } } return meshGeometry; }