// ---------------------------------------------------------------------------- CMeshBuffer<S3DVertex2TCoords>* Terrain::build(path p) { IrrlichtDevice* device = Editor::getEditor()->getDevice(); CMeshBuffer<S3DVertex2TCoords>* mb = new CMeshBuffer<S3DVertex2TCoords>(); mb->Vertices.reallocate(m_mesh.vertex_count); mb->Indices.reallocate(m_mesh.quad_count * 6); for (u32 i = 0; i < m_mesh.vertex_count; i++) mb->Vertices.push_back(m_mesh.vertices[i]); for (u32 i = 0; i < m_mesh.quad_count * 6; i++) mb->Indices.push_back(m_mesh.indices[i]); mb->recalculateBoundingBox(); mb->Material = m_material; ITexture* texture = m_material.getTexture(1); IImage* image = device->getVideoDriver()->createImage(texture, position2di(0, 0), texture->getSize()); stringc name = p + "/splatt.png"; device->getVideoDriver()->writeImageToFile(image, name.c_str()); image->drop(); return mb; } // build
IAnimatedMesh* CMY3DMeshFileLoader::createMesh(io::IReadFile* file) { MaterialEntry.clear(); MeshBufferEntry.clear(); ChildNodes.clear(); // working directory (from which we load the scene) core::stringc filepath = FileSystem->getFileDir(file->getFileName()); if (filepath==".") filepath=""; else filepath.append("/"); // read file into memory SMyFileHeader fileHeader; file->read(&fileHeader, sizeof(SMyFileHeader)); #ifdef __BIG_ENDIAN__ fileHeader.MyId = os::Byteswap::byteswap(fileHeader.MyId); fileHeader.Ver = os::Byteswap::byteswap(fileHeader.Ver); #endif if (fileHeader.MyId!=MY3D_ID || fileHeader.Ver!=MY3D_VER) { os::Printer::log("Bad MY3D file header, loading failed!", ELL_ERROR); return 0; } u16 id; file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_SCENE_HEADER_ID) { os::Printer::log("Cannot find MY3D_SCENE_HEADER_ID, loading failed!", ELL_ERROR); return 0; } SMySceneHeader sceneHeader; file->read(&sceneHeader, sizeof(SMySceneHeader)); #ifdef __BIG_ENDIAN__ sceneHeader.MaterialCount = os::Byteswap::byteswap(sceneHeader.MaterialCount); sceneHeader.MeshCount = os::Byteswap::byteswap(sceneHeader.MeshCount); #endif file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_MAT_LIST_ID) { os::Printer::log("Can not find MY3D_MAT_LIST_ID, loading failed!", ELL_ERROR); return 0; } core::stringc texturePath = SceneManager->getParameters()->getAttributeAsString(MY3D_TEXTURE_PATH); file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif c8 namebuf[256]; for (s32 m=0; m<sceneHeader.MaterialCount; ++m) { if (id != MY3D_MAT_HEADER_ID) { os::Printer::log("Cannot find MY3D_MAT_HEADER_ID, loading failed!", ELL_ERROR); return 0; } // read material header MaterialEntry.push_back(SMyMaterialEntry()); SMyMaterialEntry& me=MaterialEntry.getLast(); file->read(&(me.Header), sizeof(SMyMaterialHeader)); // read next identificator file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif bool gotLightMap=false, gotMainMap=false; for (u32 t=0; t<me.Header.TextureCount; ++t) { if (id==MY3D_TEX_FNAME_ID) file->read(namebuf, 256); else { me.Texture2 = readEmbeddedLightmap(file, namebuf); if (!me.Texture2) return 0; gotLightMap = true; } const core::stringc name(namebuf); const s32 pos = name.findLast('.'); const core::stringc LightingMapStr = "LightingMap"; const s32 ls = LightingMapStr.size(); const bool isSubString = (LightingMapStr == name.subString(core::max_(0, (pos - ls)), ls)); if ((isSubString || (name[pos-1]=='m' && name[pos-2]=='l' && name[pos-3]=='_')) && !gotLightMap) { const bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); me.Texture2FileName = texturePath.size() ? texturePath : filepath; me.Texture2FileName.append("Lightmaps/"); me.Texture2FileName.append(name); if (name.size()) me.Texture2 = SceneManager->getVideoDriver()->getTexture(me.Texture2FileName); me.MaterialType = video::EMT_LIGHTMAP_M2; gotLightMap = true; SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); } else if (!gotLightMap && gotMainMap) { me.Texture2FileName = texturePath.size() ? texturePath : filepath; me.Texture2FileName.append(name); if (name.size()) me.Texture2 = SceneManager->getVideoDriver()->getTexture(me.Texture2FileName); me.MaterialType = video::EMT_REFLECTION_2_LAYER; } else if (!gotMainMap && !gotLightMap) { me.Texture1FileName = filepath; me.Texture1FileName.append(name); if (name.size()) me.Texture1 = SceneManager->getVideoDriver()->getTexture(me.Texture1FileName); gotMainMap = true; me.MaterialType = video::EMT_SOLID; } else if (gotLightMap) { me.MaterialType = video::EMT_LIGHTMAP_M2; } file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif } // override material types based on their names if (!strncmp(me.Header.Name, "AlphaChannel-", 13)) me.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; else if (!strncmp(me.Header.Name, "SphereMap-", 10)) me.MaterialType = video::EMT_SPHERE_MAP; } // loading meshes if (id!=MY3D_MESH_LIST_ID) { os::Printer::log("Can not find MY3D_MESH_LIST_ID, loading failed!", ELL_ERROR); return 0; } file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif for (s32 mesh_id=0; mesh_id<sceneHeader.MeshCount; mesh_id++) { // Warning!!! In some cases MY3D exporter uncorrectly calculates // MeshCount (it's a problem, has to be solved) thats why // i added this code line if (id!=MY3D_MESH_HEADER_ID) break; if (id!=MY3D_MESH_HEADER_ID) { os::Printer::log("Can not find MY3D_MESH_HEADER_ID, loading failed!", ELL_ERROR); return 0; } SMyMeshHeader meshHeader; file->read(&meshHeader, sizeof(SMyMeshHeader)); core::array <SMyVertex> Vertex; core::array <SMyFace> Face; core::array <SMyTVertex> TVertex1, TVertex2; core::array <SMyFace> TFace1, TFace2; s32 vertsNum=0; s32 facesNum=0; // vertices file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_VERTS_ID) { os::Printer::log("Can not find MY3D_VERTS_ID, loading failed!", ELL_ERROR); return 0; } file->read(&vertsNum, sizeof(vertsNum)); Vertex.set_used(vertsNum); file->read(Vertex.pointer(), sizeof(SMyVertex)*vertsNum); // faces file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_FACES_ID) { os::Printer::log("Can not find MY3D_FACES_ID, loading failed!", ELL_ERROR); return 0; } file->read(&facesNum, sizeof(facesNum)); Face.set_used(facesNum); file->read(Face.pointer(), sizeof(SMyFace)*facesNum); // reading texture channels for (s32 tex=0; tex<(s32)meshHeader.TChannelCnt; tex++) { // Max 2 texture channels allowed (but in format .my3d can be more) s32 tVertsNum=0, tFacesNum=0; // reading texture coords file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_TVERTS_ID) { core::stringc msg="Can not find MY3D_TVERTS_ID ("; msg.append(core::stringc(tex)); msg.append("texture channel), loading failed!"); os::Printer::log(msg.c_str(), ELL_ERROR); return 0; } file->read(&tVertsNum, sizeof(tVertsNum)); if (tex==0) { // 1st texture channel TVertex1.set_used(tVertsNum); file->read(TVertex1.pointer(), sizeof(SMyTVertex)*tVertsNum); } else if (tex==1) { // 2nd texture channel TVertex2.set_used(tVertsNum); file->read(TVertex2.pointer(), sizeof(SMyTVertex)*tVertsNum); } else { // skip other texture channels file->seek(file->getPos()+sizeof(SMyTVertex)*tVertsNum); } // reading texture faces file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif if (id!=MY3D_TFACES_ID) { core::stringc msg="Can not find MY3D_TFACES_ID ("; msg.append(core::stringc(tex)); msg.append("texture channel), loading failed!"); os::Printer::log(msg.c_str(), ELL_ERROR); return 0; } file->read(&tFacesNum, sizeof(tFacesNum)); if (tex==0) { // 1st texture channel TFace1.set_used(tFacesNum); file->read(TFace1.pointer(), sizeof(SMyFace)*tFacesNum); } else if (tex==1) { // 2nd texture channel TFace2.set_used(tFacesNum); file->read(TFace2.pointer(), sizeof(SMyFace)*tFacesNum); } else { // skip other texture channels file->seek(file->getPos()+sizeof(SMyFace)*tFacesNum); } } // trying to find material SMyMaterialEntry* matEnt = getMaterialEntryByIndex(meshHeader.MatIndex); // creating geometry for the mesh // trying to find mesh buffer for this material CMeshBuffer<video::S3DVertex2TCoords>* buffer = getMeshBufferByMaterialIndex(meshHeader.MatIndex); if (!buffer || (buffer->getVertexBuffer()->getVertexCount()+vertsNum) > SceneManager->getVideoDriver()->getMaximalPrimitiveCount()) { // creating new mesh buffer for this material buffer = new CMeshBuffer<video::S3DVertex2TCoords>(SceneManager->getVideoDriver()->getVertexDescriptor(1)); buffer->Material.MaterialType = video::EMT_LIGHTMAP_M2; // EMT_LIGHTMAP_M4 also possible buffer->Material.Wireframe = false; buffer->Material.Lighting = false; if (matEnt) { buffer->Material.MaterialType = matEnt->MaterialType; if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER) { buffer->Material.Lighting = true; buffer->Material.setTexture(1, matEnt->Texture1); buffer->Material.setTexture(0, matEnt->Texture2); } else { buffer->Material.setTexture(0, matEnt->Texture1); buffer->Material.setTexture(1, matEnt->Texture2); } if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) { buffer->Material.BackfaceCulling = true; buffer->Material.Lighting = true; } else if (buffer->Material.MaterialType == video::EMT_SPHERE_MAP) { buffer->Material.Lighting = true; } buffer->Material.AmbientColor = video::SColor( matEnt->Header.AmbientColor.A, matEnt->Header.AmbientColor.R, matEnt->Header.AmbientColor.G, matEnt->Header.AmbientColor.B ); buffer->Material.DiffuseColor = video::SColor( matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R, matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B ); buffer->Material.EmissiveColor = video::SColor( matEnt->Header.EmissiveColor.A, matEnt->Header.EmissiveColor.R, matEnt->Header.EmissiveColor.G, matEnt->Header.EmissiveColor.B ); buffer->Material.SpecularColor = video::SColor( matEnt->Header.SpecularColor.A, matEnt->Header.SpecularColor.R, matEnt->Header.SpecularColor.G, matEnt->Header.SpecularColor.B ); } else { buffer->Material.setTexture(0, 0); buffer->Material.setTexture(1, 0); buffer->Material.AmbientColor = video::SColor(255, 255, 255, 255); buffer->Material.DiffuseColor = video::SColor(255, 255, 255, 255); buffer->Material.EmissiveColor = video::SColor(0, 0, 0, 0); buffer->Material.SpecularColor = video::SColor(0, 0, 0, 0); } if (matEnt && matEnt->Header.Transparency!=0) { if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER ) { buffer->Material.MaterialType = video::EMT_TRANSPARENT_REFLECTION_2_LAYER; buffer->Material.Lighting = true; buffer->Material.BackfaceCulling = true; } else { buffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; buffer->Material.Lighting = false; buffer->Material.BackfaceCulling = false; } } else if ( !buffer->Material.getTexture(1) && buffer->Material.MaterialType != video::EMT_TRANSPARENT_ALPHA_CHANNEL && buffer->Material.MaterialType != video::EMT_SPHERE_MAP) { buffer->Material.MaterialType = video::EMT_SOLID; buffer->Material.Lighting = true; } MeshBufferEntry.push_back( SMyMeshBufferEntry(meshHeader.MatIndex, buffer)); } video::S3DVertex2TCoords VertexA, VertexB, VertexC; // vertices (A, B, C) color video::SColor vert_color; if (matEnt && (buffer->Material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA || buffer->Material.MaterialType == video::EMT_TRANSPARENT_REFLECTION_2_LAYER)) { video::SColor color( matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R, matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B); vert_color = color.getInterpolated(video::SColor(0,0,0,0), 1-matEnt->Header.Transparency); } else { vert_color = buffer->Material.DiffuseColor; } VertexA.Color = VertexB.Color = VertexC.Color = vert_color; if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) { buffer->getIndexBuffer()->reallocate(buffer->getIndexBuffer()->getIndexCount()+6*facesNum); buffer->getVertexBuffer()->reallocate(buffer->getVertexBuffer()->getVertexCount()+6*facesNum); } else { buffer->getIndexBuffer()->reallocate(buffer->getIndexBuffer()->getIndexCount()+3*facesNum); buffer->getVertexBuffer()->reallocate(buffer->getVertexBuffer()->getVertexCount()+3*facesNum); } for (int f=0; f<facesNum; f++) { // vertex A VertexA.Pos.X = Vertex[Face[f].C].Coord.X; VertexA.Pos.Y = Vertex[Face[f].C].Coord.Y; VertexA.Pos.Z = Vertex[Face[f].C].Coord.Z; VertexA.Normal.X = Vertex[Face[f].C].Normal.X; VertexA.Normal.Y = Vertex[Face[f].C].Normal.Y; VertexA.Normal.Z = Vertex[Face[f].C].Normal.Z; if (meshHeader.TChannelCnt>0) { VertexA.TCoords.X = TVertex1[TFace1[f].C].TCoord.X; VertexA.TCoords.Y = TVertex1[TFace1[f].C].TCoord.Y; } if (meshHeader.TChannelCnt>1) { VertexA.TCoords2.X = TVertex2[TFace2[f].C].TCoord.X; VertexA.TCoords2.Y = TVertex2[TFace2[f].C].TCoord.Y; } // vertex B VertexB.Pos.X = Vertex[Face[f].B].Coord.X; VertexB.Pos.Y = Vertex[Face[f].B].Coord.Y; VertexB.Pos.Z = Vertex[Face[f].B].Coord.Z; VertexB.Normal.X = Vertex[Face[f].B].Normal.X; VertexB.Normal.Y = Vertex[Face[f].B].Normal.Y; VertexB.Normal.Z = Vertex[Face[f].B].Normal.Z; if (meshHeader.TChannelCnt>0) { VertexB.TCoords.X = TVertex1[TFace1[f].B].TCoord.X; VertexB.TCoords.Y = TVertex1[TFace1[f].B].TCoord.Y; } if (meshHeader.TChannelCnt>1) { VertexB.TCoords2.X = TVertex2[TFace2[f].B].TCoord.X; VertexB.TCoords2.Y = TVertex2[TFace2[f].B].TCoord.Y; } // vertex C VertexC.Pos.X = Vertex[Face[f].A].Coord.X; VertexC.Pos.Y = Vertex[Face[f].A].Coord.Y; VertexC.Pos.Z = Vertex[Face[f].A].Coord.Z; VertexC.Normal.X = Vertex[Face[f].A].Normal.X; VertexC.Normal.Y = Vertex[Face[f].A].Normal.Y; VertexC.Normal.Z = Vertex[Face[f].A].Normal.Z; if (meshHeader.TChannelCnt>0) { VertexC.TCoords.X = TVertex1[TFace1[f].A].TCoord.X; VertexC.TCoords.Y = TVertex1[TFace1[f].A].TCoord.Y; } if (meshHeader.TChannelCnt>1) { VertexC.TCoords2.X = TVertex2[TFace2[f].A].TCoord.X; VertexC.TCoords2.Y = TVertex2[TFace2[f].A].TCoord.Y; } // store 3d data in mesh buffer buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexA); buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexB); buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexC); //***************************************************************** // !!!!!! W A R N I N G !!!!!!! //***************************************************************** // For materials with alpha channel we duplicate all faces. // This has be done for proper lighting calculation of the back faces. // So you must remember this while you creating your models !!!!! //***************************************************************** // !!!!!! W A R N I N G !!!!!!! //***************************************************************** if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) { VertexA.Normal = core::vector3df(-VertexA.Normal.X, -VertexA.Normal.Y, -VertexA.Normal.Z); VertexB.Normal = core::vector3df(-VertexB.Normal.X, -VertexB.Normal.Y, -VertexB.Normal.Z); VertexC.Normal = core::vector3df(-VertexC.Normal.X, -VertexC.Normal.Y, -VertexC.Normal.Z); buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexC); buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexB); buffer->getIndexBuffer()->addIndex(buffer->getVertexBuffer()->getVertexCount()); buffer->getVertexBuffer()->addVertex(&VertexA); } } file->read(&id, sizeof(id)); #ifdef __BIG_ENDIAN__ id = os::Byteswap::byteswap(id); #endif } // creating mesh SMesh* mesh = new SMesh(); for (u32 num=0; num<MeshBufferEntry.size(); ++num) { CMeshBuffer<video::S3DVertex2TCoords>* buffer = MeshBufferEntry[num].MeshBuffer; if (!buffer) continue; mesh->addMeshBuffer(buffer); buffer->recalculateBoundingBox(); buffer->drop(); } mesh->recalculateBoundingBox(); if (id != MY3D_FILE_END_ID) os::Printer::log("Loading finished, but can not find MY3D_FILE_END_ID token.", ELL_WARNING); SAnimatedMesh* am = new SAnimatedMesh(); am->addMesh(mesh); mesh->drop(); am->recalculateBoundingBox(); return am; }