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