aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp1396
1 files changed, 1396 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp
new file mode 100644
index 0000000..65d3117
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/C3DSMeshFileLoader.cpp
@@ -0,0 +1,1396 @@
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_3DS_LOADER_
7
8#include "C3DSMeshFileLoader.h"
9#include "os.h"
10#include "SMeshBuffer.h"
11#include "SAnimatedMesh.h"
12#include "IReadFile.h"
13#include "IVideoDriver.h"
14#include "IMeshManipulator.h"
15
16#ifdef _DEBUG
17#define _IRR_DEBUG_3DS_LOADER_
18#endif
19
20namespace irr
21{
22namespace scene
23{
24
25
26namespace
27{
28enum e3DSChunk
29{
30 // Primary chunk
31 C3DS_MAIN3DS = 0x4D4D,
32
33 // Main Chunks
34 C3DS_EDIT3DS = 0x3D3D,
35 C3DS_KEYF3DS = 0xB000,
36 C3DS_VERSION = 0x0002,
37 C3DS_MESHVERSION = 0x3D3E,
38
39 // sub chunks of C3DS_EDIT3DS
40 C3DS_EDIT_MATERIAL = 0xAFFF,
41 C3DS_EDIT_OBJECT = 0x4000,
42
43 // sub chunks of C3DS_EDIT_MATERIAL
44 C3DS_MATNAME = 0xA000,
45 C3DS_MATAMBIENT = 0xA010,
46 C3DS_MATDIFFUSE = 0xA020,
47 C3DS_MATSPECULAR = 0xA030,
48 C3DS_MATSHININESS = 0xA040,
49 C3DS_MATSHIN2PCT = 0xA041,
50 C3DS_TRANSPARENCY = 0xA050,
51 C3DS_TRANSPARENCY_FALLOFF = 0xA052,
52 C3DS_REFL_BLUR = 0xA053,
53 C3DS_TWO_SIDE = 0xA081,
54 C3DS_WIRE = 0xA085,
55 C3DS_SHADING = 0xA100,
56 C3DS_MATTEXMAP = 0xA200,
57 C3DS_MATSPECMAP = 0xA204,
58 C3DS_MATOPACMAP = 0xA210,
59 C3DS_MATREFLMAP = 0xA220,
60 C3DS_MATBUMPMAP = 0xA230,
61 C3DS_MATMAPFILE = 0xA300,
62 C3DS_MAT_TEXTILING = 0xA351,
63 C3DS_MAT_USCALE = 0xA354,
64 C3DS_MAT_VSCALE = 0xA356,
65 C3DS_MAT_UOFFSET = 0xA358,
66 C3DS_MAT_VOFFSET = 0xA35A,
67
68 // subs of C3DS_EDIT_OBJECT
69 C3DS_OBJTRIMESH = 0x4100,
70
71 // subs of C3DS_OBJTRIMESH
72 C3DS_TRIVERT = 0x4110,
73 C3DS_POINTFLAGARRAY= 0x4111,
74 C3DS_TRIFACE = 0x4120,
75 C3DS_TRIFACEMAT = 0x4130,
76 C3DS_TRIUV = 0x4140,
77 C3DS_TRISMOOTH = 0x4150,
78 C3DS_TRIMATRIX = 0x4160,
79 C3DS_MESHCOLOR = 0x4165,
80 C3DS_DIRECT_LIGHT = 0x4600,
81 C3DS_DL_INNER_RANGE= 0x4659,
82 C3DS_DL_OUTER_RANGE= 0x465A,
83 C3DS_DL_MULTIPLIER = 0x465B,
84 C3DS_CAMERA = 0x4700,
85 C3DS_CAM_SEE_CONE = 0x4710,
86 C3DS_CAM_RANGES = 0x4720,
87
88 // subs of C3DS_KEYF3DS
89 C3DS_KF_HDR = 0xB00A,
90 C3DS_AMBIENT_TAG = 0xB001,
91 C3DS_OBJECT_TAG = 0xB002,
92 C3DS_CAMERA_TAG = 0xB003,
93 C3DS_TARGET_TAG = 0xB004,
94 C3DS_LIGHTNODE_TAG = 0xB005,
95 C3DS_KF_SEG = 0xB008,
96 C3DS_KF_CURTIME = 0xB009,
97 C3DS_KF_NODE_HDR = 0xB010,
98 C3DS_PIVOTPOINT = 0xB013,
99 C3DS_BOUNDBOX = 0xB014,
100 C3DS_MORPH_SMOOTH = 0xB015,
101 C3DS_POS_TRACK_TAG = 0xB020,
102 C3DS_ROT_TRACK_TAG = 0xB021,
103 C3DS_SCL_TRACK_TAG = 0xB022,
104 C3DS_NODE_ID = 0xB030,
105
106 // Viewport definitions
107 C3DS_VIEWPORT_LAYOUT = 0x7001,
108 C3DS_VIEWPORT_DATA = 0x7011,
109 C3DS_VIEWPORT_DATA_3 = 0x7012,
110 C3DS_VIEWPORT_SIZE = 0x7020,
111
112 // different color chunk types
113 C3DS_COL_RGB = 0x0010,
114 C3DS_COL_TRU = 0x0011,
115 C3DS_COL_LIN_24 = 0x0012,
116 C3DS_COL_LIN_F = 0x0013,
117
118 // percentage chunk types
119 C3DS_PERCENTAGE_I = 0x0030,
120 C3DS_PERCENTAGE_F = 0x0031,
121
122 C3DS_CHUNK_MAX = 0xFFFF
123};
124}
125
126
127//! Constructor
128C3DSMeshFileLoader::C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs)
129: SceneManager(smgr), FileSystem(fs), Vertices(0), Indices(0), SmoothingGroups(0), TCoords(0),
130 CountVertices(0), CountFaces(0), CountTCoords(0), Mesh(0)
131{
132
133 #ifdef _DEBUG
134 setDebugName("C3DSMeshFileLoader");
135 #endif
136
137 if (FileSystem)
138 FileSystem->grab();
139}
140
141
142//! destructor
143C3DSMeshFileLoader::~C3DSMeshFileLoader()
144{
145 cleanUp();
146
147 if (FileSystem)
148 FileSystem->drop();
149
150 if (Mesh)
151 Mesh->drop();
152}
153
154
155//! returns true if the file maybe is able to be loaded by this class
156//! based on the file extension (e.g. ".bsp")
157bool C3DSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
158{
159 return core::hasFileExtension ( filename, "3ds" );
160}
161
162
163//! creates/loads an animated mesh from the file.
164//! \return Pointer to the created mesh. Returns 0 if loading failed.
165//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
166//! See IReferenceCounted::drop() for more information.
167IAnimatedMesh* C3DSMeshFileLoader::createMesh(io::IReadFile* file)
168{
169 ChunkData data;
170
171 readChunkData(file, data);
172
173 if (data.header.id != C3DS_MAIN3DS )
174 return 0;
175
176 CurrentMaterial.clear();
177 Materials.clear();
178 MeshBufferNames.clear();
179 cleanUp();
180
181 if (Mesh)
182 Mesh->drop();
183
184 Mesh = new SMesh();
185
186 if (readChunk(file, &data))
187 {
188 // success
189
190 for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)
191 {
192 SMeshBuffer* mb = ((SMeshBuffer*)Mesh->getMeshBuffer(i));
193 // drop empty buffers
194 if (mb->getIndexCount() == 0 || mb->getVertexCount() == 0)
195 {
196 Mesh->MeshBuffers.erase(i--);
197 mb->drop();
198 }
199 else
200 {
201 if (mb->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID)
202 {
203 SMesh tmp;
204 tmp.addMeshBuffer(mb);
205 mb->drop();
206 IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp);
207 Mesh->MeshBuffers[i]=tangentMesh->getMeshBuffer(0);
208 // we need to grab because we replace the buffer manually.
209 Mesh->MeshBuffers[i]->grab();
210 // clean up intermediate mesh struct
211 tangentMesh->drop();
212 }
213 Mesh->MeshBuffers[i]->recalculateBoundingBox();
214 }
215 }
216
217 Mesh->recalculateBoundingBox();
218
219 SAnimatedMesh* am = new SAnimatedMesh();
220 am->Type = EAMT_3DS;
221 am->addMesh(Mesh);
222 am->recalculateBoundingBox();
223 Mesh->drop();
224 Mesh = 0;
225 return am;
226 }
227
228 Mesh->drop();
229 Mesh = 0;
230
231 return 0;
232}
233
234
235bool C3DSMeshFileLoader::readPercentageChunk(io::IReadFile* file,
236 ChunkData* chunk, f32& percentage)
237{
238#ifdef _IRR_DEBUG_3DS_LOADER_
239 os::Printer::log("Load percentage chunk.", ELL_DEBUG);
240#endif
241
242 ChunkData data;
243 readChunkData(file, data);
244
245 short intpercentage;
246 float fpercentage;
247
248 switch(data.header.id)
249 {
250 case C3DS_PERCENTAGE_I:
251 {
252 // read short
253 file->read(&intpercentage, 2);
254#ifdef __BIG_ENDIAN__
255 intpercentage = os::Byteswap::byteswap(intpercentage);
256#endif
257 percentage=intpercentage/100.0f;
258 data.read += 2;
259 }
260 break;
261 case C3DS_PERCENTAGE_F:
262 {
263 // read float
264 file->read(&fpercentage, sizeof(float));
265 data.read += sizeof(float);
266#ifdef __BIG_ENDIAN__
267 percentage = os::Byteswap::byteswap(fpercentage);
268#else
269 percentage = (f32)fpercentage;
270#endif
271 }
272 break;
273 default:
274 {
275 // unknown percentage chunk
276 os::Printer::log("Unknown percentage chunk in 3Ds file.", ELL_WARNING);
277 file->seek(data.header.length - data.read, true);
278 data.read += data.header.length - data.read;
279 }
280 }
281
282 chunk->read += data.read;
283
284 return true;
285}
286
287bool C3DSMeshFileLoader::readColorChunk(io::IReadFile* file, ChunkData* chunk,
288 video::SColor& out)
289{
290#ifdef _IRR_DEBUG_3DS_LOADER_
291 os::Printer::log("Load color chunk.", ELL_DEBUG);
292#endif
293 ChunkData data;
294 readChunkData(file, data);
295
296 u8 c[3];
297 f32 cf[3];
298
299 switch(data.header.id)
300 {
301 case C3DS_COL_TRU:
302 case C3DS_COL_LIN_24:
303 {
304 // read 8 bit data
305 file->read(c, sizeof(c));
306 out.set(255, c[0], c[1], c[2]);
307 data.read += sizeof(c);
308 }
309 break;
310 case C3DS_COL_RGB:
311 case C3DS_COL_LIN_F:
312 {
313 // read float data
314 file->read(cf, sizeof(cf));
315#ifdef __BIG_ENDIAN__
316 cf[0] = os::Byteswap::byteswap(cf[0]);
317 cf[1] = os::Byteswap::byteswap(cf[1]);
318 cf[2] = os::Byteswap::byteswap(cf[2]);
319#endif
320 out.set(255, (s32)(cf[0]*255.0f), (s32)(cf[1]*255.0f), (s32)(cf[2]*255.0f));
321 data.read += sizeof(cf);
322 }
323 break;
324 default:
325 {
326 // unknown color chunk size
327 os::Printer::log("Unknown size of color chunk in 3Ds file.", ELL_WARNING);
328 file->seek(data.header.length - data.read, true);
329 data.read += data.header.length - data.read;
330 }
331 }
332
333 chunk->read += data.read;
334
335 return true;
336}
337
338
339bool C3DSMeshFileLoader::readMaterialChunk(io::IReadFile* file, ChunkData* parent)
340{
341#ifdef _IRR_DEBUG_3DS_LOADER_
342 os::Printer::log("Load material chunk.", ELL_DEBUG);
343#endif
344 u16 matSection=0;
345
346 while(parent->read < parent->header.length)
347 {
348 ChunkData data;
349 readChunkData(file, data);
350
351 switch(data.header.id)
352 {
353 case C3DS_MATNAME:
354 {
355 c8* c = new c8[data.header.length - data.read];
356 file->read(c, data.header.length - data.read);
357
358 if (strlen(c))
359 CurrentMaterial.Name = c;
360
361 data.read += data.header.length - data.read;
362 delete [] c;
363 }
364 break;
365 case C3DS_MATAMBIENT:
366 readColorChunk(file, &data, CurrentMaterial.Material.AmbientColor);
367 break;
368 case C3DS_MATDIFFUSE:
369 readColorChunk(file, &data, CurrentMaterial.Material.DiffuseColor);
370 break;
371 case C3DS_MATSPECULAR:
372 readColorChunk(file, &data, CurrentMaterial.Material.SpecularColor);
373 break;
374 case C3DS_MATSHININESS:
375 readPercentageChunk(file, &data, CurrentMaterial.Material.Shininess);
376 CurrentMaterial.Material.Shininess = (1.f-CurrentMaterial.Material.Shininess)*128.f;
377 break;
378 case C3DS_TRANSPARENCY:
379 {
380 f32 percentage;
381 readPercentageChunk(file, &data, percentage);
382 if (percentage>0.0f)
383 {
384 CurrentMaterial.Material.MaterialTypeParam=percentage;
385 CurrentMaterial.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;
386 }
387 else
388 {
389 CurrentMaterial.Material.MaterialType=video::EMT_SOLID;
390 }
391 }
392 break;
393 case C3DS_WIRE:
394 CurrentMaterial.Material.Wireframe=true;
395 break;
396 case C3DS_TWO_SIDE:
397 CurrentMaterial.Material.BackfaceCulling=false;
398 break;
399 case C3DS_SHADING:
400 {
401 s16 flags;
402 file->read(&flags, 2);
403#ifdef __BIG_ENDIAN__
404 flags = os::Byteswap::byteswap(flags);
405#endif
406 switch (flags)
407 {
408 case 0:
409 CurrentMaterial.Material.Wireframe=true;
410 break;
411 case 1:
412 CurrentMaterial.Material.Wireframe=false;
413 CurrentMaterial.Material.GouraudShading=false;
414 break;
415 case 2:
416 CurrentMaterial.Material.Wireframe=false;
417 CurrentMaterial.Material.GouraudShading=true;
418 break;
419 default:
420 // phong and metal missing
421 break;
422 }
423 data.read += data.header.length - data.read;
424 }
425 break;
426 case C3DS_MATTEXMAP:
427 case C3DS_MATSPECMAP:
428 case C3DS_MATOPACMAP:
429 case C3DS_MATREFLMAP:
430 case C3DS_MATBUMPMAP:
431 {
432 matSection=data.header.id;
433 // Should contain a percentage chunk, but does
434 // not always have it
435 s16 testval;
436 const long pos = file->getPos();
437 file->read(&testval, 2);
438#ifdef __BIG_ENDIAN__
439 testval = os::Byteswap::byteswap(testval);
440#endif
441 file->seek(pos, false);
442 if ((testval == C3DS_PERCENTAGE_I) ||
443 (testval == C3DS_PERCENTAGE_F))
444 switch (matSection)
445 {
446 case C3DS_MATTEXMAP:
447 readPercentageChunk(file, &data, CurrentMaterial.Strength[0]);
448 break;
449 case C3DS_MATSPECMAP:
450 readPercentageChunk(file, &data, CurrentMaterial.Strength[1]);
451 break;
452 case C3DS_MATOPACMAP:
453 readPercentageChunk(file, &data, CurrentMaterial.Strength[2]);
454 break;
455 case C3DS_MATBUMPMAP:
456 readPercentageChunk(file, &data, CurrentMaterial.Strength[4]);
457 break;
458 }
459 }
460 break;
461 case C3DS_MATMAPFILE:
462 {
463 // read texture file name
464 c8* c = new c8[data.header.length - data.read];
465 file->read(c, data.header.length - data.read);
466 switch (matSection)
467 {
468 case C3DS_MATTEXMAP:
469 CurrentMaterial.Filename[0] = c;
470 break;
471 case C3DS_MATSPECMAP:
472 CurrentMaterial.Filename[1] = c;
473 break;
474 case C3DS_MATOPACMAP:
475 CurrentMaterial.Filename[2] = c;
476 break;
477 case C3DS_MATREFLMAP:
478 CurrentMaterial.Filename[3] = c;
479 break;
480 case C3DS_MATBUMPMAP:
481 CurrentMaterial.Filename[4] = c;
482 break;
483 }
484 data.read += data.header.length - data.read;
485 delete [] c;
486 }
487 break;
488 case C3DS_MAT_TEXTILING:
489 {
490 s16 flags;
491 file->read(&flags, 2);
492#ifdef __BIG_ENDIAN__
493 flags = os::Byteswap::byteswap(flags);
494#endif
495 data.read += 2;
496 }
497 break;
498 case C3DS_MAT_USCALE:
499 case C3DS_MAT_VSCALE:
500 case C3DS_MAT_UOFFSET:
501 case C3DS_MAT_VOFFSET:
502 {
503 f32 value;
504 file->read(&value, 4);
505#ifdef __BIG_ENDIAN__
506 value = os::Byteswap::byteswap(value);
507#endif
508 u32 i=0;
509 if (matSection != C3DS_MATTEXMAP)
510 i=1;
511 u32 j=0,k=0;
512 if (data.header.id == C3DS_MAT_VSCALE)
513 {
514 j=1;
515 k=1;
516 }
517 else if (data.header.id == C3DS_MAT_UOFFSET)
518 {
519 j=2;
520 k=0;
521 }
522 else if (data.header.id == C3DS_MAT_VOFFSET)
523 {
524 j=2;
525 k=1;
526 }
527 CurrentMaterial.Material.getTextureMatrix(i)(j,k)=value;
528
529 data.read += 4;
530 }
531 break;
532 default:
533 // ignore chunk
534 file->seek(data.header.length - data.read, true);
535 data.read += data.header.length - data.read;
536 }
537
538 parent->read += data.read;
539 }
540
541 Materials.push_back(CurrentMaterial);
542 CurrentMaterial.clear();
543
544 return true;
545}
546
547
548
549bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data,
550 IMeshBuffer* mb, const core::vector3df& pivot)
551{
552#ifdef _IRR_DEBUG_3DS_LOADER_
553 os::Printer::log("Load track chunk.", ELL_DEBUG);
554#endif
555 u16 flags;
556 u32 flags2;
557 // Track flags
558 file->read(&flags, 2);
559#ifdef __BIG_ENDIAN__
560 flags = os::Byteswap::byteswap(flags);
561#endif
562 file->read(&flags2, 4);
563#ifdef __BIG_ENDIAN__
564 flags2 = os::Byteswap::byteswap(flags2);
565#endif
566 file->read(&flags2, 4);
567#ifdef __BIG_ENDIAN__
568 flags2 = os::Byteswap::byteswap(flags2);
569#endif
570 // Num keys
571 file->read(&flags2, 4);
572#ifdef __BIG_ENDIAN__
573 flags2 = os::Byteswap::byteswap(flags2);
574#endif
575 file->read(&flags2, 4);
576#ifdef __BIG_ENDIAN__
577 flags2 = os::Byteswap::byteswap(flags2);
578#endif
579 // TCB flags
580 file->read(&flags, 2);
581#ifdef __BIG_ENDIAN__
582 flags = os::Byteswap::byteswap(flags);
583#endif
584 data.read += 20;
585
586 f32 angle=0.0f;
587 if (data.header.id== C3DS_ROT_TRACK_TAG)
588 {
589 // Angle
590 file->read(&angle, sizeof(f32));
591#ifdef __BIG_ENDIAN__
592 angle = os::Byteswap::byteswap(angle);
593#endif
594 data.read += sizeof(f32);
595 }
596 core::vector3df vec;
597 file->read(&vec.X, sizeof(f32));
598 file->read(&vec.Y, sizeof(f32));
599 file->read(&vec.Z, sizeof(f32));
600#ifdef __BIG_ENDIAN__
601 vec.X = os::Byteswap::byteswap(vec.X);
602 vec.Y = os::Byteswap::byteswap(vec.Y);
603 vec.Z = os::Byteswap::byteswap(vec.Z);
604#endif
605 data.read += 12;
606 vec-=pivot;
607
608 // apply transformation to mesh buffer
609 if (false)//mb)
610 {
611 video::S3DVertex *vertices=(video::S3DVertex*)mb->getVertices();
612 if (data.header.id==C3DS_POS_TRACK_TAG)
613 {
614 for (u32 i=0; i<mb->getVertexCount(); ++i)
615 vertices[i].Pos+=vec;
616 }
617 else if (data.header.id==C3DS_ROT_TRACK_TAG)
618 {
619 //TODO
620 }
621 else if (data.header.id==C3DS_SCL_TRACK_TAG)
622 {
623 //TODO
624 }
625 }
626 // skip further frames
627 file->seek(data.header.length - data.read, true);
628 data.read += data.header.length - data.read;
629 return true;
630}
631
632
633bool C3DSMeshFileLoader::readFrameChunk(io::IReadFile* file, ChunkData* parent)
634{
635#ifdef _IRR_DEBUG_3DS_LOADER_
636 os::Printer::log("Load frame chunk.", ELL_DEBUG);
637#endif
638 ChunkData data;
639
640 //KF_HDR is always at the beginning
641 readChunkData(file, data);
642 if (data.header.id != C3DS_KF_HDR)
643 return false;
644 else
645 {
646#ifdef _IRR_DEBUG_3DS_LOADER_
647 os::Printer::log("Load keyframe header.", ELL_DEBUG);
648#endif
649 u16 version;
650 file->read(&version, 2);
651#ifdef __BIG_ENDIAN__
652 version = os::Byteswap::byteswap(version);
653#endif
654 core::stringc name;
655 readString(file, data, name);
656 u32 flags;
657 file->read(&flags, 4);
658#ifdef __BIG_ENDIAN__
659 flags = os::Byteswap::byteswap(flags);
660#endif
661
662 data.read += 4;
663 parent->read += data.read;
664 }
665 data.read=0;
666
667 IMeshBuffer* mb=0;
668 core::vector3df pivot,bboxCenter;
669 while(parent->read < parent->header.length)
670 {
671 readChunkData(file, data);
672
673 switch(data.header.id)
674 {
675 case C3DS_OBJECT_TAG:
676 {
677#ifdef _IRR_DEBUG_3DS_LOADER_
678 os::Printer::log("Load object tag.", ELL_DEBUG);
679#endif
680 mb=0;
681 pivot.set(0.0f, 0.0f, 0.0f);
682 }
683 break;
684 case C3DS_KF_SEG:
685 {
686#ifdef _IRR_DEBUG_3DS_LOADER_
687 os::Printer::log("Load keyframe segment.", ELL_DEBUG);
688#endif
689 u32 flags;
690 file->read(&flags, 4);
691#ifdef __BIG_ENDIAN__
692 flags = os::Byteswap::byteswap(flags);
693#endif
694 file->read(&flags, 4);
695#ifdef __BIG_ENDIAN__
696 flags = os::Byteswap::byteswap(flags);
697#endif
698 data.read += 8;
699 }
700 break;
701 case C3DS_KF_NODE_HDR:
702 {
703#ifdef _IRR_DEBUG_3DS_LOADER_
704 os::Printer::log("Load keyframe node header.", ELL_DEBUG);
705#endif
706 s16 flags;
707 c8* c = new c8[data.header.length - data.read-6];
708 file->read(c, data.header.length - data.read-6);
709
710 // search mesh buffer to apply these transformations to
711 for (u32 i=0; i<MeshBufferNames.size(); ++i)
712 {
713 if (MeshBufferNames[i]==c)
714 {
715 mb=Mesh->getMeshBuffer(i);
716 break;
717 }
718 }
719
720 file->read(&flags, 2);
721#ifdef __BIG_ENDIAN__
722 flags = os::Byteswap::byteswap(flags);
723#endif
724 file->read(&flags, 2);
725#ifdef __BIG_ENDIAN__
726 flags = os::Byteswap::byteswap(flags);
727#endif
728 file->read(&flags, 2);
729#ifdef __BIG_ENDIAN__
730 flags = os::Byteswap::byteswap(flags);
731#endif
732 data.read += data.header.length - data.read;
733 delete [] c;
734 }
735 break;
736 case C3DS_KF_CURTIME:
737 {
738#ifdef _IRR_DEBUG_3DS_LOADER_
739 os::Printer::log("Load keyframe current time.", ELL_DEBUG);
740#endif
741 u32 flags;
742 file->read(&flags, 4);
743#ifdef __BIG_ENDIAN__
744 flags = os::Byteswap::byteswap(flags);
745#endif
746 data.read += 4;
747 }
748 break;
749 case C3DS_NODE_ID:
750 {
751#ifdef _IRR_DEBUG_3DS_LOADER_
752 os::Printer::log("Load node ID.", ELL_DEBUG);
753#endif
754 u16 flags;
755 file->read(&flags, 2);
756#ifdef __BIG_ENDIAN__
757 flags = os::Byteswap::byteswap(flags);
758#endif
759 data.read += 2;
760 }
761 break;
762 case C3DS_PIVOTPOINT:
763 {
764#ifdef _IRR_DEBUG_3DS_LOADER_
765 os::Printer::log("Load pivot point.", ELL_DEBUG);
766#endif
767 file->read(&pivot.X, sizeof(f32));
768 file->read(&pivot.Y, sizeof(f32));
769 file->read(&pivot.Z, sizeof(f32));
770#ifdef __BIG_ENDIAN__
771 pivot.X = os::Byteswap::byteswap(pivot.X);
772 pivot.Y = os::Byteswap::byteswap(pivot.Y);
773 pivot.Z = os::Byteswap::byteswap(pivot.Z);
774#endif
775 data.read += 12;
776 }
777 break;
778 case C3DS_BOUNDBOX:
779 {
780#ifdef _IRR_DEBUG_3DS_LOADER_
781 os::Printer::log("Load bounding box.", ELL_DEBUG);
782#endif
783 core::aabbox3df bbox;
784 // abuse bboxCenter as temporary variable
785 file->read(&bboxCenter.X, sizeof(f32));
786 file->read(&bboxCenter.Y, sizeof(f32));
787 file->read(&bboxCenter.Z, sizeof(f32));
788#ifdef __BIG_ENDIAN__
789 bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X);
790 bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y);
791 bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z);
792#endif
793 bbox.reset(bboxCenter);
794 file->read(&bboxCenter.X, sizeof(f32));
795 file->read(&bboxCenter.Y, sizeof(f32));
796 file->read(&bboxCenter.Z, sizeof(f32));
797#ifdef __BIG_ENDIAN__
798 bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X);
799 bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y);
800 bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z);
801#endif
802 bbox.addInternalPoint(bboxCenter);
803 bboxCenter=bbox.getCenter();
804 data.read += 24;
805 }
806 break;
807 case C3DS_MORPH_SMOOTH:
808 {
809#ifdef _IRR_DEBUG_3DS_LOADER_
810 os::Printer::log("Load morph smooth.", ELL_DEBUG);
811#endif
812 f32 flag;
813 file->read(&flag, 4);
814#ifdef __BIG_ENDIAN__
815 flag = os::Byteswap::byteswap(flag);
816#endif
817 data.read += 4;
818 }
819 break;
820 case C3DS_POS_TRACK_TAG:
821 case C3DS_ROT_TRACK_TAG:
822 case C3DS_SCL_TRACK_TAG:
823 readTrackChunk(file, data, mb, bboxCenter-pivot);
824 break;
825 default:
826 // ignore chunk
827 file->seek(data.header.length - data.read, true);
828 data.read += data.header.length - data.read;
829 }
830
831 parent->read += data.read;
832 data.read=0;
833 }
834
835 return true;
836}
837
838
839bool C3DSMeshFileLoader::readChunk(io::IReadFile* file, ChunkData* parent)
840{
841 while(parent->read < parent->header.length)
842 {
843 ChunkData data;
844 readChunkData(file, data);
845
846 switch(data.header.id)
847 {
848 case C3DS_VERSION:
849 {
850 u16 version;
851 file->read(&version, sizeof(u16));
852#ifdef __BIG_ENDIAN__
853 version = os::Byteswap::byteswap(version);
854#endif
855 file->seek(data.header.length - data.read - 2, true);
856 data.read += data.header.length - data.read;
857 if (version != 0x03)
858 os::Printer::log("3ds file version is other than 3.", ELL_ERROR);
859 }
860 break;
861 case C3DS_EDIT_MATERIAL:
862 readMaterialChunk(file, &data);
863 break;
864 case C3DS_KEYF3DS:
865 readFrameChunk(file, &data);
866 break;
867 case C3DS_EDIT3DS:
868 break;
869 case C3DS_MESHVERSION:
870 case 0x01:
871 {
872 u32 version;
873 file->read(&version, sizeof(u32));
874#ifdef __BIG_ENDIAN__
875 version = os::Byteswap::byteswap(version);
876#endif
877 data.read += sizeof(u32);
878 }
879 break;
880 case C3DS_EDIT_OBJECT:
881 {
882 core::stringc name;
883 readString(file, data, name);
884 readObjectChunk(file, &data);
885 composeObject(file, name);
886 }
887 break;
888
889 default:
890 // ignore chunk
891 file->seek(data.header.length - data.read, true);
892 data.read += data.header.length - data.read;
893 }
894
895 parent->read += data.read;
896 }
897
898 return true;
899}
900
901
902bool C3DSMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData* parent)
903{
904#ifdef _IRR_DEBUG_3DS_LOADER_
905 os::Printer::log("Load object chunk.", ELL_DEBUG);
906#endif
907 while(parent->read < parent->header.length)
908 {
909 ChunkData data;
910 readChunkData(file, data);
911
912 switch(data.header.id)
913 {
914 case C3DS_OBJTRIMESH:
915 readObjectChunk(file, &data);
916 break;
917
918 case C3DS_TRIVERT:
919 readVertices(file, data);
920 break;
921
922 case C3DS_POINTFLAGARRAY:
923 {
924 u16 numVertex, flags;
925 file->read(&numVertex, sizeof(u16));
926#ifdef __BIG_ENDIAN__
927 numVertex= os::Byteswap::byteswap(numVertex);
928#endif
929 for (u16 i=0; i<numVertex; ++i)
930 {
931 file->read(&flags, sizeof(u16));
932#ifdef __BIG_ENDIAN__
933 flags = os::Byteswap::byteswap(flags);
934#endif
935 }
936 data.read += (numVertex+1)*sizeof(u16);
937 }
938 break;
939
940 case C3DS_TRIFACE:
941 readIndices(file, data);
942 readObjectChunk(file, &data); // read smooth and material groups
943 break;
944
945 case C3DS_TRIFACEMAT:
946 readMaterialGroup(file, data);
947 break;
948
949 case C3DS_TRIUV: // getting texture coordinates
950 readTextureCoords(file, data);
951 break;
952
953 case C3DS_TRIMATRIX:
954 {
955 f32 mat[4][3];
956 file->read(&mat, 12*sizeof(f32));
957 TransformationMatrix.makeIdentity();
958 for (int i=0; i<4; ++i)
959 {
960 for (int j=0; j<3; ++j)
961 {
962#ifdef __BIG_ENDIAN__
963 TransformationMatrix(i,j)=os::Byteswap::byteswap(mat[i][j]);
964#else
965 TransformationMatrix(i,j)=mat[i][j];
966#endif
967 }
968 }
969 data.read += 12*sizeof(f32);
970 }
971 break;
972 case C3DS_MESHCOLOR:
973 {
974 u8 flag;
975 file->read(&flag, sizeof(u8));
976 ++data.read;
977 }
978 break;
979 case C3DS_TRISMOOTH: // TODO
980 {
981 SmoothingGroups = new u32[CountFaces];
982 file->read(SmoothingGroups, CountFaces*sizeof(u32));
983#ifdef __BIG_ENDIAN__
984 for (u16 i=0; i<CountFaces; ++i)
985 SmoothingGroups[i] = os::Byteswap::byteswap(SmoothingGroups[i]);
986#endif
987 data.read += CountFaces*sizeof(u32);
988 }
989 break;
990
991 default:
992 // ignore chunk
993 file->seek(data.header.length - data.read, true);
994 data.read += data.header.length - data.read;
995 }
996
997 parent->read += data.read;
998 }
999
1000 return true;
1001}
1002
1003
1004void C3DSMeshFileLoader::composeObject(io::IReadFile* file, const core::stringc& name)
1005{
1006#ifdef _IRR_DEBUG_3DS_LOADER_
1007 os::Printer::log("Compose object.", ELL_DEBUG);
1008#endif
1009 if (Mesh->getMeshBufferCount() != Materials.size())
1010 loadMaterials(file);
1011
1012 if (MaterialGroups.empty())
1013 {
1014 // no material group, so add all
1015 SMaterialGroup group;
1016 group.faceCount = CountFaces;
1017 group.faces = new u16[group.faceCount];
1018 for (u16 i=0; i<group.faceCount; ++i)
1019 group.faces[i] = i;
1020 MaterialGroups.push_back(group);
1021
1022 // if we've got no material, add one without a texture
1023 if (Materials.empty())
1024 {
1025 SCurrentMaterial m;
1026 Materials.push_back(m);
1027 SMeshBuffer* mb = new scene::SMeshBuffer();
1028 Mesh->addMeshBuffer(mb);
1029 mb->getMaterial() = Materials[0].Material;
1030 mb->drop();
1031 // add an empty mesh buffer name
1032 MeshBufferNames.push_back("");
1033 }
1034 }
1035
1036 for (u32 i=0; i<MaterialGroups.size(); ++i)
1037 {
1038 SMeshBuffer* mb = 0;
1039 video::SMaterial* mat=0;
1040 u32 mbPos;
1041 // -3 because we add three vertices at once
1042 u32 maxPrimitives = core::min_(SceneManager->getVideoDriver()->getMaximalPrimitiveCount(), (u32)((1<<16)-1))-3; // currently hardcoded s16 max value for index pointers
1043
1044 // find mesh buffer for this group
1045 for (mbPos=0; mbPos<Materials.size(); ++mbPos)
1046 {
1047 if (MaterialGroups[i].MaterialName == Materials[mbPos].Name)
1048 {
1049 mb = (SMeshBuffer*)Mesh->getMeshBuffer(mbPos);
1050 mat=&Materials[mbPos].Material;
1051 MeshBufferNames[mbPos]=name;
1052 break;
1053 }
1054 }
1055
1056 if (mb != 0)
1057 {
1058 // add geometry to the buffer.
1059
1060 video::S3DVertex vtx;
1061 core::vector3df vec;
1062 vtx.Color=mat->DiffuseColor;
1063 if (mat->MaterialType==video::EMT_TRANSPARENT_VERTEX_ALPHA)
1064 {
1065 vtx.Color.setAlpha((int)(255.0f*mat->MaterialTypeParam));
1066 }
1067 vtx.Normal.set(0,0,0);
1068
1069 for (s32 f=0; f<MaterialGroups[i].faceCount; ++f)
1070 {
1071 u32 vtxCount = mb->Vertices.size();
1072 if (vtxCount>maxPrimitives)
1073 {
1074 IMeshBuffer* tmp = mb;
1075 mb = new SMeshBuffer();
1076 Mesh->addMeshBuffer(mb);
1077 mb->drop();
1078 Mesh->MeshBuffers[mbPos] = Mesh->MeshBuffers.getLast();
1079 Mesh->MeshBuffers[Mesh->MeshBuffers.size()-1] = tmp;
1080 mb->getMaterial() = tmp->getMaterial();
1081 vtxCount=0;
1082 }
1083
1084 for (s32 v=0; v<3; ++v)
1085 {
1086 s32 idx = Indices[MaterialGroups[i].faces[f]*4 +v];
1087
1088 if (CountVertices > idx)
1089 {
1090 vtx.Pos.X = Vertices[idx*3 + 0];
1091 vtx.Pos.Z = Vertices[idx*3 + 1];
1092 vtx.Pos.Y = Vertices[idx*3 + 2];
1093// TransformationMatrix.transformVect(vtx.Pos);
1094 }
1095
1096 if (CountTCoords > idx)
1097 {
1098 vtx.TCoords.X = TCoords[idx*2 + 0];
1099 vtx.TCoords.Y = 1.0f -TCoords[idx*2 + 1];
1100 }
1101
1102 mb->Vertices.push_back(vtx);
1103 }
1104
1105 // compute normal
1106 core::plane3d<f32> pl(mb->Vertices[vtxCount].Pos, mb->Vertices[vtxCount+2].Pos,
1107 mb->Vertices[vtxCount+1].Pos);
1108
1109 mb->Vertices[vtxCount].Normal = pl.Normal;
1110 mb->Vertices[vtxCount+1].Normal = pl.Normal;
1111 mb->Vertices[vtxCount+2].Normal = pl.Normal;
1112
1113 // add indices
1114
1115 mb->Indices.push_back(vtxCount);
1116 mb->Indices.push_back(vtxCount+2);
1117 mb->Indices.push_back(vtxCount+1);
1118 }
1119 }
1120 else
1121 os::Printer::log("Found no matching material for Group in 3ds file.", ELL_WARNING);
1122 }
1123
1124 cleanUp();
1125}
1126
1127
1128void C3DSMeshFileLoader::loadMaterials(io::IReadFile* file)
1129{
1130 // create a mesh buffer for every material
1131 core::stringc modelFilename = file->getFileName();
1132
1133 if (Materials.empty())
1134 os::Printer::log("No materials found in 3ds file.", ELL_INFORMATION);
1135
1136 MeshBufferNames.reallocate(Materials.size());
1137 for (u32 i=0; i<Materials.size(); ++i)
1138 {
1139 MeshBufferNames.push_back("");
1140 SMeshBuffer* m = new scene::SMeshBuffer();
1141 Mesh->addMeshBuffer(m);
1142
1143 m->getMaterial() = Materials[i].Material;
1144 if (Materials[i].Filename[0].size())
1145 {
1146 video::ITexture* texture = 0;
1147 if (FileSystem->existFile(Materials[i].Filename[0]))
1148 texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[0]);
1149 if (!texture)
1150 {
1151 const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[0]);
1152 if (FileSystem->existFile(fname))
1153 texture = SceneManager->getVideoDriver()->getTexture(fname);
1154 }
1155 if (!texture)
1156 os::Printer::log("Could not load a texture for entry in 3ds file",
1157 Materials[i].Filename[0].c_str(), ELL_WARNING);
1158 else
1159 m->getMaterial().setTexture(0, texture);
1160 }
1161
1162 if (Materials[i].Filename[2].size())
1163 {
1164 video::ITexture* texture = 0;
1165 if (FileSystem->existFile(Materials[i].Filename[2]))
1166 texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[2]);
1167 if (!texture)
1168 {
1169 const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[2]);
1170 if (FileSystem->existFile(fname))
1171 texture = SceneManager->getVideoDriver()->getTexture(fname);
1172 }
1173 if (!texture)
1174 {
1175 os::Printer::log("Could not load a texture for entry in 3ds file",
1176 Materials[i].Filename[2].c_str(), ELL_WARNING);
1177 }
1178 else
1179 {
1180 m->getMaterial().setTexture(0, texture);
1181 m->getMaterial().MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
1182 }
1183 }
1184
1185 if (Materials[i].Filename[3].size())
1186 {
1187 video::ITexture* texture = 0;
1188 if (FileSystem->existFile(Materials[i].Filename[3]))
1189 texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[3]);
1190 if (!texture)
1191 {
1192 const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[3]);
1193 if (FileSystem->existFile(fname))
1194 texture = SceneManager->getVideoDriver()->getTexture(fname);
1195 }
1196
1197 if (!texture)
1198 {
1199 os::Printer::log("Could not load a texture for entry in 3ds file",
1200 Materials[i].Filename[3].c_str(), ELL_WARNING);
1201 }
1202 else
1203 {
1204 m->getMaterial().setTexture(1, m->getMaterial().getTexture(0));
1205 m->getMaterial().setTexture(0, texture);
1206 m->getMaterial().MaterialType = video::EMT_REFLECTION_2_LAYER;
1207 }
1208 }
1209
1210 if (Materials[i].Filename[4].size())
1211 {
1212 video::ITexture* texture = 0;
1213 if (FileSystem->existFile(Materials[i].Filename[4]))
1214 texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[4]);
1215 if (!texture)
1216 {
1217 const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[4]);
1218 if (FileSystem->existFile(fname))
1219 texture = SceneManager->getVideoDriver()->getTexture(fname);
1220 }
1221 if (!texture)
1222 os::Printer::log("Could not load a texture for entry in 3ds file",
1223 Materials[i].Filename[4].c_str(), ELL_WARNING);
1224 else
1225 {
1226 m->getMaterial().setTexture(1, texture);
1227 SceneManager->getVideoDriver()->makeNormalMapTexture(texture, Materials[i].Strength[4]*10.f);
1228 m->getMaterial().MaterialType=video::EMT_PARALLAX_MAP_SOLID;
1229 m->getMaterial().MaterialTypeParam=.035f;
1230 }
1231 }
1232
1233 m->drop();
1234 }
1235}
1236
1237
1238void C3DSMeshFileLoader::cleanUp()
1239{
1240 delete [] Vertices;
1241 CountVertices = 0;
1242 Vertices = 0;
1243 delete [] Indices;
1244 Indices = 0;
1245 CountFaces = 0;
1246 delete [] SmoothingGroups;
1247 SmoothingGroups = 0;
1248 delete [] TCoords;
1249 TCoords = 0;
1250 CountTCoords = 0;
1251
1252 MaterialGroups.clear();
1253}
1254
1255
1256void C3DSMeshFileLoader::readTextureCoords(io::IReadFile* file, ChunkData& data)
1257{
1258#ifdef _IRR_DEBUG_3DS_LOADER_
1259 os::Printer::log("Load texture coords.", ELL_DEBUG);
1260#endif
1261 file->read(&CountTCoords, sizeof(CountTCoords));
1262#ifdef __BIG_ENDIAN__
1263 CountTCoords = os::Byteswap::byteswap(CountTCoords);
1264#endif
1265 data.read += sizeof(CountTCoords);
1266
1267 s32 tcoordsBufferByteSize = CountTCoords * sizeof(f32) * 2;
1268
1269 if (data.header.length - data.read != tcoordsBufferByteSize)
1270 {
1271 os::Printer::log("Invalid size of tcoords found in 3ds file.", ELL_WARNING);
1272 return;
1273 }
1274
1275 TCoords = new f32[CountTCoords * 3];
1276 file->read(TCoords, tcoordsBufferByteSize);
1277#ifdef __BIG_ENDIAN__
1278 for (int i=0;i<CountTCoords*2;i++) TCoords[i] = os::Byteswap::byteswap(TCoords[i]);
1279#endif
1280 data.read += tcoordsBufferByteSize;
1281}
1282
1283
1284void C3DSMeshFileLoader::readMaterialGroup(io::IReadFile* file, ChunkData& data)
1285{
1286#ifdef _IRR_DEBUG_3DS_LOADER_
1287 os::Printer::log("Load material group.", ELL_DEBUG);
1288#endif
1289 SMaterialGroup group;
1290
1291 readString(file, data, group.MaterialName);
1292
1293 file->read(&group.faceCount, sizeof(group.faceCount));
1294#ifdef __BIG_ENDIAN__
1295 group.faceCount = os::Byteswap::byteswap(group.faceCount);
1296#endif
1297 data.read += sizeof(group.faceCount);
1298
1299 // read faces
1300 group.faces = new u16[group.faceCount];
1301 file->read(group.faces, sizeof(u16) * group.faceCount);
1302#ifdef __BIG_ENDIAN__
1303 for (u32 i=0;i<group.faceCount;++i)
1304 group.faces[i] = os::Byteswap::byteswap(group.faces[i]);
1305#endif
1306 data.read += sizeof(u16) * group.faceCount;
1307
1308 MaterialGroups.push_back(group);
1309}
1310
1311
1312void C3DSMeshFileLoader::readIndices(io::IReadFile* file, ChunkData& data)
1313{
1314#ifdef _IRR_DEBUG_3DS_LOADER_
1315 os::Printer::log("Load indices.", ELL_DEBUG);
1316#endif
1317 file->read(&CountFaces, sizeof(CountFaces));
1318#ifdef __BIG_ENDIAN__
1319 CountFaces = os::Byteswap::byteswap(CountFaces);
1320#endif
1321 data.read += sizeof(CountFaces);
1322
1323 s32 indexBufferByteSize = CountFaces * sizeof(u16) * 4;
1324
1325 // Indices are u16s.
1326 // After every 3 Indices in the array, there follows an edge flag.
1327 Indices = new u16[CountFaces * 4];
1328 file->read(Indices, indexBufferByteSize);
1329#ifdef __BIG_ENDIAN__
1330 for (int i=0;i<CountFaces*4;++i)
1331 Indices[i] = os::Byteswap::byteswap(Indices[i]);
1332#endif
1333 data.read += indexBufferByteSize;
1334}
1335
1336
1337void C3DSMeshFileLoader::readVertices(io::IReadFile* file, ChunkData& data)
1338{
1339#ifdef _IRR_DEBUG_3DS_LOADER_
1340 os::Printer::log("Load vertices.", ELL_DEBUG);
1341#endif
1342 file->read(&CountVertices, sizeof(CountVertices));
1343#ifdef __BIG_ENDIAN__
1344 CountVertices = os::Byteswap::byteswap(CountVertices);
1345#endif
1346 data.read += sizeof(CountVertices);
1347
1348 const s32 vertexBufferByteSize = CountVertices * sizeof(f32) * 3;
1349
1350 if (data.header.length - data.read != vertexBufferByteSize)
1351 {
1352 os::Printer::log("Invalid size of vertices found in 3ds file", core::stringc(CountVertices), ELL_ERROR);
1353 return;
1354 }
1355
1356 Vertices = new f32[CountVertices * 3];
1357 file->read(Vertices, vertexBufferByteSize);
1358#ifdef __BIG_ENDIAN__
1359 for (int i=0;i<CountVertices*3;i++)
1360 Vertices[i] = os::Byteswap::byteswap(Vertices[i]);
1361#endif
1362 data.read += vertexBufferByteSize;
1363}
1364
1365
1366void C3DSMeshFileLoader::readChunkData(io::IReadFile* file, ChunkData& data)
1367{
1368 file->read(&data.header, sizeof(ChunkHeader));
1369#ifdef __BIG_ENDIAN__
1370 data.header.id = os::Byteswap::byteswap(data.header.id);
1371 data.header.length = os::Byteswap::byteswap(data.header.length);
1372#endif
1373 data.read += sizeof(ChunkHeader);
1374}
1375
1376
1377void C3DSMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out)
1378{
1379 c8 c = 1;
1380 out = "";
1381
1382 while (c)
1383 {
1384 file->read(&c, sizeof(c8));
1385 if (c)
1386 out.append(c);
1387 }
1388 data.read+=out.size()+1;
1389}
1390
1391
1392} // end namespace scene
1393} // end namespace irr
1394
1395#endif // _IRR_COMPILE_WITH_3DS_LOADER_
1396