1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 // This file was written by Jonas Petersen and modified by Nikolaus Gebhardt.
5 // See CLMTSMeshFileLoder.h for details.
6 /*
7
8 CLMTSMeshFileLoader.cpp
9
10 LMTSMeshFileLoader
11 Written by Jonas Petersen (a.k.a. jox)
12
13 Version 1.5 - 15 March 2005
14
15 Get the latest version here: http://development.mindfloaters.de/
16
17 This class allows loading meshes with lightmaps (*.lmts + *.tga files) that were created
18 using Pulsar LMTools by Lord Trancos (http://www.geocities.com/dxlab/index_en.html)
19
20 Notes:
21 - This version does not support user data in the *.lmts files, but still loads those files (by skipping the extra data).
22
23 License:
24 --------
25
26 It's free. You are encouraged to give me credit if you use it in your software.
27
28 Version History:
29 ----------------
30
31 Version 1.5 - 15 March 2005
32 - Did a better cleanup. No memory leaks in case of an loading error.
33 - Added "#include <stdio.h>" for sprintf.
34
35 Version 1.4 - 12 March 2005
36 - Fixed bug in texture and subset loading code that would possibly cause crash.
37 - Fixed memory cleanup to avoid leak when loading more then one mesh
38 - Used the irrlicht Logger instead of cerr to output warnings and errors.
39 For this I had to change the constructor
40 from:
41 CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver)
42 to:
43 CLMTSMeshFileLoader(IrrlichtDevice* device)
44
45 Version 1.3 - 15 February 2005
46 - Fixed bug that prevented loading more than one different lmts files.
47 - Removed unnecessary "#include <os.h>".
48 - Added "std::" in front of "cerr". This was necessary for Visual Studio .NET,
49 I hope it's not disturbing other compilers.
50 - Added warning message when a texture can not be loaded.
51 - Changed the documentation a bit (minor).
52
53 Version 1.2
54 - To avoid confusion I skipped version 1.2 because the website was offering
55 version 1.2 even though it was only version 1.1. Sorry about that.
56
57 Version 1.1 - 29 July 2004
58 - Added setTexturePath() function
59 - Minor improvements
60
61 Version 1.0 - 29 July 2004
62 - Initial release
63
64
65 */
66 //////////////////////////////////////////////////////////////////////
67
68 #include "IrrCompileConfig.h"
69 #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_
70
71 #include "SMeshBufferLightMap.h"
72 #include "SAnimatedMesh.h"
73 #include "SMeshBuffer.h"
74 #include "irrString.h"
75 #include "IReadFile.h"
76 #include "IAttributes.h"
77 #include "ISceneManager.h"
78 #include "CLMTSMeshFileLoader.h"
79 #include "os.h"
80
81 namespace irr
82 {
83 namespace scene
84 {
85
CLMTSMeshFileLoader(io::IFileSystem * fs,video::IVideoDriver * driver,io::IAttributes * parameters)86 CLMTSMeshFileLoader::CLMTSMeshFileLoader(io::IFileSystem* fs,
87 video::IVideoDriver* driver, io::IAttributes* parameters)
88 : Textures(0), Subsets(0), Triangles(0),
89 Parameters(parameters), Driver(driver), FileSystem(fs), FlipEndianess(false)
90 {
91 #ifdef _DEBUG
92 setDebugName("CLMTSMeshFileLoader");
93 #endif
94
95 if (Driver)
96 Driver->grab();
97
98 if (FileSystem)
99 FileSystem->grab();
100 }
101
102
~CLMTSMeshFileLoader()103 CLMTSMeshFileLoader::~CLMTSMeshFileLoader()
104 {
105 cleanup();
106
107 if (Driver)
108 Driver->drop();
109
110 if (FileSystem)
111 FileSystem->drop();
112 }
113
114
cleanup()115 void CLMTSMeshFileLoader::cleanup()
116 {
117 delete [] Textures;
118 Textures = 0;
119 delete [] Subsets;
120 Subsets = 0;
121 delete [] Triangles;
122 Triangles = 0;
123 }
124
125
isALoadableFileExtension(const io::path & filename) const126 bool CLMTSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
127 {
128 return core::hasFileExtension ( filename, "lmts" );
129 }
130
131
createMesh(io::IReadFile * file)132 IAnimatedMesh* CLMTSMeshFileLoader::createMesh(io::IReadFile* file)
133 {
134 u32 i;
135 u32 id;
136
137 // HEADER
138
139 file->read(&Header, sizeof(SLMTSHeader));
140 if (Header.MagicID == 0x4C4D5354)
141 {
142 FlipEndianess = true;
143 Header.MagicID = os::Byteswap::byteswap(Header.MagicID);
144 Header.Version = os::Byteswap::byteswap(Header.Version);
145 Header.HeaderSize = os::Byteswap::byteswap(Header.HeaderSize);
146 Header.TextureCount = os::Byteswap::byteswap(Header.TextureCount);
147 Header.SubsetCount = os::Byteswap::byteswap(Header.SubsetCount);
148 Header.TriangleCount = os::Byteswap::byteswap(Header.TriangleCount);
149 Header.SubsetSize = os::Byteswap::byteswap(Header.SubsetSize);
150 Header.VertexSize = os::Byteswap::byteswap(Header.VertexSize);
151 }
152 if (Header.MagicID != 0x53544D4C) { // "LMTS"
153 os::Printer::log("LMTS ERROR: wrong header magic id!", ELL_ERROR);
154 return 0;
155 }
156
157 //Skip any User Data (arbitrary app specific data)
158
159 const s32 userSize = Header.HeaderSize - sizeof(SLMTSHeader);
160 if (userSize>0)
161 file->seek(userSize,true);
162
163 // TEXTURES
164
165 file->read(&id, sizeof(u32));
166 if (FlipEndianess)
167 id = os::Byteswap::byteswap(id);
168 if (id != 0x54584554) { // "TEXT"
169 os::Printer::log("LMTS ERROR: wrong texture magic id!", ELL_ERROR);
170 return 0;
171 }
172
173 Textures = new SLMTSTextureInfoEntry[Header.TextureCount];
174
175 file->read(Textures, sizeof(SLMTSTextureInfoEntry)*Header.TextureCount);
176 if (FlipEndianess)
177 {
178 for (i=0; i<Header.TextureCount; ++i)
179 Textures[i].Flags = os::Byteswap::byteswap(Textures[i].Flags);
180 }
181
182 // SUBSETS
183
184 file->read(&id, sizeof(u32));
185 if (FlipEndianess)
186 id = os::Byteswap::byteswap(id);
187 if (id != 0x53425553) // "SUBS"
188 {
189 os::Printer::log("LMTS ERROR: wrong subset magic id!", ELL_ERROR);
190 cleanup();
191 return 0;
192 }
193
194 Subsets = new SLMTSSubsetInfoEntry[Header.SubsetCount];
195 const s32 subsetUserSize = Header.SubsetSize - sizeof(SLMTSSubsetInfoEntry);
196
197 for (i=0; i<Header.SubsetCount; ++i)
198 {
199 file->read(&Subsets[i], sizeof(SLMTSSubsetInfoEntry));
200 if (FlipEndianess)
201 {
202 Subsets[i].Offset = os::Byteswap::byteswap(Subsets[i].Offset);
203 Subsets[i].Count = os::Byteswap::byteswap(Subsets[i].Count);
204 Subsets[i].TextID1 = os::Byteswap::byteswap(Subsets[i].TextID1);
205 Subsets[i].TextID2 = os::Byteswap::byteswap(Subsets[i].TextID2);
206 }
207 if (subsetUserSize>0)
208 file->seek(subsetUserSize,true);
209 }
210
211 // TRIANGLES
212
213 file->read(&id, sizeof(u32));
214 if (FlipEndianess)
215 id = os::Byteswap::byteswap(id);
216 if (id != 0x53495254) // "TRIS"
217 {
218 os::Printer::log("LMTS ERROR: wrong triangle magic id!", ELL_ERROR);
219 cleanup();
220 return 0;
221 }
222
223 Triangles = new SLMTSTriangleDataEntry[(Header.TriangleCount*3)];
224 const s32 triUserSize = Header.VertexSize - sizeof(SLMTSTriangleDataEntry);
225
226 for (i=0; i<(Header.TriangleCount*3); ++i)
227 {
228 file->read(&Triangles[i], sizeof(SLMTSTriangleDataEntry));
229 if (FlipEndianess)
230 {
231 Triangles[i].X = os::Byteswap::byteswap(Triangles[i].X);
232 Triangles[i].Y = os::Byteswap::byteswap(Triangles[i].Y);
233 Triangles[i].Z = os::Byteswap::byteswap(Triangles[i].Z);
234 Triangles[i].U1 = os::Byteswap::byteswap(Triangles[i].U1);
235 Triangles[i].V1 = os::Byteswap::byteswap(Triangles[i].U2);
236 Triangles[i].U2 = os::Byteswap::byteswap(Triangles[i].V1);
237 Triangles[i].V2 = os::Byteswap::byteswap(Triangles[i].V2);
238 }
239 if (triUserSize>0)
240 file->seek(triUserSize,true);
241 }
242
243 /////////////////////////////////////////////////////////////////
244
245 SMesh* mesh = new SMesh();
246
247 constructMesh(mesh);
248
249 loadTextures(mesh);
250
251 cleanup();
252
253 SAnimatedMesh* am = new SAnimatedMesh();
254 am->Type = EAMT_LMTS; // not unknown to irrlicht anymore
255
256 am->addMesh(mesh);
257 am->recalculateBoundingBox();
258 mesh->drop();
259 return am;
260 }
261
262
constructMesh(SMesh * mesh)263 void CLMTSMeshFileLoader::constructMesh(SMesh* mesh)
264 {
265 for (s32 i=0; i<Header.SubsetCount; ++i)
266 {
267 scene::SMeshBufferLightMap* meshBuffer = new scene::SMeshBufferLightMap();
268
269 // EMT_LIGHTMAP_M2/EMT_LIGHTMAP_M4 also possible
270 meshBuffer->Material.MaterialType = video::EMT_LIGHTMAP;
271 meshBuffer->Material.Wireframe = false;
272 meshBuffer->Material.Lighting = false;
273
274 mesh->addMeshBuffer(meshBuffer);
275
276 const u32 offs = Subsets[i].Offset * 3;
277
278 for (u32 sc=0; sc<Subsets[i].Count; sc++)
279 {
280 const u32 idx = meshBuffer->getVertexCount();
281
282 for (u32 vu=0; vu<3; ++vu)
283 {
284 const SLMTSTriangleDataEntry& v = Triangles[offs+(3*sc)+vu];
285 meshBuffer->Vertices.push_back(
286 video::S3DVertex2TCoords(
287 v.X, v.Y, v.Z,
288 video::SColor(255,255,255,255),
289 v.U1, v.V1, v.U2, v.V2));
290 }
291 const core::vector3df normal = core::plane3df(
292 meshBuffer->Vertices[idx].Pos,
293 meshBuffer->Vertices[idx+1].Pos,
294 meshBuffer->Vertices[idx+2].Pos).Normal;
295
296 meshBuffer->Vertices[idx].Normal = normal;
297 meshBuffer->Vertices[idx+1].Normal = normal;
298 meshBuffer->Vertices[idx+2].Normal = normal;
299
300 meshBuffer->Indices.push_back(idx);
301 meshBuffer->Indices.push_back(idx+1);
302 meshBuffer->Indices.push_back(idx+2);
303 }
304 meshBuffer->drop();
305 }
306
307 for (u32 j=0; j<mesh->MeshBuffers.size(); ++j)
308 mesh->MeshBuffers[j]->recalculateBoundingBox();
309
310 mesh->recalculateBoundingBox();
311 }
312
313
loadTextures(SMesh * mesh)314 void CLMTSMeshFileLoader::loadTextures(SMesh* mesh)
315 {
316 if (!Driver || !FileSystem)
317 return;
318
319 // load textures
320
321 // a little too much space, but won't matter here
322 core::array<video::ITexture*> tex;
323 tex.reallocate(Header.TextureCount);
324 core::array<video::ITexture*> lig;
325 lig.reallocate(Header.TextureCount);
326 core::array<u32> id2id;
327 id2id.reallocate(Header.TextureCount);
328
329 const core::stringc Path = Parameters->getAttributeAsString(LMTS_TEXTURE_PATH);
330
331 core::stringc s;
332 for (u32 t=0; t<Header.TextureCount; ++t)
333 {
334 video::ITexture* tmptex = 0;
335 s = Path;
336 s.append(Textures[t].Filename);
337
338 if (FileSystem->existFile(s))
339 tmptex = Driver->getTexture(s);
340 else
341 os::Printer::log("LMTS WARNING: Texture does not exist", s.c_str(), ELL_WARNING);
342
343 if (Textures[t].Flags & 0x01)
344 {
345 id2id.push_back(lig.size());
346 lig.push_back(tmptex);
347 }
348 else
349 {
350 id2id.push_back(tex.size());
351 tex.push_back(tmptex);
352 }
353 }
354
355 // attach textures to materials.
356
357 for (u32 i=0; i<Header.SubsetCount; ++i)
358 {
359 if (Subsets[i].TextID1 < Header.TextureCount && id2id[Subsets[i].TextID1] < tex.size())
360 mesh->getMeshBuffer(i)->getMaterial().setTexture(0, tex[id2id[Subsets[i].TextID1]]);
361 if (Subsets[i].TextID2 < Header.TextureCount && id2id[Subsets[i].TextID2] < lig.size())
362 mesh->getMeshBuffer(i)->getMaterial().setTexture(1, lig[id2id[Subsets[i].TextID2]]);
363
364 if (!mesh->getMeshBuffer(i)->getMaterial().getTexture(1))
365 mesh->getMeshBuffer(i)->getMaterial().MaterialType = video::EMT_SOLID;
366 }
367 }
368
369
370 } // end namespace scene
371 } // end namespace irr
372
373 #endif // _IRR_COMPILE_WITH_LMTS_LOADER_
374