aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp554
1 files changed, 554 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp
new file mode 100644
index 0000000..6478aaf
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CIrrMeshFileLoader.cpp
@@ -0,0 +1,554 @@
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
5#include "IrrCompileConfig.h"
6#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
7
8#include "CIrrMeshFileLoader.h"
9#include "os.h"
10#include "IXMLReader.h"
11#include "SAnimatedMesh.h"
12#include "fast_atof.h"
13#include "IReadFile.h"
14#include "IAttributes.h"
15#include "IMeshSceneNode.h"
16#include "CDynamicMeshBuffer.h"
17#include "SMeshBufferLightMap.h"
18
19namespace irr
20{
21namespace scene
22{
23
24
25//! Constructor
26CIrrMeshFileLoader::CIrrMeshFileLoader(scene::ISceneManager* smgr,
27 io::IFileSystem* fs)
28 : SceneManager(smgr), FileSystem(fs)
29{
30
31 #ifdef _DEBUG
32 setDebugName("CIrrMeshFileLoader");
33 #endif
34
35}
36
37
38//! Returns true if the file maybe is able to be loaded by this class.
39/** This decision should be based only on the file extension (e.g. ".cob") */
40bool CIrrMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
41{
42 return core::hasFileExtension ( filename, "xml", "irrmesh" );
43}
44
45
46//! creates/loads an animated mesh from the file.
47//! \return Pointer to the created mesh. Returns 0 if loading failed.
48//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
49//! See IReferenceCounted::drop() for more information.
50IAnimatedMesh* CIrrMeshFileLoader::createMesh(io::IReadFile* file)
51{
52 io::IXMLReader* reader = FileSystem->createXMLReader(file);
53 if (!reader)
54 return 0;
55
56 // read until mesh section, skip other parts
57
58 const core::stringc meshTagName = "mesh";
59 IAnimatedMesh* mesh = 0;
60
61 while(reader->read())
62 {
63 if (reader->getNodeType() == io::EXN_ELEMENT)
64 {
65 if (meshTagName == reader->getNodeName())
66 {
67 mesh = readMesh(reader);
68 break;
69 }
70 else
71 skipSection(reader, true); // unknown section
72 }
73 }
74
75 reader->drop();
76
77 return mesh;
78}
79
80
81//! reads a mesh sections and creates a mesh from it
82IAnimatedMesh* CIrrMeshFileLoader::readMesh(io::IXMLReader* reader)
83{
84 SAnimatedMesh* animatedmesh = new SAnimatedMesh();
85 SMesh* mesh = new SMesh();
86
87 animatedmesh->addMesh(mesh);
88 mesh->drop();
89
90 core::stringc bbSectionName = "boundingBox";
91 core::stringc bufferSectionName = "buffer";
92 core::stringc meshSectionName = "mesh";
93
94 if (!reader->isEmptyElement())
95 while(reader->read())
96 {
97 if (reader->getNodeType() == io::EXN_ELEMENT)
98 {
99 const wchar_t* nodeName = reader->getNodeName();
100 if (bbSectionName == nodeName)
101 {
102 // inside a bounding box, ignore it for now because
103 // we are calculating this anyway ourselves later.
104 }
105 else
106 if (bufferSectionName == nodeName)
107 {
108 // we've got a mesh buffer
109
110 IMeshBuffer* buffer = readMeshBuffer(reader);
111 if (buffer)
112 {
113 mesh->addMeshBuffer(buffer);
114 buffer->drop();
115 }
116 }
117 else
118 skipSection(reader, true); // unknown section
119
120 } // end if node type is element
121 else
122 if (reader->getNodeType() == io::EXN_ELEMENT_END)
123 {
124 if (meshSectionName == reader->getNodeName())
125 {
126 // end of mesh section reached, cancel out
127 break;
128 }
129 }
130 } // end while reader->read();
131
132 mesh->recalculateBoundingBox();
133 animatedmesh->recalculateBoundingBox();
134
135 return animatedmesh;
136}
137
138
139//! reads a mesh sections and creates a mesh buffer from it
140IMeshBuffer* CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader)
141{
142 CDynamicMeshBuffer* buffer = 0;
143
144 core::stringc verticesSectionName = "vertices";
145 core::stringc bbSectionName = "boundingBox";
146 core::stringc materialSectionName = "material";
147 core::stringc indicesSectionName = "indices";
148 core::stringc bufferSectionName = "buffer";
149
150 bool insideVertexSection = false;
151 bool insideIndexSection = false;
152
153 int vertexCount = 0;
154 int indexCount = 0;
155
156 video::SMaterial material;
157
158 if (!reader->isEmptyElement())
159 while(reader->read())
160 {
161 if (reader->getNodeType() == io::EXN_ELEMENT)
162 {
163 const wchar_t* nodeName = reader->getNodeName();
164 if (bbSectionName == nodeName)
165 {
166 // inside a bounding box, ignore it for now because
167 // we are calculating this anyway ourselves later.
168 }
169 else
170 if (materialSectionName == nodeName)
171 {
172 //we've got a material
173
174 io::IAttributes* attributes = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver());
175 attributes->read(reader, true, L"material");
176
177 SceneManager->getVideoDriver()->fillMaterialStructureFromAttributes(material, attributes);
178 attributes->drop();
179 }
180 else
181 if (verticesSectionName == nodeName)
182 {
183 // vertices section
184
185 const core::stringc vertexTypeName1 = "standard";
186 const core::stringc vertexTypeName2 = "2tcoords";
187 const core::stringc vertexTypeName3 = "tangents";
188
189 const wchar_t* vertexType = reader->getAttributeValue(L"type");
190 vertexCount = reader->getAttributeValueAsInt(L"vertexCount");
191
192 insideVertexSection = true;
193
194 video::E_INDEX_TYPE itype = (vertexCount > 65536)?irr::video::EIT_32BIT:irr::video::EIT_16BIT;
195 if (vertexTypeName1 == vertexType)
196 {
197 buffer = new CDynamicMeshBuffer(irr::video::EVT_STANDARD, itype);
198
199 }
200 else
201 if (vertexTypeName2 == vertexType)
202 {
203 buffer = new CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, itype);
204 }
205 else
206 if (vertexTypeName3 == vertexType)
207 {
208 buffer = new CDynamicMeshBuffer(irr::video::EVT_TANGENTS, itype);
209 }
210 buffer->getVertexBuffer().reallocate(vertexCount);
211 buffer->Material = material;
212 }
213 else
214 if (indicesSectionName == nodeName)
215 {
216 // indices section
217
218 indexCount = reader->getAttributeValueAsInt(L"indexCount");
219 insideIndexSection = true;
220 }
221
222 } // end if node type is element
223 else
224 if (reader->getNodeType() == io::EXN_TEXT)
225 {
226 // read vertex data
227 if (insideVertexSection)
228 {
229 readMeshBuffer(reader, vertexCount, buffer);
230 insideVertexSection = false;
231
232 } // end reading vertex array
233 else
234 if (insideIndexSection)
235 {
236 readIndices(reader, indexCount, buffer->getIndexBuffer());
237 insideIndexSection = false;
238 }
239
240 } // end if node type is text
241 else
242 if (reader->getNodeType() == io::EXN_ELEMENT_END)
243 {
244 if (bufferSectionName == reader->getNodeName())
245 {
246 // end of buffer section reached, cancel out
247 break;
248 }
249 }
250 } // end while reader->read();
251
252 if (buffer)
253 buffer->recalculateBoundingBox();
254
255 return buffer;
256}
257
258
259//! read indices
260void CIrrMeshFileLoader::readIndices(io::IXMLReader* reader, int indexCount, IIndexBuffer& indices)
261{
262 indices.reallocate(indexCount);
263
264 core::stringc data = reader->getNodeData();
265 const c8* p = &data[0];
266
267 for (int i=0; i<indexCount && *p; ++i)
268 {
269 findNextNoneWhiteSpace(&p);
270 indices.push_back(readInt(&p));
271 }
272}
273
274
275void CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader, int vertexCount, CDynamicMeshBuffer* sbuffer)
276{
277 core::stringc data = reader->getNodeData();
278 const c8* p = &data[0];
279 scene::IVertexBuffer& Vertices = sbuffer->getVertexBuffer();
280 video::E_VERTEX_TYPE vType = Vertices.getType();
281
282 if (sbuffer)
283 {
284 for (int i=0; i<vertexCount && *p; ++i)
285 {
286 switch(vType)
287 {
288 case video::EVT_STANDARD:
289 {
290 video::S3DVertex vtx;
291 // position
292
293 findNextNoneWhiteSpace(&p);
294 vtx.Pos.X = readFloat(&p);
295 findNextNoneWhiteSpace(&p);
296 vtx.Pos.Y = readFloat(&p);
297 findNextNoneWhiteSpace(&p);
298 vtx.Pos.Z = readFloat(&p);
299
300 // normal
301
302 findNextNoneWhiteSpace(&p);
303 vtx.Normal.X = readFloat(&p);
304 findNextNoneWhiteSpace(&p);
305 vtx.Normal.Y = readFloat(&p);
306 findNextNoneWhiteSpace(&p);
307 vtx.Normal.Z = readFloat(&p);
308
309 // color
310
311 u32 col;
312 findNextNoneWhiteSpace(&p);
313 sscanf(p, "%08x", &col);
314 vtx.Color.set(col);
315 skipCurrentNoneWhiteSpace(&p);
316
317 // tcoord1
318
319 findNextNoneWhiteSpace(&p);
320 vtx.TCoords.X = readFloat(&p);
321 findNextNoneWhiteSpace(&p);
322 vtx.TCoords.Y = readFloat(&p);
323
324 Vertices.push_back(vtx);
325 }
326 break;
327 case video::EVT_2TCOORDS:
328 {
329 video::S3DVertex2TCoords vtx;
330 // position
331
332 findNextNoneWhiteSpace(&p);
333 vtx.Pos.X = readFloat(&p);
334 findNextNoneWhiteSpace(&p);
335 vtx.Pos.Y = readFloat(&p);
336 findNextNoneWhiteSpace(&p);
337 vtx.Pos.Z = readFloat(&p);
338
339 // normal
340
341 findNextNoneWhiteSpace(&p);
342 vtx.Normal.X = readFloat(&p);
343 findNextNoneWhiteSpace(&p);
344 vtx.Normal.Y = readFloat(&p);
345 findNextNoneWhiteSpace(&p);
346 vtx.Normal.Z = readFloat(&p);
347
348 // color
349
350 u32 col;
351 findNextNoneWhiteSpace(&p);
352 sscanf(p, "%08x", &col);
353 vtx.Color.set(col);
354 skipCurrentNoneWhiteSpace(&p);
355
356 // tcoord1
357
358 findNextNoneWhiteSpace(&p);
359 vtx.TCoords.X = readFloat(&p);
360 findNextNoneWhiteSpace(&p);
361 vtx.TCoords.Y = readFloat(&p);
362
363 // tcoord2
364
365 findNextNoneWhiteSpace(&p);
366 vtx.TCoords2.X = readFloat(&p);
367 findNextNoneWhiteSpace(&p);
368 vtx.TCoords2.Y = readFloat(&p);
369
370 Vertices.push_back(vtx);
371 }
372 break;
373
374 case video::EVT_TANGENTS:
375 {
376 video::S3DVertexTangents vtx;
377 // position
378
379 findNextNoneWhiteSpace(&p);
380 vtx.Pos.X = readFloat(&p);
381 findNextNoneWhiteSpace(&p);
382 vtx.Pos.Y = readFloat(&p);
383 findNextNoneWhiteSpace(&p);
384 vtx.Pos.Z = readFloat(&p);
385
386 // normal
387
388 findNextNoneWhiteSpace(&p);
389 vtx.Normal.X = readFloat(&p);
390 findNextNoneWhiteSpace(&p);
391 vtx.Normal.Y = readFloat(&p);
392 findNextNoneWhiteSpace(&p);
393 vtx.Normal.Z = readFloat(&p);
394
395 // color
396
397 u32 col;
398 findNextNoneWhiteSpace(&p);
399 sscanf(p, "%08x", &col);
400 vtx.Color.set(col);
401 skipCurrentNoneWhiteSpace(&p);
402
403 // tcoord1
404
405 findNextNoneWhiteSpace(&p);
406 vtx.TCoords.X = readFloat(&p);
407 findNextNoneWhiteSpace(&p);
408 vtx.TCoords.Y = readFloat(&p);
409
410 // tangent
411
412 findNextNoneWhiteSpace(&p);
413 vtx.Tangent.X = readFloat(&p);
414 findNextNoneWhiteSpace(&p);
415 vtx.Tangent.Y = readFloat(&p);
416 findNextNoneWhiteSpace(&p);
417 vtx.Tangent.Z = readFloat(&p);
418
419 // binormal
420
421 findNextNoneWhiteSpace(&p);
422 vtx.Binormal.X = readFloat(&p);
423 findNextNoneWhiteSpace(&p);
424 vtx.Binormal.Y = readFloat(&p);
425 findNextNoneWhiteSpace(&p);
426 vtx.Binormal.Z = readFloat(&p);
427
428 Vertices.push_back(vtx);
429 }
430 break;
431 };
432
433 }
434 }
435}
436
437
438//! skips an (unknown) section in the irrmesh document
439void CIrrMeshFileLoader::skipSection(io::IXMLReader* reader, bool reportSkipping)
440{
441#ifdef _DEBUG
442 os::Printer::log("irrMesh skipping section", core::stringc(reader->getNodeName()).c_str());
443#endif
444
445 // skip if this element is empty anyway.
446 if (reader->isEmptyElement())
447 return;
448
449 // read until we've reached the last element in this section
450 u32 tagCounter = 1;
451
452 while(tagCounter && reader->read())
453 {
454 if (reader->getNodeType() == io::EXN_ELEMENT &&
455 !reader->isEmptyElement())
456 {
457 #ifdef _DEBUG
458 if (reportSkipping)
459 os::Printer::log("irrMesh unknown element:", core::stringc(reader->getNodeName()).c_str());
460 #endif
461
462 ++tagCounter;
463 }
464 else
465 if (reader->getNodeType() == io::EXN_ELEMENT_END)
466 --tagCounter;
467 }
468}
469
470
471//! parses a float from a char pointer and moves the pointer
472//! to the end of the parsed float
473inline f32 CIrrMeshFileLoader::readFloat(const c8** p)
474{
475 f32 ftmp;
476 *p = core::fast_atof_move(*p, ftmp);
477 return ftmp;
478}
479
480
481//! parses an int from a char pointer and moves the pointer to
482//! the end of the parsed float
483inline s32 CIrrMeshFileLoader::readInt(const c8** p)
484{
485 return (s32)readFloat(p);
486}
487
488
489//! places pointer to next begin of a token
490void CIrrMeshFileLoader::skipCurrentNoneWhiteSpace(const c8** start)
491{
492 const c8* p = *start;
493
494 while(*p && !(*p==' ' || *p=='\n' || *p=='\r' || *p=='\t'))
495 ++p;
496
497 // TODO: skip comments <!-- -->
498
499 *start = p;
500}
501
502//! places pointer to next begin of a token
503void CIrrMeshFileLoader::findNextNoneWhiteSpace(const c8** start)
504{
505 const c8* p = *start;
506
507 while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t'))
508 ++p;
509
510 // TODO: skip comments <!-- -->
511
512 *start = p;
513}
514
515
516//! reads floats from inside of xml element until end of xml element
517void CIrrMeshFileLoader::readFloatsInsideElement(io::IXMLReader* reader, f32* floats, u32 count)
518{
519 if (reader->isEmptyElement())
520 return;
521
522 while(reader->read())
523 {
524 // TODO: check for comments inside the element
525 // and ignore them.
526
527 if (reader->getNodeType() == io::EXN_TEXT)
528 {
529 // parse float data
530 core::stringc data = reader->getNodeData();
531 const c8* p = &data[0];
532
533 for (u32 i=0; i<count; ++i)
534 {
535 findNextNoneWhiteSpace(&p);
536 if (*p)
537 floats[i] = readFloat(&p);
538 else
539 floats[i] = 0.0f;
540 }
541 }
542 else
543 if (reader->getNodeType() == io::EXN_ELEMENT_END)
544 break; // end parsing text
545 }
546}
547
548
549
550
551} // end namespace scene
552} // end namespace irr
553
554#endif // _IRR_COMPILE_WITH_IRR_MESH_LOADER_