mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-03 00:40:41 +01:00
381 lines
10 KiB
C++
381 lines
10 KiB
C++
|
// 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 <stdio.h>" 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 <os.h>".
|
||
|
- 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 "CLMTSMeshFileLoader.h"
|
||
|
#include "CMeshTextureLoader.h"
|
||
|
#include "SMeshBufferLightMap.h"
|
||
|
#include "SAnimatedMesh.h"
|
||
|
#include "SMeshBuffer.h"
|
||
|
#include "irrString.h"
|
||
|
#include "IReadFile.h"
|
||
|
#include "IAttributes.h"
|
||
|
#include "ISceneManager.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();
|
||
|
|
||
|
TextureLoader = new CMeshTextureLoader( FileSystem, Driver );
|
||
|
}
|
||
|
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
if ( getMeshTextureLoader() )
|
||
|
getMeshTextureLoader()->setMeshFile(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;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CLMTSMeshFileLoader::constructMesh(SMesh* mesh)
|
||
|
{
|
||
|
for (s32 i=0; i<Header.SubsetCount; ++i)
|
||
|
{
|
||
|
scene::SMeshBufferLightMap* meshBuffer = new scene::SMeshBufferLightMap();
|
||
|
|
||
|
// EMT_LIGHTMAP_M2/EMT_LIGHTMAP_M4 also possible
|
||
|
meshBuffer->Material.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; sc<Subsets[i].Count; sc++)
|
||
|
{
|
||
|
const u32 idx = meshBuffer->getVertexCount();
|
||
|
|
||
|
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; j<mesh->MeshBuffers.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<video::ITexture*> tex;
|
||
|
tex.reallocate(Header.TextureCount);
|
||
|
core::array<video::ITexture*> lig;
|
||
|
lig.reallocate(Header.TextureCount);
|
||
|
core::array<u32> id2id;
|
||
|
id2id.reallocate(Header.TextureCount);
|
||
|
|
||
|
if ( getMeshTextureLoader() )
|
||
|
{
|
||
|
if ( Parameters->existsAttribute(LMTS_TEXTURE_PATH) )
|
||
|
getMeshTextureLoader()->setTexturePath(Parameters->getAttributeAsString(LMTS_TEXTURE_PATH));
|
||
|
}
|
||
|
|
||
|
core::stringc s;
|
||
|
for (u32 t=0; t<Header.TextureCount; ++t)
|
||
|
{
|
||
|
video::ITexture* tmptex = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(Textures[t].Filename) : NULL;
|
||
|
if ( !tmptex )
|
||
|
{
|
||
|
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; i<Header.SubsetCount; ++i)
|
||
|
{
|
||
|
if (Subsets[i].TextID1 < Header.TextureCount && id2id[Subsets[i].TextID1] < tex.size())
|
||
|
mesh->getMeshBuffer(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_
|