aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CB3DMeshFileLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CB3DMeshFileLoader.cpp1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CB3DMeshFileLoader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CB3DMeshFileLoader.cpp
new file mode 100644
index 0000000..3d8769e
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CB3DMeshFileLoader.cpp
@@ -0,0 +1,1105 @@
1// Copyright (C) 2006-2012 Luke Hoschke
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5// B3D Mesh loader
6// File format designed by Mark Sibly for the Blitz3D engine and has been
7// declared public domain
8
9#include "IrrCompileConfig.h"
10#ifdef _IRR_COMPILE_WITH_B3D_LOADER_
11
12#include "CB3DMeshFileLoader.h"
13
14#include "IVideoDriver.h"
15#include "IFileSystem.h"
16#include "os.h"
17
18#ifdef _DEBUG
19#define _B3D_READER_DEBUG
20#endif
21
22namespace irr
23{
24namespace scene
25{
26
27//! Constructor
28CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr)
29: SceneManager(smgr), AnimatedMesh(0), B3DFile(0), NormalsInFile(false),
30 HasVertexColors(false), ShowWarning(true)
31{
32 #ifdef _DEBUG
33 setDebugName("CB3DMeshFileLoader");
34 #endif
35}
36
37
38//! returns true if the file maybe is able to be loaded by this class
39//! based on the file extension (e.g. ".bsp")
40bool CB3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
41{
42 return core::hasFileExtension ( filename, "b3d" );
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* CB3DMeshFileLoader::createMesh(io::IReadFile* f)
51{
52 if (!f)
53 return 0;
54
55 B3DFile = f;
56 AnimatedMesh = new scene::CSkinnedMesh();
57 ShowWarning = true; // If true a warning is issued if too many textures are used
58 VerticesStart=0;
59
60 if ( load() )
61 {
62 AnimatedMesh->finalize();
63 }
64 else
65 {
66 AnimatedMesh->drop();
67 AnimatedMesh = 0;
68 }
69
70 return AnimatedMesh;
71}
72
73
74bool CB3DMeshFileLoader::load()
75{
76 B3dStack.clear();
77
78 NormalsInFile=false;
79 HasVertexColors=false;
80
81 //------ Get header ------
82
83 SB3dChunkHeader header;
84 B3DFile->read(&header, sizeof(header));
85#ifdef __BIG_ENDIAN__
86 header.size = os::Byteswap::byteswap(header.size);
87#endif
88
89 if ( strncmp( header.name, "BB3D", 4 ) != 0 )
90 {
91 os::Printer::log("File is not a b3d file. Loading failed (No header found)", B3DFile->getFileName(), ELL_ERROR);
92 return false;
93 }
94
95 // Add main chunk...
96 B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
97
98 // Get file version, but ignore it, as it's not important with b3d files...
99 s32 fileVersion;
100 B3DFile->read(&fileVersion, sizeof(fileVersion));
101#ifdef __BIG_ENDIAN__
102 fileVersion = os::Byteswap::byteswap(fileVersion);
103#endif
104
105 //------ Read main chunk ------
106
107 while ( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos() )
108 {
109 B3DFile->read(&header, sizeof(header));
110#ifdef __BIG_ENDIAN__
111 header.size = os::Byteswap::byteswap(header.size);
112#endif
113 B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
114
115 if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 )
116 {
117 if (!readChunkTEXS())
118 return false;
119 }
120 else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 )
121 {
122 if (!readChunkBRUS())
123 return false;
124 }
125 else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 )
126 {
127 if (!readChunkNODE((CSkinnedMesh::SJoint*)0) )
128 return false;
129 }
130 else
131 {
132 os::Printer::log("Unknown chunk found in mesh base - skipping");
133 B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length);
134 B3dStack.erase(B3dStack.size()-1);
135 }
136 }
137
138 B3dStack.clear();
139
140 BaseVertices.clear();
141 AnimatedVertices_VertexID.clear();
142 AnimatedVertices_BufferID.clear();
143
144 Materials.clear();
145 Textures.clear();
146
147 return true;
148}
149
150
151bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint)
152{
153 CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint);
154 readString(joint->Name);
155
156#ifdef _B3D_READER_DEBUG
157 core::stringc logStr;
158 for ( u32 i=1; i < B3dStack.size(); ++i )
159 logStr += "-";
160 logStr += "read ChunkNODE";
161 os::Printer::log(logStr.c_str(), joint->Name.c_str());
162#endif
163
164 f32 position[3], scale[3], rotation[4];
165
166 readFloats(position, 3);
167 readFloats(scale, 3);
168 readFloats(rotation, 4);
169
170 joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ;
171 joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]);
172 joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]);
173
174 //Build LocalMatrix:
175
176 core::matrix4 positionMatrix;
177 positionMatrix.setTranslation( joint->Animatedposition );
178 core::matrix4 scaleMatrix;
179 scaleMatrix.setScale( joint->Animatedscale );
180 core::matrix4 rotationMatrix;
181 joint->Animatedrotation.getMatrix_transposed(rotationMatrix);
182
183 joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix;
184
185 if (inJoint)
186 joint->GlobalMatrix = inJoint->GlobalMatrix * joint->LocalMatrix;
187 else
188 joint->GlobalMatrix = joint->LocalMatrix;
189
190 while(B3dStack.getLast().startposition + B3dStack.getLast().length > B3DFile->getPos()) // this chunk repeats
191 {
192 SB3dChunkHeader header;
193 B3DFile->read(&header, sizeof(header));
194#ifdef __BIG_ENDIAN__
195 header.size = os::Byteswap::byteswap(header.size);
196#endif
197
198 B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
199
200 if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 )
201 {
202 if (!readChunkNODE(joint))
203 return false;
204 }
205 else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 )
206 {
207 VerticesStart=BaseVertices.size();
208 if (!readChunkMESH(joint))
209 return false;
210 }
211 else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 )
212 {
213 if (!readChunkBONE(joint))
214 return false;
215 }
216 else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 )
217 {
218 if(!readChunkKEYS(joint))
219 return false;
220 }
221 else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 )
222 {
223 if (!readChunkANIM())
224 return false;
225 }
226 else
227 {
228 os::Printer::log("Unknown chunk found in node chunk - skipping");
229 B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length);
230 B3dStack.erase(B3dStack.size()-1);
231 }
232 }
233
234 B3dStack.erase(B3dStack.size()-1);
235
236 return true;
237}
238
239
240bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint)
241{
242#ifdef _B3D_READER_DEBUG
243 core::stringc logStr;
244 for ( u32 i=1; i < B3dStack.size(); ++i )
245 logStr += "-";
246 logStr += "read ChunkMESH";
247 os::Printer::log(logStr.c_str());
248#endif
249
250 s32 brushID;
251 B3DFile->read(&brushID, sizeof(brushID));
252#ifdef __BIG_ENDIAN__
253 brushID = os::Byteswap::byteswap(brushID);
254#endif
255
256 NormalsInFile=false;
257 HasVertexColors=false;
258
259 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
260 {
261 SB3dChunkHeader header;
262 B3DFile->read(&header, sizeof(header));
263#ifdef __BIG_ENDIAN__
264 header.size = os::Byteswap::byteswap(header.size);
265#endif
266
267 B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
268
269 if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 )
270 {
271 if (!readChunkVRTS(inJoint))
272 return false;
273 }
274 else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 )
275 {
276 scene::SSkinMeshBuffer *meshBuffer = AnimatedMesh->addMeshBuffer();
277
278 if (brushID!=-1)
279 {
280 loadTextures(Materials[brushID]);
281 meshBuffer->Material=Materials[brushID].Material;
282 }
283
284 if(readChunkTRIS(meshBuffer,AnimatedMesh->getMeshBuffers().size()-1, VerticesStart)==false)
285 return false;
286
287 if (!NormalsInFile)
288 {
289 s32 i;
290
291 for ( i=0; i<(s32)meshBuffer->Indices.size(); i+=3)
292 {
293 core::plane3df p(meshBuffer->getVertex(meshBuffer->Indices[i+0])->Pos,
294 meshBuffer->getVertex(meshBuffer->Indices[i+1])->Pos,
295 meshBuffer->getVertex(meshBuffer->Indices[i+2])->Pos);
296
297 meshBuffer->getVertex(meshBuffer->Indices[i+0])->Normal += p.Normal;
298 meshBuffer->getVertex(meshBuffer->Indices[i+1])->Normal += p.Normal;
299 meshBuffer->getVertex(meshBuffer->Indices[i+2])->Normal += p.Normal;
300 }
301
302 for ( i = 0; i<(s32)meshBuffer->getVertexCount(); ++i )
303 {
304 meshBuffer->getVertex(i)->Normal.normalize();
305 BaseVertices[VerticesStart+i].Normal=meshBuffer->getVertex(i)->Normal;
306 }
307 }
308 }
309 else
310 {
311 os::Printer::log("Unknown chunk found in mesh - skipping");
312 B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length);
313 B3dStack.erase(B3dStack.size()-1);
314 }
315 }
316
317 B3dStack.erase(B3dStack.size()-1);
318
319 return true;
320}
321
322
323/*
324VRTS:
325 int flags ;1=normal values present, 2=rgba values present
326 int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8
327 but we only support 3
328 int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4
329 {
330 float x,y,z ;always present
331 float nx,ny,nz ;vertex normal: present if (flags&1)
332 float red,green,blue,alpha ;vertex color: present if (flags&2)
333 float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
334 }
335*/
336bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint)
337{
338#ifdef _B3D_READER_DEBUG
339 core::stringc logStr;
340 for ( u32 i=1; i < B3dStack.size(); ++i )
341 logStr += "-";
342 logStr += "ChunkVRTS";
343 os::Printer::log(logStr.c_str());
344#endif
345
346 const s32 max_tex_coords = 3;
347 s32 flags, tex_coord_sets, tex_coord_set_size;
348
349 B3DFile->read(&flags, sizeof(flags));
350 B3DFile->read(&tex_coord_sets, sizeof(tex_coord_sets));
351 B3DFile->read(&tex_coord_set_size, sizeof(tex_coord_set_size));
352#ifdef __BIG_ENDIAN__
353 flags = os::Byteswap::byteswap(flags);
354 tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets);
355 tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size);
356#endif
357
358 if (tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong
359 {
360 os::Printer::log("tex_coord_sets or tex_coord_set_size too big", B3DFile->getFileName(), ELL_ERROR);
361 return false;
362 }
363
364 //------ Allocate Memory, for speed -----------//
365
366 s32 numberOfReads = 3;
367
368 if (flags & 1)
369 {
370 NormalsInFile = true;
371 numberOfReads += 3;
372 }
373 if (flags & 2)
374 {
375 numberOfReads += 4;
376 HasVertexColors=true;
377 }
378
379 numberOfReads += tex_coord_sets*tex_coord_set_size;
380
381 const s32 memoryNeeded = (B3dStack.getLast().length / sizeof(f32)) / numberOfReads;
382
383 BaseVertices.reallocate(memoryNeeded + BaseVertices.size() + 1);
384 AnimatedVertices_VertexID.reallocate(memoryNeeded + AnimatedVertices_VertexID.size() + 1);
385
386 //--------------------------------------------//
387
388 while( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
389 {
390 f32 position[3];
391 f32 normal[3]={0.f, 0.f, 0.f};
392 f32 color[4]={1.0f, 1.0f, 1.0f, 1.0f};
393 f32 tex_coords[max_tex_coords][4];
394
395 readFloats(position, 3);
396
397 if (flags & 1)
398 readFloats(normal, 3);
399 if (flags & 2)
400 readFloats(color, 4);
401
402 for (s32 i=0; i<tex_coord_sets; ++i)
403 readFloats(tex_coords[i], tex_coord_set_size);
404
405 f32 tu=0.0f, tv=0.0f;
406 if (tex_coord_sets >= 1 && tex_coord_set_size >= 2)
407 {
408 tu=tex_coords[0][0];
409 tv=tex_coords[0][1];
410 }
411
412 f32 tu2=0.0f, tv2=0.0f;
413 if (tex_coord_sets>1 && tex_coord_set_size>1)
414 {
415 tu2=tex_coords[1][0];
416 tv2=tex_coords[1][1];
417 }
418
419 // Create Vertex...
420 video::S3DVertex2TCoords Vertex(position[0], position[1], position[2],
421 normal[0], normal[1], normal[2],
422 video::SColorf(color[0], color[1], color[2], color[3]).toSColor(),
423 tu, tv, tu2, tv2);
424
425 // Transform the Vertex position by nested node...
426 inJoint->GlobalMatrix.transformVect(Vertex.Pos);
427 inJoint->GlobalMatrix.rotateVect(Vertex.Normal);
428
429 //Add it...
430 BaseVertices.push_back(Vertex);
431
432 AnimatedVertices_VertexID.push_back(-1);
433 AnimatedVertices_BufferID.push_back(-1);
434 }
435
436 B3dStack.erase(B3dStack.size()-1);
437
438 return true;
439}
440
441
442bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 meshBufferID, s32 vertices_Start)
443{
444#ifdef _B3D_READER_DEBUG
445 core::stringc logStr;
446 for ( u32 i=1; i < B3dStack.size(); ++i )
447 logStr += "-";
448 logStr += "ChunkTRIS";
449 os::Printer::log(logStr.c_str());
450#endif
451
452 bool showVertexWarning=false;
453
454 s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (using a workaround)
455 B3DFile->read(&triangle_brush_id, sizeof(triangle_brush_id));
456#ifdef __BIG_ENDIAN__
457 triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id);
458#endif
459
460 SB3dMaterial *B3dMaterial;
461
462 if (triangle_brush_id != -1)
463 {
464 loadTextures(Materials[triangle_brush_id]);
465 B3dMaterial = &Materials[triangle_brush_id];
466 meshBuffer->Material = B3dMaterial->Material;
467 }
468 else
469 B3dMaterial = 0;
470
471 const s32 memoryNeeded = B3dStack.getLast().length / sizeof(s32);
472 meshBuffer->Indices.reallocate(memoryNeeded + meshBuffer->Indices.size() + 1);
473
474 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
475 {
476 s32 vertex_id[3];
477
478 B3DFile->read(vertex_id, 3*sizeof(s32));
479#ifdef __BIG_ENDIAN__
480 vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]);
481 vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]);
482 vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]);
483#endif
484
485 //Make Ids global:
486 vertex_id[0] += vertices_Start;
487 vertex_id[1] += vertices_Start;
488 vertex_id[2] += vertices_Start;
489
490 for(s32 i=0; i<3; ++i)
491 {
492 if ((u32)vertex_id[i] >= AnimatedVertices_VertexID.size())
493 {
494 os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR);
495 return false;
496 }
497
498 if (AnimatedVertices_VertexID[ vertex_id[i] ] != -1)
499 {
500 if ( AnimatedVertices_BufferID[ vertex_id[i] ] != (s32)meshBufferID ) //If this vertex is linked in a different meshbuffer
501 {
502 AnimatedVertices_VertexID[ vertex_id[i] ] = -1;
503 AnimatedVertices_BufferID[ vertex_id[i] ] = -1;
504 showVertexWarning=true;
505 }
506 }
507 if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer
508 {
509 //Check for lightmapping:
510 if (BaseVertices[ vertex_id[i] ].TCoords2 != core::vector2df(0.f,0.f))
511 meshBuffer->convertTo2TCoords(); //Will only affect the meshbuffer the first time this is called
512
513 //Add the vertex to the meshbuffer:
514 if (meshBuffer->VertexType == video::EVT_STANDARD)
515 meshBuffer->Vertices_Standard.push_back( BaseVertices[ vertex_id[i] ] );
516 else
517 meshBuffer->Vertices_2TCoords.push_back(BaseVertices[ vertex_id[i] ] );
518
519 //create vertex id to meshbuffer index link:
520 AnimatedVertices_VertexID[ vertex_id[i] ] = meshBuffer->getVertexCount()-1;
521 AnimatedVertices_BufferID[ vertex_id[i] ] = meshBufferID;
522
523 if (B3dMaterial)
524 {
525 // Apply Material/Color/etc...
526 video::S3DVertex *Vertex=meshBuffer->getVertex(meshBuffer->getVertexCount()-1);
527
528 if (!HasVertexColors)
529 Vertex->Color=B3dMaterial->Material.DiffuseColor;
530 else if (Vertex->Color.getAlpha() == 255)
531 Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) );
532
533 // Use texture's scale
534 if (B3dMaterial->Textures[0])
535 {
536 Vertex->TCoords.X *= B3dMaterial->Textures[0]->Xscale;
537 Vertex->TCoords.Y *= B3dMaterial->Textures[0]->Yscale;
538 }
539 /*
540 if (B3dMaterial->Textures[1])
541 {
542 Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale;
543 Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale;
544 }
545 */
546 }
547 }
548 }
549
550 meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] );
551 meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] );
552 meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] );
553 }
554
555 B3dStack.erase(B3dStack.size()-1);
556
557 if (showVertexWarning)
558 os::Printer::log("B3dMeshLoader: Warning, different meshbuffers linking to the same vertex, this will cause problems with animated meshes");
559
560 return true;
561}
562
563
564bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint)
565{
566#ifdef _B3D_READER_DEBUG
567 core::stringc logStr;
568 for ( u32 i=1; i < B3dStack.size(); ++i )
569 logStr += "-";
570 logStr += "read ChunkBONE";
571 os::Printer::log(logStr.c_str());
572#endif
573
574 if (B3dStack.getLast().length > 8)
575 {
576 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
577 {
578 u32 globalVertexID;
579 f32 strength;
580 B3DFile->read(&globalVertexID, sizeof(globalVertexID));
581 B3DFile->read(&strength, sizeof(strength));
582#ifdef __BIG_ENDIAN__
583 globalVertexID = os::Byteswap::byteswap(globalVertexID);
584 strength = os::Byteswap::byteswap(strength);
585#endif
586 globalVertexID += VerticesStart;
587
588 if (AnimatedVertices_VertexID[globalVertexID]==-1)
589 {
590 os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)");
591 }
592 else if (strength >0)
593 {
594 CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(inJoint);
595 weight->strength=strength;
596 //Find the meshbuffer and Vertex index from the Global Vertex ID:
597 weight->vertex_id = AnimatedVertices_VertexID[globalVertexID];
598 weight->buffer_id = AnimatedVertices_BufferID[globalVertexID];
599 }
600 }
601 }
602
603 B3dStack.erase(B3dStack.size()-1);
604 return true;
605}
606
607
608bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint)
609{
610#ifdef _B3D_READER_DEBUG
611 // Only print first, that's just too much output otherwise
612 if ( !inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty()) )
613 {
614 core::stringc logStr;
615 for ( u32 i=1; i < B3dStack.size(); ++i )
616 logStr += "-";
617 logStr += "read ChunkKEYS";
618 os::Printer::log(logStr.c_str());
619 }
620#endif
621
622 s32 flags;
623 B3DFile->read(&flags, sizeof(flags));
624#ifdef __BIG_ENDIAN__
625 flags = os::Byteswap::byteswap(flags);
626#endif
627
628 CSkinnedMesh::SPositionKey *oldPosKey=0;
629 core::vector3df oldPos[2];
630 CSkinnedMesh::SScaleKey *oldScaleKey=0;
631 core::vector3df oldScale[2];
632 CSkinnedMesh::SRotationKey *oldRotKey=0;
633 core::quaternion oldRot[2];
634 bool isFirst[3]={true,true,true};
635 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
636 {
637 s32 frame;
638
639 B3DFile->read(&frame, sizeof(frame));
640 #ifdef __BIG_ENDIAN__
641 frame = os::Byteswap::byteswap(frame);
642 #endif
643
644 // Add key frames, frames in Irrlicht are zero-based
645 f32 data[4];
646 if (flags & 1)
647 {
648 readFloats(data, 3);
649 if ((oldPosKey!=0) && (oldPos[0]==oldPos[1]))
650 {
651 const core::vector3df pos(data[0], data[1], data[2]);
652 if (oldPos[1]==pos)
653 oldPosKey->frame = (f32)frame-1;
654 else
655 {
656 oldPos[0]=oldPos[1];
657 oldPosKey=AnimatedMesh->addPositionKey(inJoint);
658 oldPosKey->frame = (f32)frame-1;
659 oldPos[1].set(oldPosKey->position.set(pos));
660 }
661 }
662 else if (oldPosKey==0 && isFirst[0])
663 {
664 oldPosKey=AnimatedMesh->addPositionKey(inJoint);
665 oldPosKey->frame = (f32)frame-1;
666 oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2]));
667 oldPosKey=0;
668 isFirst[0]=false;
669 }
670 else
671 {
672 if (oldPosKey!=0)
673 oldPos[0]=oldPos[1];
674 oldPosKey=AnimatedMesh->addPositionKey(inJoint);
675 oldPosKey->frame = (f32)frame-1;
676 oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2]));
677 }
678 }
679 if (flags & 2)
680 {
681 readFloats(data, 3);
682 if ((oldScaleKey!=0) && (oldScale[0]==oldScale[1]))
683 {
684 const core::vector3df scale(data[0], data[1], data[2]);
685 if (oldScale[1]==scale)
686 oldScaleKey->frame = (f32)frame-1;
687 else
688 {
689 oldScale[0]=oldScale[1];
690 oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
691 oldScaleKey->frame = (f32)frame-1;
692 oldScale[1].set(oldScaleKey->scale.set(scale));
693 }
694 }
695 else if (oldScaleKey==0 && isFirst[1])
696 {
697 oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
698 oldScaleKey->frame = (f32)frame-1;
699 oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
700 oldScaleKey=0;
701 isFirst[1]=false;
702 }
703 else
704 {
705 if (oldScaleKey!=0)
706 oldScale[0]=oldScale[1];
707 oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
708 oldScaleKey->frame = (f32)frame-1;
709 oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
710 }
711 }
712 if (flags & 4)
713 {
714 readFloats(data, 4);
715 if ((oldRotKey!=0) && (oldRot[0]==oldRot[1]))
716 {
717 // meant to be in this order since b3d stores W first
718 const core::quaternion rot(data[1], data[2], data[3], data[0]);
719 if (oldRot[1]==rot)
720 oldRotKey->frame = (f32)frame-1;
721 else
722 {
723 oldRot[0]=oldRot[1];
724 oldRotKey=AnimatedMesh->addRotationKey(inJoint);
725 oldRotKey->frame = (f32)frame-1;
726 oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
727 }
728 }
729 else if (oldRotKey==0 && isFirst[2])
730 {
731 oldRotKey=AnimatedMesh->addRotationKey(inJoint);
732 oldRotKey->frame = (f32)frame-1;
733 // meant to be in this order since b3d stores W first
734 oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
735 oldRotKey=0;
736 isFirst[2]=false;
737 }
738 else
739 {
740 if (oldRotKey!=0)
741 oldRot[0]=oldRot[1];
742 oldRotKey=AnimatedMesh->addRotationKey(inJoint);
743 oldRotKey->frame = (f32)frame-1;
744 // meant to be in this order since b3d stores W first
745 oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
746 }
747 }
748 }
749
750 B3dStack.erase(B3dStack.size()-1);
751 return true;
752}
753
754
755bool CB3DMeshFileLoader::readChunkANIM()
756{
757#ifdef _B3D_READER_DEBUG
758 core::stringc logStr;
759 for ( u32 i=1; i < B3dStack.size(); ++i )
760 logStr += "-";
761 logStr += "read ChunkANIM";
762 os::Printer::log(logStr.c_str());
763#endif
764
765 s32 animFlags; //not stored\used
766 s32 animFrames;//not stored\used
767 f32 animFPS; //not stored\used
768
769 B3DFile->read(&animFlags, sizeof(s32));
770 B3DFile->read(&animFrames, sizeof(s32));
771 readFloats(&animFPS, 1);
772 if (animFPS>0.f)
773 AnimatedMesh->setAnimationSpeed(animFPS);
774 os::Printer::log("FPS", io::path((double)animFPS), ELL_DEBUG);
775
776 #ifdef __BIG_ENDIAN__
777 animFlags = os::Byteswap::byteswap(animFlags);
778 animFrames = os::Byteswap::byteswap(animFrames);
779 #endif
780
781 B3dStack.erase(B3dStack.size()-1);
782 return true;
783}
784
785
786bool CB3DMeshFileLoader::readChunkTEXS()
787{
788#ifdef _B3D_READER_DEBUG
789 core::stringc logStr;
790 for ( u32 i=1; i < B3dStack.size(); ++i )
791 logStr += "-";
792 logStr += "read ChunkTEXS";
793 os::Printer::log(logStr.c_str());
794#endif
795
796 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
797 {
798 Textures.push_back(SB3dTexture());
799 SB3dTexture& B3dTexture = Textures.getLast();
800
801 readString(B3dTexture.TextureName);
802 B3dTexture.TextureName.replace('\\','/');
803#ifdef _B3D_READER_DEBUG
804 os::Printer::log("read Texture", B3dTexture.TextureName.c_str());
805#endif
806
807 B3DFile->read(&B3dTexture.Flags, sizeof(s32));
808 B3DFile->read(&B3dTexture.Blend, sizeof(s32));
809#ifdef __BIG_ENDIAN__
810 B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags);
811 B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend);
812#endif
813#ifdef _B3D_READER_DEBUG
814 os::Printer::log("Flags", core::stringc(B3dTexture.Flags).c_str());
815 os::Printer::log("Blend", core::stringc(B3dTexture.Blend).c_str());
816#endif
817 readFloats(&B3dTexture.Xpos, 1);
818 readFloats(&B3dTexture.Ypos, 1);
819 readFloats(&B3dTexture.Xscale, 1);
820 readFloats(&B3dTexture.Yscale, 1);
821 readFloats(&B3dTexture.Angle, 1);
822 }
823
824 B3dStack.erase(B3dStack.size()-1);
825
826 return true;
827}
828
829
830bool CB3DMeshFileLoader::readChunkBRUS()
831{
832#ifdef _B3D_READER_DEBUG
833 core::stringc logStr;
834 for ( u32 i=1; i < B3dStack.size(); ++i )
835 logStr += "-";
836 logStr += "read ChunkBRUS";
837 os::Printer::log(logStr.c_str());
838#endif
839
840 u32 n_texs;
841 B3DFile->read(&n_texs, sizeof(u32));
842#ifdef __BIG_ENDIAN__
843 n_texs = os::Byteswap::byteswap(n_texs);
844#endif
845
846 // number of texture ids read for Irrlicht
847 const u32 num_textures = core::min_(n_texs, video::MATERIAL_MAX_TEXTURES);
848 // number of bytes to skip (for ignored texture ids)
849 const u32 n_texs_offset = (num_textures<n_texs)?(n_texs-num_textures):0;
850
851 while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
852 {
853 // This is what blitz basic calls a brush, like a Irrlicht Material
854
855 core::stringc name;
856 readString(name);
857#ifdef _B3D_READER_DEBUG
858 os::Printer::log("read Material", name);
859#endif
860 Materials.push_back(SB3dMaterial());
861 SB3dMaterial& B3dMaterial=Materials.getLast();
862
863 readFloats(&B3dMaterial.red, 1);
864 readFloats(&B3dMaterial.green, 1);
865 readFloats(&B3dMaterial.blue, 1);
866 readFloats(&B3dMaterial.alpha, 1);
867 readFloats(&B3dMaterial.shininess, 1);
868
869 B3DFile->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend));
870 B3DFile->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx));
871#ifdef __BIG_ENDIAN__
872 B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend);
873 B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx);
874#endif
875#ifdef _B3D_READER_DEBUG
876 os::Printer::log("Blend", core::stringc(B3dMaterial.blend).c_str());
877 os::Printer::log("FX", core::stringc(B3dMaterial.fx).c_str());
878#endif
879
880 u32 i;
881 for (i=0; i<num_textures; ++i)
882 {
883 s32 texture_id=-1;
884 B3DFile->read(&texture_id, sizeof(s32));
885#ifdef __BIG_ENDIAN__
886 texture_id = os::Byteswap::byteswap(texture_id);
887#endif
888 //--- Get pointers to the texture, based on the IDs ---
889 if ((u32)texture_id < Textures.size())
890 {
891 B3dMaterial.Textures[i]=&Textures[texture_id];
892#ifdef _B3D_READER_DEBUG
893 os::Printer::log("Layer", core::stringc(i).c_str());
894 os::Printer::log("using texture", Textures[texture_id].TextureName.c_str());
895#endif
896 }
897 else
898 B3dMaterial.Textures[i]=0;
899 }
900 // skip other texture ids
901 for (i=0; i<n_texs_offset; ++i)
902 {
903 s32 texture_id=-1;
904 B3DFile->read(&texture_id, sizeof(s32));
905#ifdef __BIG_ENDIAN__
906 texture_id = os::Byteswap::byteswap(texture_id);
907#endif
908 if (ShowWarning && (texture_id != -1) && (n_texs>video::MATERIAL_MAX_TEXTURES))
909 {
910 os::Printer::log("Too many textures used in one material", B3DFile->getFileName(), ELL_WARNING);
911 ShowWarning = false;
912 }
913 }
914
915 //Fixes problems when the lightmap is on the first texture:
916 if (B3dMaterial.Textures[0] != 0)
917 {
918 if (B3dMaterial.Textures[0]->Flags & 65536) // 65536 = secondary UV
919 {
920 SB3dTexture *TmpTexture;
921 TmpTexture = B3dMaterial.Textures[1];
922 B3dMaterial.Textures[1] = B3dMaterial.Textures[0];
923 B3dMaterial.Textures[0] = TmpTexture;
924 }
925 }
926
927 //If a preceeding texture slot is empty move the others down:
928 for (i=num_textures; i>0; --i)
929 {
930 for (u32 j=i-1; j<num_textures-1; ++j)
931 {
932 if (B3dMaterial.Textures[j+1] != 0 && B3dMaterial.Textures[j] == 0)
933 {
934 B3dMaterial.Textures[j] = B3dMaterial.Textures[j+1];
935 B3dMaterial.Textures[j+1] = 0;
936 }
937 }
938 }
939
940 //------ Convert blitz flags/blend to irrlicht -------
941
942 //Two textures:
943 if (B3dMaterial.Textures[1])
944 {
945 if (B3dMaterial.alpha==1.f)
946 {
947 if (B3dMaterial.Textures[1]->Blend == 5) //(Multiply 2)
948 B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP_M2;
949 else
950 B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP;
951 B3dMaterial.Material.Lighting = false;
952 }
953 else
954 {
955 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
956 B3dMaterial.Material.ZWriteEnable = false;
957 }
958 }
959 else if (B3dMaterial.Textures[0]) //One texture:
960 {
961 // Flags & 0x1 is usual SOLID, 0x8 is mipmap (handled before)
962 if (B3dMaterial.Textures[0]->Flags & 0x2) //(Alpha mapped)
963 {
964 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
965 B3dMaterial.Material.ZWriteEnable = false;
966 }
967 else if (B3dMaterial.Textures[0]->Flags & 0x4) //(Masked)
968 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // TODO: create color key texture
969 else if (B3dMaterial.Textures[0]->Flags & 0x40)
970 B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP;
971 else if (B3dMaterial.Textures[0]->Flags & 0x80)
972 B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; // TODO: Should be cube map
973 else if (B3dMaterial.alpha == 1.f)
974 B3dMaterial.Material.MaterialType = video::EMT_SOLID;
975 else
976 {
977 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
978 B3dMaterial.Material.ZWriteEnable = false;
979 }
980 }
981 else //No texture:
982 {
983 if (B3dMaterial.alpha == 1.f)
984 B3dMaterial.Material.MaterialType = video::EMT_SOLID;
985 else
986 {
987 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
988 B3dMaterial.Material.ZWriteEnable = false;
989 }
990 }
991
992 B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor();
993 B3dMaterial.Material.ColorMaterial=video::ECM_NONE;
994
995 //------ Material fx ------
996
997 if (B3dMaterial.fx & 1) //full-bright
998 {
999 B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255);
1000 B3dMaterial.Material.Lighting = false;
1001 }
1002 else
1003 B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor;
1004
1005 if (B3dMaterial.fx & 2) //use vertex colors instead of brush color
1006 B3dMaterial.Material.ColorMaterial=video::ECM_DIFFUSE_AND_AMBIENT;
1007
1008 if (B3dMaterial.fx & 4) //flatshaded
1009 B3dMaterial.Material.GouraudShading = false;
1010
1011 if (B3dMaterial.fx & 16) //disable backface culling
1012 B3dMaterial.Material.BackfaceCulling = false;
1013
1014 if (B3dMaterial.fx & 32) //force vertex alpha-blending
1015 {
1016 B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
1017 B3dMaterial.Material.ZWriteEnable = false;
1018 }
1019
1020 B3dMaterial.Material.Shininess = B3dMaterial.shininess;
1021 }
1022
1023 B3dStack.erase(B3dStack.size()-1);
1024
1025 return true;
1026}
1027
1028
1029void CB3DMeshFileLoader::loadTextures(SB3dMaterial& material) const
1030{
1031 const bool previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
1032 SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
1033
1034 // read texture from disk
1035 // note that mipmaps might be disabled by Flags & 0x8
1036 const bool doMipMaps = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
1037
1038 for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
1039 {
1040 SB3dTexture* B3dTexture = material.Textures[i];
1041 if (B3dTexture && B3dTexture->TextureName.size() && !material.Material.getTexture(i))
1042 {
1043 if (!SceneManager->getParameters()->getAttributeAsBool(B3D_LOADER_IGNORE_MIPMAP_FLAG))
1044 SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false);
1045 {
1046 video::ITexture* tex = 0;
1047 io::IFileSystem* fs = SceneManager->getFileSystem();
1048 io::path texnameWithUserPath( SceneManager->getParameters()->getAttributeAsString(B3D_TEXTURE_PATH) );
1049 if ( texnameWithUserPath.size() )
1050 {
1051 texnameWithUserPath += '/';
1052 texnameWithUserPath += B3dTexture->TextureName;
1053 }
1054 if (fs->existFile(texnameWithUserPath))
1055 tex = SceneManager->getVideoDriver()->getTexture(texnameWithUserPath);
1056 else if (fs->existFile(B3dTexture->TextureName))
1057 tex = SceneManager->getVideoDriver()->getTexture(B3dTexture->TextureName);
1058 else if (fs->existFile(fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName)))
1059 tex = SceneManager->getVideoDriver()->getTexture(fs->getFileDir(B3DFile->getFileName()) +"/"+ fs->getFileBasename(B3dTexture->TextureName));
1060 else
1061 tex = SceneManager->getVideoDriver()->getTexture(fs->getFileBasename(B3dTexture->TextureName));
1062
1063 material.Material.setTexture(i, tex);
1064 }
1065 if (material.Textures[i]->Flags & 0x10) // Clamp U
1066 material.Material.TextureLayer[i].TextureWrapU=video::ETC_CLAMP;
1067 if (material.Textures[i]->Flags & 0x20) // Clamp V
1068 material.Material.TextureLayer[i].TextureWrapV=video::ETC_CLAMP;
1069 }
1070 }
1071
1072 SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, doMipMaps);
1073 SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, previous32BitTextureFlag);
1074}
1075
1076
1077void CB3DMeshFileLoader::readString(core::stringc& newstring)
1078{
1079 newstring="";
1080 while (B3DFile->getPos() <= B3DFile->getSize())
1081 {
1082 c8 character;
1083 B3DFile->read(&character, sizeof(character));
1084 if (character==0)
1085 return;
1086 newstring.append(character);
1087 }
1088}
1089
1090
1091void CB3DMeshFileLoader::readFloats(f32* vec, u32 count)
1092{
1093 B3DFile->read(vec, count*sizeof(f32));
1094 #ifdef __BIG_ENDIAN__
1095 for (u32 n=0; n<count; ++n)
1096 vec[n] = os::Byteswap::byteswap(vec[n]);
1097 #endif
1098}
1099
1100} // end namespace scene
1101} // end namespace irr
1102
1103
1104#endif // _IRR_COMPILE_WITH_B3D_LOADER_
1105