//! Creates/loads an animated mesh from the file. IAnimatedMesh* CSMFMeshFileLoader::createMesh(io::IReadFile* file) { // create empty mesh SMesh *mesh = new SMesh(); // load file u16 version; u8 flags; s32 limbCount; s32 i; io::BinaryFile::read(file, version); io::BinaryFile::read(file, flags); io::BinaryFile::read(file, limbCount); // load mesh data core::matrix4 identity; for (i=0; i < limbCount; ++i) loadLimb(file, mesh, identity); // recalculate buffer bounding boxes for (i=0; i < (s32)mesh->getMeshBufferCount(); ++i) mesh->getMeshBuffer(i)->recalculateBoundingBox(); mesh->recalculateBoundingBox(); SAnimatedMesh *am = new SAnimatedMesh(); am->addMesh(mesh); mesh->drop(); am->recalculateBoundingBox(); return am; }
//! reads a mesh sections and creates a mesh from it IAnimatedMesh* CIrrMeshFileLoader::readMesh(io::IXMLReader* reader) { SAnimatedMesh* animatedmesh = new SAnimatedMesh(); SMesh* mesh = new SMesh(); animatedmesh->addMesh(mesh); mesh->drop(); core::stringc bbSectionName = "boundingBox"; core::stringc bufferSectionName = "buffer"; core::stringc meshSectionName = "mesh"; if (!reader->isEmptyElement()) while(reader->read()) { if (reader->getNodeType() == io::EXN_ELEMENT) { const wchar_t* nodeName = reader->getNodeName(); if (bbSectionName == nodeName) { // inside a bounding box, ignore it for now because // we are calculating this anyway ourselves later. } else if (bufferSectionName == nodeName) { // we've got a mesh buffer IMeshBuffer* buffer = readMeshBuffer(reader); if (buffer) { mesh->addMeshBuffer(buffer); buffer->drop(); } } else skipSection(reader, true); // unknown section } // end if node type is element else if (reader->getNodeType() == io::EXN_ELEMENT_END) { if (meshSectionName == reader->getNodeName()) { // end of mesh section reached, cancel out break; } } } // end while reader->read(); mesh->recalculateBoundingBox(); animatedmesh->recalculateBoundingBox(); return animatedmesh; }
//! creates/loads an animated mesh from the file. IAnimatedMesh* CCSMLoader::createMesh(io::IReadFile* file) { scene::IMesh* m = createCSMMesh(file); if (!m) return 0; SAnimatedMesh* am = new SAnimatedMesh(); am->Type = EAMT_CSM; am->addMesh(m); m->drop(); am->recalculateBoundingBox(); return am; }
//! creates/loads an animated mesh from the file. IAnimatedMesh* CCSMLoader::createMesh(io::IReadFile* file) { file->grab(); // originally, this loader created the file on its own. scene::IMesh* m = createCSMMesh(file); if (!m) return 0; SAnimatedMesh* am = new SAnimatedMesh(); am->Type = EAMT_CSM; am->addMesh(m); m->drop(); am->recalculateBoundingBox(); return am; }
IAnimatedMesh* CLMTSMeshFileLoader::createMesh(io::IReadFile* file) { u32 i; u32 id; // HEADER file->read(&Header, sizeof(SLMTSHeader)); if (Header.MagicID == 0x4C4D5354) { FlipEndianess = true; Header.MagicID = os::Byteswap::byteswap(Header.MagicID); Header.Version = os::Byteswap::byteswap(Header.Version); Header.HeaderSize = os::Byteswap::byteswap(Header.HeaderSize); Header.TextureCount = os::Byteswap::byteswap(Header.TextureCount); Header.SubsetCount = os::Byteswap::byteswap(Header.SubsetCount); Header.TriangleCount = os::Byteswap::byteswap(Header.TriangleCount); Header.SubsetSize = os::Byteswap::byteswap(Header.SubsetSize); Header.VertexSize = os::Byteswap::byteswap(Header.VertexSize); } if (Header.MagicID != 0x53544D4C) { // "LMTS" os::Printer::log("LMTS ERROR: wrong header magic id!", ELL_ERROR); return 0; } //Skip any User Data (arbitrary app specific data) const s32 userSize = Header.HeaderSize - sizeof(SLMTSHeader); if (userSize>0) file->seek(userSize,true); // TEXTURES file->read(&id, sizeof(u32)); if (FlipEndianess) id = os::Byteswap::byteswap(id); if (id != 0x54584554) { // "TEXT" os::Printer::log("LMTS ERROR: wrong texture magic id!", ELL_ERROR); return 0; } Textures = new SLMTSTextureInfoEntry[Header.TextureCount]; file->read(Textures, sizeof(SLMTSTextureInfoEntry)*Header.TextureCount); if (FlipEndianess) { for (i=0; i<Header.TextureCount; ++i) Textures[i].Flags = os::Byteswap::byteswap(Textures[i].Flags); } // SUBSETS file->read(&id, sizeof(u32)); if (FlipEndianess) id = os::Byteswap::byteswap(id); if (id != 0x53425553) // "SUBS" { os::Printer::log("LMTS ERROR: wrong subset magic id!", ELL_ERROR); cleanup(); return 0; } Subsets = new SLMTSSubsetInfoEntry[Header.SubsetCount]; const s32 subsetUserSize = Header.SubsetSize - sizeof(SLMTSSubsetInfoEntry); for (i=0; i<Header.SubsetCount; ++i) { file->read(&Subsets[i], sizeof(SLMTSSubsetInfoEntry)); if (FlipEndianess) { Subsets[i].Offset = os::Byteswap::byteswap(Subsets[i].Offset); Subsets[i].Count = os::Byteswap::byteswap(Subsets[i].Count); Subsets[i].TextID1 = os::Byteswap::byteswap(Subsets[i].TextID1); Subsets[i].TextID2 = os::Byteswap::byteswap(Subsets[i].TextID2); } if (subsetUserSize>0) file->seek(subsetUserSize,true); } // TRIANGLES file->read(&id, sizeof(u32)); if (FlipEndianess) id = os::Byteswap::byteswap(id); if (id != 0x53495254) // "TRIS" { os::Printer::log("LMTS ERROR: wrong triangle magic id!", ELL_ERROR); cleanup(); return 0; } Triangles = new SLMTSTriangleDataEntry[(Header.TriangleCount*3)]; const s32 triUserSize = Header.VertexSize - sizeof(SLMTSTriangleDataEntry); for (i=0; i<(Header.TriangleCount*3); ++i) { file->read(&Triangles[i], sizeof(SLMTSTriangleDataEntry)); if (FlipEndianess) { Triangles[i].X = os::Byteswap::byteswap(Triangles[i].X); Triangles[i].Y = os::Byteswap::byteswap(Triangles[i].Y); Triangles[i].Z = os::Byteswap::byteswap(Triangles[i].Z); Triangles[i].U1 = os::Byteswap::byteswap(Triangles[i].U1); Triangles[i].V1 = os::Byteswap::byteswap(Triangles[i].U2); Triangles[i].U2 = os::Byteswap::byteswap(Triangles[i].V1); Triangles[i].V2 = os::Byteswap::byteswap(Triangles[i].V2); } if (triUserSize>0) file->seek(triUserSize,true); } ///////////////////////////////////////////////////////////////// SMesh* mesh = new SMesh(); constructMesh(mesh); loadTextures(mesh); cleanup(); SAnimatedMesh* am = new SAnimatedMesh(); am->Type = EAMT_LMTS; // not unknown to irrlicht anymore am->addMesh(mesh); am->recalculateBoundingBox(); mesh->drop(); return am; }
//! creates/loads an animated mesh from the file. //! \return Pointer to the created mesh. Returns 0 if loading failed. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! See IReferenceCounted::drop() for more information. IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) { const long filesize = file->getSize(); if (filesize < 6) // we need a header return 0; const u32 WORD_BUFFER_LENGTH = 512; SMesh* mesh = new SMesh(); SMeshBuffer* meshBuffer = new SMeshBuffer(); mesh->addMeshBuffer(meshBuffer); meshBuffer->drop(); core::vector3df vertex[3]; core::vector3df normal; c8 buffer[WORD_BUFFER_LENGTH]; bool binary = false; file->read(buffer, 5); if (strncmp("solid", buffer, 5)) binary = true; // read/skip header u32 binFaceCount = 0; if (binary) { file->seek(80); file->read(&binFaceCount, 4); #ifdef __BIG_ENDIAN__ binFaceCount = os::Byteswap::byteswap(binFaceCount); #endif } else goNextLine(file); u16 attrib=0; core::stringc token; token.reserve(32); while (file->getPos() < filesize) { if (!binary) { if (getNextToken(file, token) != "facet") { if (token=="endsolid") break; mesh->drop(); return 0; } if (getNextToken(file, token) != "normal") { mesh->drop(); return 0; } } getNextVector(file, normal, binary); if (!binary) { if (getNextToken(file, token) != "outer") { mesh->drop(); return 0; } if (getNextToken(file, token) != "loop") { mesh->drop(); return 0; } } for (u32 i=0; i<3; ++i) { if (!binary) { if (getNextToken(file, token) != "vertex") { mesh->drop(); return 0; } } getNextVector(file, vertex[i], binary); } if (!binary) { if (getNextToken(file, token) != "endloop") { mesh->drop(); return 0; } if (getNextToken(file, token) != "endfacet") { mesh->drop(); return 0; } } else { file->read(&attrib, 2); #ifdef __BIG_ENDIAN__ attrib = os::Byteswap::byteswap(attrib); #endif } SMeshBuffer* mb = reinterpret_cast<SMeshBuffer*>(mesh->getMeshBuffer(mesh->getMeshBufferCount()-1)); u32 vCount = mb->getVertexCount(); video::SColor color(0xffffffff); if (attrib & 0x8000) color = video::A1R5G5B5toA8R8G8B8(attrib); if (normal==core::vector3df()) normal=core::plane3df(vertex[2],vertex[1],vertex[0]).Normal; mb->Vertices.push_back(video::S3DVertex(vertex[2],normal,color, core::vector2df())); mb->Vertices.push_back(video::S3DVertex(vertex[1],normal,color, core::vector2df())); mb->Vertices.push_back(video::S3DVertex(vertex[0],normal,color, core::vector2df())); mb->Indices.push_back(vCount); mb->Indices.push_back(vCount+1); mb->Indices.push_back(vCount+2); } // end while (file->getPos() < filesize) mesh->getMeshBuffer(0)->recalculateBoundingBox(); // Create the Animated mesh if there's anything in the mesh SAnimatedMesh* pAM = 0; if ( 0 != mesh->getMeshBufferCount() ) { mesh->recalculateBoundingBox(); pAM = new SAnimatedMesh(); pAM->Type = EAMT_OBJ; pAM->addMesh(mesh); pAM->recalculateBoundingBox(); } mesh->drop(); return pAM; }
GLlink(ISceneNode *i_parent, ISceneManager *i_mgr, s32 i_id, const LinkInfo &i_li, BodyInfo_var i_binfo) : ISceneNode(i_parent, i_mgr, i_id), m_jointId(i_li.jointId) { setAutomaticCulling(scene::EAC_OFF); setPosition(vector3df( i_li.translation[0], -i_li.translation[1], i_li.translation[2])); Vector3 axis(i_li.rotation[0], i_li.rotation[1], i_li.rotation[2]); Matrix33 R; hrp::calcRodrigues(R, axis, i_li.rotation[3]); Vector3 rpy(rpyFromRot(R)); //std::cout << "rpy:" << rpy << std::endl; setRotation(vector3df(-180/M_PI*rpy[0], 180/M_PI*rpy[1], -180/M_PI*rpy[2])); m_axis << i_li.jointAxis[0], i_li.jointAxis[1], i_li.jointAxis[2]; ShapeInfoSequence_var sis = i_binfo->shapes(); AppearanceInfoSequence_var ais = i_binfo->appearances(); MaterialInfoSequence_var mis = i_binfo->materials(); TextureInfoSequence_var txs = i_binfo->textures(); const TransformedShapeIndexSequence& tsis = i_li.shapeIndices; core::vector3df vertex; core::vector3df normal; for (unsigned int l=0; l<tsis.length(); l++) { SMesh* mesh = new SMesh(); SMeshBuffer* meshBuffer = new SMeshBuffer(); mesh->addMeshBuffer(meshBuffer); meshBuffer->drop(); const TransformedShapeIndex &tsi = tsis[l]; short index = tsi.shapeIndex; ShapeInfo& si = sis[index]; const float *vertices = si.vertices.get_buffer(); const LongSequence& triangles = si.triangles; const AppearanceInfo& ai = ais[si.appearanceIndex]; const float *normals = ai.normals.get_buffer(); //std::cout << "length of normals = " << ai.normals.length() << std::endl; const LongSequence& normalIndices = ai.normalIndices; //std::cout << "length of normalIndices = " << normalIndices.length() << std::endl; const int numTriangles = triangles.length() / 3; //std::cout << "numTriangles = " << numTriangles << std::endl; video::SColor color(0xffffffff); if (ai.colors.length()) { color.set(0xff, 0xff*ai.colors[0], 0xff*ai.colors[1], 0xff*ai.colors[2]); } else if (ai.materialIndex >= 0) { const MaterialInfo& mi = mis[ai.materialIndex]; color.set(0xff, 0xff*mi.diffuseColor[0], 0xff*mi.diffuseColor[1], 0xff*mi.diffuseColor[2]); } else { std::cout << "no material" << std::endl; } SMeshBuffer* mb = reinterpret_cast<SMeshBuffer*>(mesh->getMeshBuffer(mesh->getMeshBufferCount()-1)); u32 vCount = mb->getVertexCount(); const DblArray12& tfm = tsi.transformMatrix; CMatrix4<f32> cmat; for (int i=0; i<3; i++) { for (int j=0; j<4; j++) { cmat[j*4+i] = tfm[i*4+j]; } } cmat[3] = cmat[7] = cmat[11] = 0.0; cmat[15] = 1.0; vector3df pos = cmat.getTranslation(); pos.Y *= -1; vector3df rpy = cmat.getRotationDegrees(); rpy.X *= -1; rpy.Z *= -1; vector3df scale = cmat.getScale(); const float *textureCoordinate = NULL; if (ai.textureIndex >= 0) { textureCoordinate = ai.textureCoordinate.get_buffer(); //std::cout << "length of textureCoordinate:" << ai.textureCoordinate.length() << std::endl; //std::cout << "length of vertices:" << si.vertices.length() << std::endl; } for(int j=0; j < numTriangles; ++j) { if (!ai.normalPerVertex) { int p; if (normalIndices.length() == 0) { p = j*3; } else { p = normalIndices[j]*3; } if ( normals != NULL ) { normal.X = normals[p]; normal.Y = -normals[p+1]; //left-handed->right-handed normal.Z = normals[p+2]; } else { normal.X = 0; normal.Y = 0; normal.Z = 1; } } for(int k=0; k < 3; ++k) { long orgVertexIndex = si.triangles[j * 3 + k]; if (ai.normalPerVertex) { int p; if (normalIndices.length()) { p = normalIndices[j*3+k]*3; } else { p = orgVertexIndex*3; } normal.X = normals[p]; normal.Y = -normals[p+1]; //left-handed -> right-handed normal.Z = normals[p+2]; } int p = orgVertexIndex * 3; vertex.X = scale.X*vertices[p]; vertex.Y = -scale.Y*vertices[p+1]; // left-handed -> right-handed vertex.Z = scale.Z*vertices[p+2]; //std::cout << vertices[p] <<"," << vertices[p+1] << "," << vertices[p+2] << std::endl; vector2df texc; if (textureCoordinate) { texc.X = textureCoordinate[ai.textureCoordIndices[j*3+k]*2]; texc.Y = textureCoordinate[ai.textureCoordIndices[j*3+k]*2+1]; } // redundant vertices mb->Vertices.push_back(video::S3DVertex(vertex,normal,color, texc)); } mb->Indices.push_back(vCount); mb->Indices.push_back(vCount+2); mb->Indices.push_back(vCount+1); vCount += 3; } mesh->getMeshBuffer(0)->recalculateBoundingBox(); // Create the Animated mesh if there's anything in the mesh SAnimatedMesh* pAM = 0; if ( 0 != mesh->getMeshBufferCount() ) { mesh->recalculateBoundingBox(); pAM = new SAnimatedMesh(); pAM->Type = EAMT_OBJ; pAM->addMesh(mesh); pAM->recalculateBoundingBox(); } mesh->drop(); vector3df noscale(1,1,1); IMeshSceneNode *node = i_mgr->addMeshSceneNode(mesh, this, -1, pos, rpy, noscale); if (ai.textureIndex >= 0) { const TextureInfo& ti = txs[ai.textureIndex]; //std::cout << "url:" << ti.url << std::endl; video::IVideoDriver* driver = i_mgr->getVideoDriver(); const char *path = ti.url; SMaterial& mat = node->getMaterial(0); ITexture *texture = driver->getTexture(path); mat.setTexture( 0, texture); } } const SensorInfoSequence& sensors = i_li.sensors; for (unsigned int i=0; i<sensors.length(); i++) { const SensorInfo& si = sensors[i]; std::string type(si.type); if (type == "Vision") { //std::cout << si.name << std::endl; ISceneNode *camera = i_mgr->addEmptySceneNode(this); camera->setName(si.name); camera->setPosition(vector3df( si.translation[0], -si.translation[1], si.translation[2])); Vector3 axis(si.rotation[0], si.rotation[1], si.rotation[2]); Matrix33 R; hrp::calcRodrigues(R, axis, si.rotation[3]); Vector3 rpy(rpyFromRot(R)); camera->setRotation(vector3df(-180/M_PI*rpy[0], 180/M_PI*rpy[1], -180/M_PI*rpy[2])); m_cameraInfos.push_back(new GLcamera(si, camera)); } } }
//! creates/loads an animated mesh from the file. //! \return Pointer to the created mesh. Returns 0 if loading failed. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! See IReferenceCounted::drop() for more information. IAnimatedMesh* COCTLoader::createMesh(io::IReadFile* file) { if (!file) return 0; octHeader header; file->read(&header, sizeof(octHeader)); octVert * verts = new octVert[header.numVerts]; octFace * faces = new octFace[header.numFaces]; octTexture * textures = new octTexture[header.numTextures]; octLightmap * lightmaps = new octLightmap[header.numLightmaps]; octLight * lights = new octLight[header.numLights]; file->read(verts, sizeof(octVert) * header.numVerts); file->read(faces, sizeof(octFace) * header.numFaces); //TODO: Make sure id is in the legal range for Textures and Lightmaps u32 i; for (i = 0; i < header.numTextures; i++) { octTexture t; file->read(&t, sizeof(octTexture)); textures[t.id] = t; } for (i = 0; i < header.numLightmaps; i++) { octLightmap t; file->read(&t, sizeof(octLightmap)); lightmaps[t.id] = t; } file->read(lights, sizeof(octLight) * header.numLights); //TODO: Now read in my extended OCT header (flexible lightmaps and vertex normals) // This is the method Nikolaus Gebhardt used in the Q3 loader -- create a // meshbuffer for every possible combination of lightmap and texture including // a "null" texture and "null" lightmap. Ones that end up with nothing in them // will be removed later. SMesh * Mesh = new SMesh(); for (i=0; i<(header.numTextures+1) * (header.numLightmaps+1); ++i) { scene::SMeshBufferLightMap* buffer = new scene::SMeshBufferLightMap(); buffer->Material.MaterialType = video::EMT_LIGHTMAP; buffer->Material.Lighting = false; Mesh->addMeshBuffer(buffer); buffer->drop(); } // Build the mesh buffers for (i = 0; i < header.numFaces; i++) { if (faces[i].numVerts < 3) continue; const f32* const a = verts[faces[i].firstVert].pos; const f32* const b = verts[faces[i].firstVert+1].pos; const f32* const c = verts[faces[i].firstVert+2].pos; const core::vector3df normal = core::plane3df(core::vector3df(a[0],a[1],a[2]), core::vector3df(b[0],c[1],c[2]), core::vector3df(c[0],c[1],c[2])).Normal; const u32 textureID = core::min_(s32(faces[i].textureID), s32(header.numTextures - 1)) + 1; const u32 lightmapID = core::min_(s32(faces[i].lightmapID),s32(header.numLightmaps - 1)) + 1; SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(lightmapID * (header.numTextures + 1) + textureID); const u32 base = meshBuffer->Vertices.size(); // Add this face's verts u32 v; for (v = 0; v < faces[i].numVerts; ++v) { octVert * vv = &verts[faces[i].firstVert + v]; video::S3DVertex2TCoords vert; vert.Pos.set(vv->pos[0], vv->pos[1], vv->pos[2]); vert.Color = video::SColor(0,255,255,255); vert.Normal.set(normal); if (textureID == 0) { // No texture -- just a lightmap. Thus, use lightmap coords for texture 1. // (the actual texture will be swapped later) vert.TCoords.set(vv->lc[0], vv->lc[1]); } else { vert.TCoords.set(vv->tc[0], vv->tc[1]); vert.TCoords2.set(vv->lc[0], vv->lc[1]); } meshBuffer->Vertices.push_back(vert); } // Now add the indices // This weird loop turns convex polygons into triangle strips. // I do it this way instead of a simple fan because it usually looks a lot better in wireframe, for example. // High, Low u32 h = faces[i].numVerts - 1; u32 l = 0; for (v = 0; v < faces[i].numVerts - 2; ++v) { const u32 center = (v & 1)? h - 1: l + 1; meshBuffer->Indices.push_back(base + h); meshBuffer->Indices.push_back(base + l); meshBuffer->Indices.push_back(base + center); if (v & 1) --h; else ++l; } } // load textures core::array<video::ITexture*> tex; tex.reallocate(header.numTextures + 1); tex.push_back(0); const core::stringc relpath = FileSystem->getFileDir(file->getFileName())+"/"; for (i = 1; i < (header.numTextures + 1); i++) { core::stringc path(textures[i-1].fileName); path.replace('\\','/'); if (FileSystem->existFile(path)) tex.push_back(SceneManager->getVideoDriver()->getTexture(path)); else // try to read in the relative path of the OCT file tex.push_back(SceneManager->getVideoDriver()->getTexture( (relpath + path) )); } // prepare lightmaps core::array<video::ITexture*> lig; lig.set_used(header.numLightmaps + 1); lig[0] = 0; const u32 lightmapWidth = 128; const u32 lightmapHeight = 128; const core::dimension2d<u32> lmapsize(lightmapWidth, lightmapHeight); bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); video::CImage tmpImage(video::ECF_R8G8B8, lmapsize); for (i = 1; i < (header.numLightmaps + 1); ++i) { core::stringc lightmapname = file->getFileName(); lightmapname += ".lightmap."; lightmapname += (int)i; const octLightmap* lm = &lightmaps[i-1]; for (u32 x=0; x<lightmapWidth; ++x) { for (u32 y=0; y<lightmapHeight; ++y) { tmpImage.setPixel(x, y, video::SColor(255, lm->data[x][y][2], lm->data[x][y][1], lm->data[x][y][0])); } } lig[i] = SceneManager->getVideoDriver()->addTexture(lightmapname.c_str(), &tmpImage); } SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); // Free stuff delete [] verts; delete [] faces; delete [] textures; delete [] lightmaps; delete [] lights; // attach materials for (i = 0; i < header.numLightmaps + 1; i++) { for (u32 j = 0; j < header.numTextures + 1; j++) { u32 mb = i * (header.numTextures + 1) + j; SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(mb); meshBuffer->Material.setTexture(0, tex[j]); meshBuffer->Material.setTexture(1, lig[i]); if (meshBuffer->Material.getTexture(0) == 0) { // This material has no texture, so we'll just show the lightmap if there is one. // We swapped the texture coordinates earlier. meshBuffer->Material.setTexture(0, meshBuffer->Material.getTexture(1)); meshBuffer->Material.setTexture(1, 0); } if (meshBuffer->Material.getTexture(1) == 0) { // If there is only one texture, it should be solid and lit. // Among other things, this way you can preview OCT lights. meshBuffer->Material.MaterialType = video::EMT_SOLID; meshBuffer->Material.Lighting = true; } } } // delete all buffers without geometry in it. i = 0; while(i < Mesh->MeshBuffers.size()) { if (Mesh->MeshBuffers[i]->getVertexCount() == 0 || Mesh->MeshBuffers[i]->getIndexCount() == 0 || Mesh->MeshBuffers[i]->getMaterial().getTexture(0) == 0) { // Meshbuffer is empty -- drop it Mesh->MeshBuffers[i]->drop(); Mesh->MeshBuffers.erase(i); } else { ++i; } } // create bounding box for (i = 0; i < Mesh->MeshBuffers.size(); ++i) { Mesh->MeshBuffers[i]->recalculateBoundingBox(); } Mesh->recalculateBoundingBox(); // Set up an animated mesh to hold the mesh SAnimatedMesh* AMesh = new SAnimatedMesh(); AMesh->Type = EAMT_OCT; AMesh->addMesh(Mesh); AMesh->recalculateBoundingBox(); Mesh->drop(); return AMesh; }
IAnimatedMesh* CLMTSMeshFileLoader::createMesh(irr::io::IReadFile* file) { u32 i; u32 id; // HEADER file->read(&Header, sizeof(SLMTSHeader)); if (Header.MagicID != 0x53544D4C) { // "LMTS" LMTS_LOG("LMTS ERROR: wrong header magic id!", ELL_ERROR); return 0; } // TEXTURES file->read(&id, sizeof(u32)); if (id != 0x54584554) { // "TEXT" LMTS_LOG("LMTS ERROR: wrong texture magic id!", ELL_ERROR); return 0; } Textures = new SLMTSTextureInfoEntry[Header.TextureCount]; TextureIDs = new u16[Header.TextureCount]; NumLightMaps = NumTextures = 0; for (i=0; i<Header.TextureCount; i++) { file->read(&Textures[i], sizeof(SLMTSTextureInfoEntry)); if (Textures[i].Flags & 1) { TextureIDs[i] = NumLightMaps; NumLightMaps++; } else { TextureIDs[i] = NumTextures; NumTextures++; } } // SUBSETS file->read(&id, sizeof(u32)); if (id != 0x53425553) { // "SUBS" LMTS_LOG("LMTS ERROR: wrong subset magic id!", ELL_ERROR); cleanup(); return 0; } Subsets = new SLMTSSubsetInfoEntry[Header.SubsetCount]; for (i=0; i<Header.SubsetCount; i++) { file->read(&Subsets[i], sizeof(SLMTSSubsetInfoEntry)); } // TRIANGLES file->read(&id, sizeof(u32)); if (id != 0x53495254) { // "TRIS" LMTS_LOG("LMTS ERROR: wrong triangle magic id!", ELL_ERROR); cleanup(); return 0; } Triangles = new SLMTSTriangleDataEntry[(Header.TriangleCount*3)]; for (i=0; i<(Header.TriangleCount*3); i++) { file->read(&Triangles[i], sizeof(SLMTSTriangleDataEntry)); } ///////////////////////////////////////////////////////////////// constructMesh(); loadTextures(); cleanup(); SAnimatedMesh* am = new SAnimatedMesh(); am->Type = EAMT_LMTS; // not unknown to irrlicht anymore am->addMesh(Mesh); am->recalculateBoundingBox(); Mesh->drop(); Mesh = 0; return am; }
static IAnimatedMesh* buildMesh( mqo::Loader &loader, video::IVideoDriver *driver) { int vertexCount=0; int triangleCount=0; int qudrangleCount=0; int originalVertexCount=0; // convert to irrlicht mesh. // mqo is shared vertex that has different uv (and normal). // therefore, the indexed array is expanded here. // // index array is [0, 1, 2, 3, 4, 5...] SMesh *mesh=new SMesh; TEXTURE_MAP texture_map; for(auto it=loader.objects.begin(); it!=loader.objects.end(); ++it){ mqo::Object &o=*it; //////////////////////////////////////////////////////////// // each mqo object //////////////////////////////////////////////////////////// originalVertexCount+=o.vertices.size(); std::map<int, SMeshBuffer*> mesh_map; for(auto it=o.faces.begin(); it!=o.faces.end(); ++it){ mqo::Face &f=*it; //////////////////////////////////////////////////////////// // each mqo face //////////////////////////////////////////////////////////// // split by material int material_index=f.material_index; std::map<int, SMeshBuffer*>::iterator found= mesh_map.find(material_index); SMeshBuffer *meshBuffer=0; if(found==mesh_map.end()){ // not found. new meshBuffer. meshBuffer=createMeshBuffer( loader, material_index, texture_map, driver); mesh_map.insert(std::make_pair(material_index, meshBuffer)); mesh->MeshBuffers.push_back(meshBuffer); } else{ // use found meshBuffer. meshBuffer=found->second; } // material mqo::Material &m=loader.materials[material_index]; // append face switch(f.index_count) { case 3: // triangle push_vertex(meshBuffer, o.vertices[f.indices[0]], f.uv[0], m.vcol ? f.color[0] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[1]], f.uv[1], m.vcol ? f.color[1] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[2]], f.uv[2], m.vcol ? f.color[2] : m.color); vertexCount+=3; triangleCount+=1; break; case 4: // qudrangle // triangle 0 push_vertex(meshBuffer, o.vertices[f.indices[0]], f.uv[0], m.vcol ? f.color[0] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[1]], f.uv[1], m.vcol ? f.color[1] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[2]], f.uv[2], m.vcol ? f.color[2] : m.color); // triangle 1 push_vertex(meshBuffer, o.vertices[f.indices[2]], f.uv[2], m.vcol ? f.color[2] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[3]], f.uv[3], m.vcol ? f.color[3] : m.color); push_vertex(meshBuffer, o.vertices[f.indices[0]], f.uv[0], m.vcol ? f.color[0] : m.color); vertexCount+=6; triangleCount+=2; qudrangleCount+=1; break; } } } // finalize mesh->recalculateBoundingBox(); SAnimatedMesh *animMesh = new SAnimatedMesh(); animMesh->Type = EAMT_UNKNOWN; animMesh->recalculateBoundingBox(); animMesh->addMesh(mesh); mesh->drop(); // summary std::cout << originalVertexCount << " vertices" << " is expand to " << vertexCount << " vertices" << std::endl << triangleCount << " triangles (" << qudrangleCount << "quadrangles)" << std::endl ; return animMesh; }
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; }
/**Creates/loads an animated mesh from the file. \return Pointer to the created mesh. Returns 0 if loading failed. If you no longer need the mesh, you should call IAnimatedMesh::drop(). See IReferenceCounted::drop() for more information.*/ IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) { if (!file) return 0; video::IVideoDriver* driver = SceneMgr->getVideoDriver(); //Load stringlist StringList dmfRawFile; LoadFromFile(file, dmfRawFile); if (dmfRawFile.size()==0) return 0; SMesh * mesh = new SMesh(); u32 i; dmfHeader header; //load header core::array<dmfMaterial> materiali; if (GetDMFHeader(dmfRawFile, header)) { //let's set ambient light SceneMgr->setAmbientLight(header.dmfAmbient); //let's create the correct number of materials, vertices and faces dmfVert *verts=new dmfVert[header.numVertices]; dmfFace *faces=new dmfFace[header.numFaces]; //let's get the materials #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Loading materials", core::stringc(header.numMaterials).c_str()); #endif GetDMFMaterials(dmfRawFile, materiali, header.numMaterials); //let's get vertices and faces #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Loading geometry"); #endif GetDMFVerticesFaces(dmfRawFile, verts, faces); //create a meshbuffer for each material, then we'll remove empty ones #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Creating meshbuffers."); #endif for (i=0; i<header.numMaterials; i++) { //create a new SMeshBufferLightMap for each material SSkinMeshBuffer* buffer = new SSkinMeshBuffer(); buffer->Material.MaterialType = video::EMT_LIGHTMAP_LIGHTING; buffer->Material.Wireframe = false; buffer->Material.Lighting = true; mesh->addMeshBuffer(buffer); buffer->drop(); } // Build the mesh buffers #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Adding geometry to mesh."); #endif for (i = 0; i < header.numFaces; i++) { #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Polygon with #vertices", core::stringc(faces[i].numVerts).c_str()); #endif if (faces[i].numVerts < 3) continue; const core::vector3df normal = core::triangle3df(verts[faces[i].firstVert].pos, verts[faces[i].firstVert+1].pos, verts[faces[i].firstVert+2].pos).getNormal().normalize(); SSkinMeshBuffer* meshBuffer = (SSkinMeshBuffer*)mesh->getMeshBuffer( faces[i].materialID); const bool use2TCoords = meshBuffer->Vertices_2TCoords.size() || materiali[faces[i].materialID].lightmapName.size(); if (use2TCoords && meshBuffer->Vertices_Standard.size()) meshBuffer->convertTo2TCoords(); const u32 base = meshBuffer->Vertices_2TCoords.size()?meshBuffer->Vertices_2TCoords.size():meshBuffer->Vertices_Standard.size(); // Add this face's verts if (use2TCoords) { // make sure we have the proper type set meshBuffer->VertexType=video::EVT_2TCOORDS; for (u32 v = 0; v < faces[i].numVerts; v++) { const dmfVert& vv = verts[faces[i].firstVert + v]; video::S3DVertex2TCoords vert(vv.pos, normal, video::SColor(255,255,255,255), vv.tc, vv.lc); if (materiali[faces[i].materialID].textureBlend==4 && SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES)) { vert.TCoords.set(vv.tc.X,-vv.tc.Y); } meshBuffer->Vertices_2TCoords.push_back(vert); } } else { for (u32 v = 0; v < faces[i].numVerts; v++) { const dmfVert& vv = verts[faces[i].firstVert + v]; video::S3DVertex vert(vv.pos, normal, video::SColor(255,255,255,255), vv.tc); if (materiali[faces[i].materialID].textureBlend==4 && SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES)) { vert.TCoords.set(vv.tc.X,-vv.tc.Y); } meshBuffer->Vertices_Standard.push_back(vert); } } // Now add the indices // This weird loop turns convex polygons into triangle strips. // I do it this way instead of a simple fan because it usually // looks a lot better in wireframe, for example. u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center for (u32 v = 0; v < faces[i].numVerts - 2; v++) { if (v & 1) // odd c = h - 1; else // even c = l + 1; meshBuffer->Indices.push_back(base + h); meshBuffer->Indices.push_back(base + l); meshBuffer->Indices.push_back(base + c); if (v & 1) // odd h--; else // even l++; } } delete [] verts; delete [] faces; } // delete all buffers without geometry in it. #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Cleaning meshbuffers."); #endif i = 0; while(i < mesh->MeshBuffers.size()) { if (mesh->MeshBuffers[i]->getVertexCount() == 0 || mesh->MeshBuffers[i]->getIndexCount() == 0) { // Meshbuffer is empty -- drop it mesh->MeshBuffers[i]->drop(); mesh->MeshBuffers.erase(i); materiali.erase(i); } else { i++; } } { //load textures and lightmaps in materials. //don't worry if you receive a could not load texture, cause if you don't need //a particular material in your scene it will be loaded and then destroyed. #ifdef _IRR_DMF_DEBUG_ os::Printer::log("Loading textures."); #endif const bool use_mat_dirs=!SceneMgr->getParameters()->getAttributeAsBool(DMF_IGNORE_MATERIALS_DIRS); core::stringc path; if ( SceneMgr->getParameters()->existsAttribute(DMF_TEXTURE_PATH) ) path = SceneMgr->getParameters()->getAttributeAsString(DMF_TEXTURE_PATH); else path = FileSystem->getFileDir(file->getFileName()); path += ('/'); for (i=0; i<mesh->getMeshBufferCount(); i++) { //texture and lightmap video::ITexture *tex = 0; video::ITexture *lig = 0; //current buffer to apply material video::SMaterial& mat = mesh->getMeshBuffer(i)->getMaterial(); //Primary texture is normal if (materiali[i].textureFlag==0) { if (materiali[i].textureBlend==4) driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true); findFile(use_mat_dirs, path, materiali[i].pathName, materiali[i].textureName); tex = driver->getTexture(materiali[i].textureName); } //Primary texture is just a colour else if(materiali[i].textureFlag==1) { video::SColor color(axtoi(materiali[i].textureName.c_str())); //just for compatibility with older Irrlicht versions //to support transparent materials if (color.getAlpha()!=255 && materiali[i].textureBlend==4) driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true); video::IImage *immagine= driver->createImage(video::ECF_A8R8G8B8, core::dimension2d<u32>(8,8)); immagine->fill(color); tex = driver->addTexture("", immagine); immagine->drop(); //to support transparent materials if (color.getAlpha()!=255 && materiali[i].textureBlend==4) { mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; mat.MaterialTypeParam =(((f32) (color.getAlpha()-1))/255.0f); } } //Lightmap is present if (materiali[i].lightmapFlag == 0) { findFile(use_mat_dirs, path, materiali[i].pathName, materiali[i].lightmapName); lig = driver->getTexture(materiali[i].lightmapName); } else //no lightmap { mat.MaterialType = video::EMT_SOLID; const f32 mult = 100.0f - header.dmfShadow; mat.AmbientColor=header.dmfAmbient.getInterpolated(video::SColor(255,0,0,0),mult/100.f); } if (materiali[i].textureBlend==4) { mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; mat.MaterialTypeParam = SceneMgr->getParameters()->getAttributeAsFloat(DMF_ALPHA_CHANNEL_REF); } //if texture is present mirror vertically owing to DeleD representation if (tex && header.dmfVersion<1.1) { const core::dimension2d<u32> texsize = tex->getSize(); void* pp = tex->lock(); if (pp) { const video::ECOLOR_FORMAT format = tex->getColorFormat(); if (format == video::ECF_A1R5G5B5) { s16* p = (s16*)pp; s16 tmp=0; for (u32 x=0; x<texsize.Width; x++) for (u32 y=0; y<texsize.Height/2; y++) { tmp=p[y*texsize.Width + x]; p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x]; p[(texsize.Height-y-1)*texsize.Width + x]=tmp; } } else if (format == video::ECF_A8R8G8B8) { s32* p = (s32*)pp; s32 tmp=0; for (u32 x=0; x<texsize.Width; x++) for (u32 y=0; y<texsize.Height/2; y++) { tmp=p[y*texsize.Width + x]; p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x]; p[(texsize.Height-y-1)*texsize.Width + x]=tmp; } } } tex->unlock(); tex->regenerateMipMapLevels(); } //if lightmap is present mirror vertically owing to DeleD rapresentation if (lig && header.dmfVersion<1.1) { const core::dimension2d<u32> ligsize=lig->getSize(); void* pp = lig->lock(); if (pp) { video::ECOLOR_FORMAT format = lig->getColorFormat(); if (format == video::ECF_A1R5G5B5) { s16* p = (s16*)pp; s16 tmp=0; for (u32 x=0; x<ligsize.Width; x++) { for (u32 y=0; y<ligsize.Height/2; y++) { tmp=p[y*ligsize.Width + x]; p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x]; p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp; } } } else if (format == video::ECF_A8R8G8B8) { s32* p = (s32*)pp; s32 tmp=0; for (u32 x=0; x<ligsize.Width; x++) { for (u32 y=0; y<ligsize.Height/2; y++) { tmp=p[y*ligsize.Width + x]; p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x]; p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp; } } } } lig->unlock(); lig->regenerateMipMapLevels(); } mat.setTexture(0, tex); mat.setTexture(1, lig); } } // create bounding box for (i = 0; i < mesh->MeshBuffers.size(); ++i) { mesh->MeshBuffers[i]->recalculateBoundingBox(); } mesh->recalculateBoundingBox(); // Set up an animated mesh to hold the mesh SAnimatedMesh* AMesh = new SAnimatedMesh(); AMesh->Type = EAMT_UNKNOWN; AMesh->addMesh(mesh); AMesh->recalculateBoundingBox(); mesh->drop(); return AMesh; }
// creates a hill plane IAnimatedMesh* CGeometryCreator::createHillPlaneMesh(const core::dimension2d<f32>& tileSize, const core::dimension2d<s32>& tc, video::SMaterial* material, f32 hillHeight, const core::dimension2d<f32>& ch, const core::dimension2d<f32>& textureRepeatCount) { core::dimension2d<s32> tileCount = tc; tileCount.Height += 1; tileCount.Width += 1; core::dimension2d<f32> countHills = ch; SMeshBuffer* buffer = new SMeshBuffer(); SMesh* mesh = new SMesh(); video::S3DVertex vtx; vtx.Color.set(255,255,255,255); vtx.Normal.set(0,0,0); if (countHills.Width < 0.01f) countHills.Width = 1; if (countHills.Height < 0.01f) countHills.Height = 1; f32 halfX = (tileSize.Width * tileCount.Width) / 2; f32 halfY = (tileSize.Height * tileCount.Height) / 2; // create vertices s32 x = 0; s32 y = 0; core::dimension2d<f32> tx; tx.Width = 1.0f / (tileCount.Width / textureRepeatCount.Width); tx.Height = 1.0f / (tileCount.Height / textureRepeatCount.Height); for (x=0; x<tileCount.Width; ++x) for (y=0; y<tileCount.Height; ++y) { vtx.Pos.set(tileSize.Width * x - halfX, 0, tileSize.Height * y - halfY); vtx.TCoords.set(-(f32)x * tx.Width, (f32)y * tx.Height); if (hillHeight) vtx.Pos.Y = (f32)(sin(vtx.Pos.X * countHills.Width * engine::core::PI / halfX) * cos(vtx.Pos.Z * countHills.Height * engine::core::PI / halfY)) *hillHeight; buffer->Vertices.push_back(vtx); } // create indices for (x=0; x<tileCount.Width-1; ++x) for (y=0; y<tileCount.Height-1; ++y) { s32 current = y*tileCount.Width + x; buffer->Indices.push_back(current); buffer->Indices.push_back(current + 1); buffer->Indices.push_back(current + tileCount.Width); buffer->Indices.push_back(current + 1); buffer->Indices.push_back(current + 1 + tileCount.Width); buffer->Indices.push_back(current + tileCount.Width); } // recalculate normals for (s32 i=0; i<(s32)buffer->Indices.size(); i+=3) { core::plane3d<f32> p( buffer->Vertices[buffer->Indices[i+0]].Pos, buffer->Vertices[buffer->Indices[i+1]].Pos, buffer->Vertices[buffer->Indices[i+2]].Pos); p.Normal.normalize(); buffer->Vertices[buffer->Indices[i+0]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+1]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+2]].Normal = p.Normal; } if (material) buffer->Material = *material; buffer->recalculateBoundingBox(); SAnimatedMesh* animatedMesh = new SAnimatedMesh(); mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); animatedMesh->addMesh(mesh); animatedMesh->recalculateBoundingBox(); mesh->drop(); buffer->drop(); return animatedMesh; }
IAnimatedMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, video::IImage* heightmap, const core::dimension2d<f32>& stretchSize, f32 maxHeight, video::IVideoDriver* driver, const core::dimension2d<s32> maxVtxBlockSize, bool debugBorders) { u32 tm = os::Timer::getRealTime()/1000; if (!texture || !heightmap) return 0; video::SMaterial material; c8 textureName[64]; c8 tmp[255]; // debug border s32 borderSkip = debugBorders ? 0 : 1; video::S3DVertex vtx; vtx.Color.set(255,255,255,255); SMesh* mesh = new SMesh(); core::dimension2d<s32> hMapSize= heightmap->getDimension(); core::dimension2d<s32> tMapSize= texture->getDimension(); core::position2d<f32> thRel((f32)tMapSize.Width / (s32)hMapSize.Width, (f32)tMapSize.Height / (s32)hMapSize.Height); core::position2d<s32> processed(0,0); while (processed.Y<hMapSize.Height) { while(processed.X<hMapSize.Width) { core::dimension2d<s32> blockSize = maxVtxBlockSize; if (processed.X + blockSize.Width > hMapSize.Width) blockSize.Width = hMapSize.Width - processed.X; if (processed.Y + blockSize.Height > hMapSize.Height) blockSize.Height = hMapSize.Height - processed.Y; SMeshBuffer* buffer = new SMeshBuffer(); s32 x,y; // add vertices of vertex block for (y=0; y<blockSize.Height; ++y) for (x=0; x<blockSize.Width; ++x) { video::SColor clr = heightmap->getPixel(x+processed.X, y+processed.Y); f32 height = ((clr.getRed() + clr.getGreen() + clr.getBlue()) / 3.0f)/255.0f * maxHeight; vtx.Pos.set((f32)(x+processed.X) * stretchSize.Width, height, (f32)(y+processed.Y) * stretchSize.Height); vtx.TCoords.set((f32)(x+0.5f) / ((f32)blockSize.Width), (f32)(y+0.5f) / ((f32)blockSize.Height)); buffer->Vertices.push_back(vtx); } // add indices of vertex block for (y=0; y<blockSize.Height-1; ++y) for (x=0; x<blockSize.Width-1; ++x) { s32 c = (y*blockSize.Width) + x; buffer->Indices.push_back(c); buffer->Indices.push_back(c + blockSize.Width); buffer->Indices.push_back(c + 1); buffer->Indices.push_back(c + 1); buffer->Indices.push_back(c + blockSize.Width); buffer->Indices.push_back(c + 1 + blockSize.Width); } // recalculate normals for (s32 i=0; i<(s32)buffer->Indices.size(); i+=3) { core::plane3d<f32> p( buffer->Vertices[buffer->Indices[i+0]].Pos, buffer->Vertices[buffer->Indices[i+1]].Pos, buffer->Vertices[buffer->Indices[i+2]].Pos); p.Normal.normalize(); buffer->Vertices[buffer->Indices[i+0]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+1]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+2]].Normal = p.Normal; } if (buffer->Vertices.size()) { // create texture for this block video::IImage* img = new video::CImage(texture, core::position2d<s32>((s32)(processed.X*thRel.X), (s32)(processed.Y*thRel.Y)), core::dimension2d<s32>((s32)(blockSize.Width*thRel.X), (s32)(blockSize.Height*thRel.Y))); sprintf(textureName, "terrain%d_%d", tm, mesh->getMeshBufferCount()); material.Texture1 = driver->addTexture(textureName, img); if (material.Texture1) { sprintf(tmp, "Generated terrain texture (%dx%d): %s", material.Texture1->getSize().Width, material.Texture1->getSize().Height, textureName); os::Printer::log(tmp); } else os::Printer::log("Could not create terrain texture.", textureName, ELL_ERROR); buffer->Material = material; img->drop(); } buffer->recalculateBoundingBox(); mesh->addMeshBuffer(buffer); buffer->drop(); // keep on processing processed.X += maxVtxBlockSize.Width - borderSkip; } // keep on processing processed.X = 0; processed.Y += maxVtxBlockSize.Height - borderSkip; } SAnimatedMesh* animatedMesh = new SAnimatedMesh(); mesh->recalculateBoundingBox(); animatedMesh->addMesh(mesh); animatedMesh->recalculateBoundingBox(); mesh->drop(); return animatedMesh; }
//! creates/loads an animated mesh from the file. //! \return Pointer to the created mesh. Returns 0 if loading failed. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! See IReferenceCounted::drop() for more information. IAnimatedMesh* COCTLoader::createMesh(io::IReadFile* file) { if (!file) return 0; octHeader header; file->read(&header, sizeof(octHeader)); octVert * verts = new octVert[header.numVerts]; octFace * faces = new octFace[header.numFaces]; octTexture * textures = new octTexture[header.numTextures]; octLightmap * lightmaps = new octLightmap[header.numLightmaps]; octLight * lights = new octLight[header.numLights]; file->read(verts, sizeof(octVert) * header.numVerts); file->read(faces, sizeof(octFace) * header.numFaces); //TODO: Make sure id is in the legal range for Textures and Lightmaps u32 i; for (i = 0; i < header.numTextures; i++) { octTexture t; file->read(&t, sizeof(octTexture)); textures[t.id] = t; } for (i = 0; i < header.numLightmaps; i++) { octLightmap t; file->read(&t, sizeof(octLightmap)); lightmaps[t.id] = t; } file->read(lights, sizeof(octLight) * header.numLights); //TODO: Now read in my extended OCT header (flexible lightmaps and vertex normals) // This is the method Nikolaus Gebhardt used in the Q3 loader -- create a // meshbuffer for every possible combination of lightmap and texture including // a "null" texture and "null" lightmap. Ones that end up with nothing in them // will be removed later. SMesh * Mesh = new SMesh(); for (i=0; i<(header.numTextures+1) * (header.numLightmaps+1); ++i) { scene::SMeshBufferLightMap* buffer = new scene::SMeshBufferLightMap(); buffer->Material.MaterialType = video::EMT_LIGHTMAP; buffer->Material.Lighting = false; Mesh->addMeshBuffer(buffer); buffer->drop(); } // Build the mesh buffers for (i = 0; i < header.numFaces; i++) { if (faces[i].numVerts < 3) continue; const core::vector3df normal = GetFaceNormal(verts[faces[i].firstVert].pos, verts[faces[i].firstVert+1].pos, verts[faces[i].firstVert+2].pos); const u32 textureID = core::min_(s32(faces[i].textureID), s32(header.numTextures - 1)) + 1; const u32 lightmapID = core::min_(s32(faces[i].lightmapID),s32(header.numLightmaps - 1)) + 1; SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(lightmapID * (header.numTextures + 1) + textureID); const u32 base = meshBuffer->Vertices.size(); // Add this face's verts u32 v; for (v = 0; v < faces[i].numVerts; ++v) { octVert * vv = &verts[faces[i].firstVert + v]; video::S3DVertex2TCoords vert; vert.Pos.set(vv->pos[0], vv->pos[1], vv->pos[2]); vert.Color = video::SColor(0,255,255,255); vert.Normal.set(normal); if (textureID == 0) { // No texture -- just a lightmap. Thus, use lightmap coords for texture 1. // (the actual texture will be swapped later) vert.TCoords.set(vv->lc[0], vv->lc[1]); } else { vert.TCoords.set(vv->tc[0], vv->tc[1]); vert.TCoords2.set(vv->lc[0], vv->lc[1]); } meshBuffer->Vertices.push_back(vert); } // Now add the indices // This weird loop turns convex polygons into triangle strips. // I do it this way instead of a simple fan because it usually looks a lot better in wireframe, for example. u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center for (v = 0; v < faces[i].numVerts - 2; ++v) { if (v & 1) c = h - 1; else c = l + 1; meshBuffer->Indices.push_back(base + h); meshBuffer->Indices.push_back(base + l); meshBuffer->Indices.push_back(base + c); if (v & 1) --h; else ++l; } } // load textures core::array<video::ITexture*> tex; tex.set_used(header.numTextures + 1); tex[0] = 0; for (i = 1; i < (header.numTextures + 1); i++) { tex[i] = Driver->getTexture(textures[i-1].fileName); } // prepare lightmaps core::array<video::ITexture*> lig; lig.set_used(header.numLightmaps + 1); u32 lightmapWidth = 128, lightmapHeight = 128; lig[0] = 0; core::dimension2d<s32> lmapsize(lightmapWidth, lightmapHeight); bool oldMipMapState = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); for (i = 1; i < (header.numLightmaps + 1); i++) { core::stringc lightmapname = file->getFileName(); lightmapname += ".lightmap."; lightmapname += (int)i; lig[i] = Driver->addTexture(lmapsize, lightmapname.c_str()); if (lig[i]->getSize() != lmapsize) os::Printer::log("OCTLoader: Created lightmap is not of the requested size", ELL_ERROR); if (lig[i]) { void* pp = lig[i]->lock(); if (pp) { video::ECOLOR_FORMAT format = lig[i]->getColorFormat(); if (format == video::ECF_A1R5G5B5) { s16* p = (s16*)pp; octLightmap * lm; lm = &lightmaps[i-1]; for (u32 x=0; x<lightmapWidth; ++x) for (u32 y=0; y<lightmapHeight; ++y) { p[x*128 + y] = video::RGB16( lm->data[x][y][2], lm->data[x][y][1], lm->data[x][y][0]); } } else if (format == video::ECF_A8R8G8B8) { s32* p = (s32*)pp; octLightmap* lm; lm = &lightmaps[i-1]; for (u32 x=0; x<lightmapWidth; ++x) for (u32 y=0; y<lightmapHeight; ++y) { p[x*128 + y] = video::SColor(255, lm->data[x][y][2], lm->data[x][y][1], lm->data[x][y][0]).color; } } else os::Printer::log( "OCTLoader: Could not create lightmap, unsupported texture format.", ELL_ERROR); } lig[i]->unlock(); } else os::Printer::log("OCTLoader: Could not create lightmap, driver created no texture.", ELL_ERROR); } Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); // Free stuff delete [] verts; delete [] faces; delete [] textures; delete [] lightmaps; delete [] lights; // attach materials for (i = 0; i < header.numLightmaps + 1; i++) { for (u32 j = 0; j < header.numTextures + 1; j++) { u32 mb = i * (header.numTextures + 1) + j; SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(mb); meshBuffer->Material.setTexture(0, tex[j]); meshBuffer->Material.setTexture(1, lig[i]); if (meshBuffer->Material.getTexture(0) == 0) { // This material has no texture, so we'll just show the lightmap if there is one. // We swapped the texture coordinates earlier. meshBuffer->Material.setTexture(0, meshBuffer->Material.getTexture(1)); meshBuffer->Material.setTexture(1, 0); } if (meshBuffer->Material.getTexture(1) == 0) { // If there is only one texture, it should be solid and lit. // Among other things, this way you can preview OCT lights. meshBuffer->Material.MaterialType = video::EMT_SOLID; meshBuffer->Material.Lighting = true; } } } // delete all buffers without geometry in it. i = 0; while(i < Mesh->MeshBuffers.size()) { if (Mesh->MeshBuffers[i]->getVertexCount() == 0 || Mesh->MeshBuffers[i]->getIndexCount() == 0 || Mesh->MeshBuffers[i]->getMaterial().getTexture(0) == 0) { // Meshbuffer is empty -- drop it Mesh->MeshBuffers[i]->drop(); Mesh->MeshBuffers.erase(i); } else { ++i; } } // create bounding box for (i = 0; i < Mesh->MeshBuffers.size(); ++i) { Mesh->MeshBuffers[i]->recalculateBoundingBox(); } Mesh->recalculateBoundingBox(); // Set up an animated mesh to hold the mesh SAnimatedMesh* AMesh = new SAnimatedMesh(); AMesh->Type = EAMT_OCT; AMesh->addMesh(Mesh); AMesh->recalculateBoundingBox(); Mesh->drop(); return AMesh; }