// Copyright (C) 2002-2012 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // This file was written by Jonas Petersen and modified by Nikolaus Gebhardt. // See CLMTSMeshFileLoder.h for details. /* CLMTSMeshFileLoader.cpp LMTSMeshFileLoader Written by Jonas Petersen (a.k.a. jox) Version 1.5 - 15 March 2005 Get the latest version here: http://development.mindfloaters.de/ This class allows loading meshes with lightmaps (*.lmts + *.tga files) that were created using Pulsar LMTools by Lord Trancos (http://www.geocities.com/dxlab/index_en.html) Notes: - This version does not support user data in the *.lmts files, but still loads those files (by skipping the extra data). License: -------- It's free. You are encouraged to give me credit if you use it in your software. Version History: ---------------- Version 1.5 - 15 March 2005 - Did a better cleanup. No memory leaks in case of an loading error. - Added "#include " for sprintf. Version 1.4 - 12 March 2005 - Fixed bug in texture and subset loading code that would possibly cause crash. - Fixed memory cleanup to avoid leak when loading more then one mesh - Used the irrlicht Logger instead of cerr to output warnings and errors. For this I had to change the constructor from: CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver) to: CLMTSMeshFileLoader(IrrlichtDevice* device) Version 1.3 - 15 February 2005 - Fixed bug that prevented loading more than one different lmts files. - Removed unnecessary "#include ". - Added "std::" in front of "cerr". This was necessary for Visual Studio .NET, I hope it's not disturbing other compilers. - Added warning message when a texture can not be loaded. - Changed the documentation a bit (minor). Version 1.2 - To avoid confusion I skipped version 1.2 because the website was offering version 1.2 even though it was only version 1.1. Sorry about that. Version 1.1 - 29 July 2004 - Added setTexturePath() function - Minor improvements Version 1.0 - 29 July 2004 - Initial release */ ////////////////////////////////////////////////////////////////////// #include "IrrCompileConfig.h" #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ #include "SMeshBufferLightMap.h" #include "SAnimatedMesh.h" #include "SMeshBuffer.h" #include "irrString.h" #include "IReadFile.h" #include "IAttributes.h" #include "ISceneManager.h" #include "CLMTSMeshFileLoader.h" #include "os.h" namespace irr { namespace scene { CLMTSMeshFileLoader::CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver, io::IAttributes* parameters) : Textures(0), Subsets(0), Triangles(0), Parameters(parameters), Driver(driver), FileSystem(fs), FlipEndianess(false) { #ifdef _DEBUG setDebugName("CLMTSMeshFileLoader"); #endif if (Driver) Driver->grab(); if (FileSystem) FileSystem->grab(); } CLMTSMeshFileLoader::~CLMTSMeshFileLoader() { cleanup(); if (Driver) Driver->drop(); if (FileSystem) FileSystem->drop(); } void CLMTSMeshFileLoader::cleanup() { delete [] Textures; Textures = 0; delete [] Subsets; Subsets = 0; delete [] Triangles; Triangles = 0; } bool CLMTSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const { return core::hasFileExtension ( filename, "lmts" ); } 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; iread(&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; iread(&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; } void CLMTSMeshFileLoader::constructMesh(SMesh* mesh) { for (s32 i=0; iMaterial.MaterialType = video::EMT_LIGHTMAP; meshBuffer->Material.Wireframe = false; meshBuffer->Material.Lighting = false; mesh->addMeshBuffer(meshBuffer); const u32 offs = Subsets[i].Offset * 3; for (u32 sc=0; scgetVertexCount(); for (u32 vu=0; vu<3; ++vu) { const SLMTSTriangleDataEntry& v = Triangles[offs+(3*sc)+vu]; meshBuffer->Vertices.push_back( video::S3DVertex2TCoords( v.X, v.Y, v.Z, video::SColor(255,255,255,255), v.U1, v.V1, v.U2, v.V2)); } const core::vector3df normal = core::plane3df( meshBuffer->Vertices[idx].Pos, meshBuffer->Vertices[idx+1].Pos, meshBuffer->Vertices[idx+2].Pos).Normal; meshBuffer->Vertices[idx].Normal = normal; meshBuffer->Vertices[idx+1].Normal = normal; meshBuffer->Vertices[idx+2].Normal = normal; meshBuffer->Indices.push_back(idx); meshBuffer->Indices.push_back(idx+1); meshBuffer->Indices.push_back(idx+2); } meshBuffer->drop(); } for (u32 j=0; jMeshBuffers.size(); ++j) mesh->MeshBuffers[j]->recalculateBoundingBox(); mesh->recalculateBoundingBox(); } void CLMTSMeshFileLoader::loadTextures(SMesh* mesh) { if (!Driver || !FileSystem) return; // load textures // a little too much space, but won't matter here core::array tex; tex.reallocate(Header.TextureCount); core::array lig; lig.reallocate(Header.TextureCount); core::array id2id; id2id.reallocate(Header.TextureCount); const core::stringc Path = Parameters->getAttributeAsString(LMTS_TEXTURE_PATH); core::stringc s; for (u32 t=0; texistFile(s)) tmptex = Driver->getTexture(s); else os::Printer::log("LMTS WARNING: Texture does not exist", s.c_str(), ELL_WARNING); if (Textures[t].Flags & 0x01) { id2id.push_back(lig.size()); lig.push_back(tmptex); } else { id2id.push_back(tex.size()); tex.push_back(tmptex); } } // attach textures to materials. for (u32 i=0; igetMeshBuffer(i)->getMaterial().setTexture(0, tex[id2id[Subsets[i].TextID1]]); if (Subsets[i].TextID2 < Header.TextureCount && id2id[Subsets[i].TextID2] < lig.size()) mesh->getMeshBuffer(i)->getMaterial().setTexture(1, lig[id2id[Subsets[i].TextID2]]); if (!mesh->getMeshBuffer(i)->getMaterial().getTexture(1)) mesh->getMeshBuffer(i)->getMaterial().MaterialType = video::EMT_SOLID; } } } // end namespace scene } // end namespace irr #endif // _IRR_COMPILE_WITH_LMTS_LOADER_