]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CDMFLoader.cpp
Merging r5975 through r6036 from trunk to ogl-es branch.
[irrlicht.git] / source / Irrlicht / CDMFLoader.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\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 // This file was originally written by Salvatore Russo.\r
6 // I (Nikolaus Gebhardt) did some minor modifications and changes to it and\r
7 // integrated it into Irrlicht.\r
8 // Thanks a lot to Salvatore for his work on this and that he gave me\r
9 // his permission to add it into Irrlicht using the zlib license.\r
10 /*\r
11   CDMFLoader by Salvatore Russo (September 2005)\r
12 \r
13   See the header file for additional information including use and distribution rights.\r
14 */\r
15 \r
16 #include "IrrCompileConfig.h"\r
17 #ifdef _IRR_COMPILE_WITH_DMF_LOADER_\r
18 \r
19 #ifdef _DEBUG\r
20 #define _IRR_DMF_DEBUG_\r
21 #include "os.h"\r
22 #endif\r
23 \r
24 #include "CDMFLoader.h"\r
25 #include "CMeshTextureLoader.h"\r
26 #include "ISceneManager.h"\r
27 #include "IAttributes.h"\r
28 #include "SAnimatedMesh.h"\r
29 #include "SSkinMeshBuffer.h"\r
30 #include "irrString.h"\r
31 #include "irrMath.h"\r
32 #include "dmfsupport.h"\r
33 \r
34 namespace irr\r
35 {\r
36 namespace scene\r
37 {\r
38 \r
39 /** Constructor*/\r
40 CDMFLoader::CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys)\r
41 : SceneMgr(smgr), FileSystem(filesys)\r
42 {\r
43         #ifdef _DEBUG\r
44         IReferenceCounted::setDebugName("CDMFLoader");\r
45         #endif\r
46 \r
47         TextureLoader = new CMeshTextureLoader( FileSystem, SceneMgr->getVideoDriver() );\r
48 }\r
49 \r
50 void CDMFLoader::addMaterialPath(core::stringc& filename, const core::stringc& matPath)\r
51 {\r
52         c8 last = matPath.lastChar();\r
53         if ( last == '/' || last == '\\' )\r
54                 filename = matPath+filename;\r
55         else\r
56         {\r
57                 core::stringc matPathSlash(matPath);\r
58                 matPathSlash.append('/');\r
59                 filename = matPathSlash+filename;\r
60         }\r
61 }\r
62 \r
63 \r
64 /**Creates/loads an animated mesh from the file.\r
65  \return Pointer to the created mesh. Returns 0 if loading failed.\r
66  If you no longer need the mesh, you should call IAnimatedMesh::drop().\r
67  See IReferenceCounted::drop() for more information.*/\r
68 IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file)\r
69 {\r
70         if (!file)\r
71                 return 0;\r
72 \r
73         if ( getMeshTextureLoader() )\r
74         {\r
75                 getMeshTextureLoader()->setMeshFile(file);\r
76 \r
77                 if ( SceneMgr->getParameters()->existsAttribute(DMF_TEXTURE_PATH) )\r
78                         getMeshTextureLoader()->setTexturePath( SceneMgr->getParameters()->getAttributeAsString(DMF_TEXTURE_PATH) );\r
79         }\r
80 \r
81         video::IVideoDriver* driver = SceneMgr->getVideoDriver();\r
82 \r
83         //Load stringlist\r
84         StringList dmfRawFile;\r
85         LoadFromFile(file, dmfRawFile);\r
86 \r
87         if (dmfRawFile.size()==0)\r
88                 return 0;\r
89 \r
90         SMesh * mesh = new SMesh();\r
91 \r
92         u32 i;\r
93 \r
94         dmfHeader header;\r
95 \r
96         //load header\r
97         core::array<dmfMaterial> materiali;\r
98         if (GetDMFHeader(dmfRawFile, header))\r
99         {\r
100                 //let's set ambient light\r
101                 SceneMgr->setAmbientLight(header.dmfAmbient);\r
102 \r
103                 //let's create the correct number of materials, vertices and faces\r
104                 dmfVert *verts=new dmfVert[header.numVertices];\r
105                 dmfFace *faces=new dmfFace[header.numFaces];\r
106 \r
107                 //let's get the materials\r
108 #ifdef _IRR_DMF_DEBUG_\r
109                 os::Printer::log("Loading materials", core::stringc(header.numMaterials).c_str());\r
110 #endif\r
111                 GetDMFMaterials(dmfRawFile, materiali, header.numMaterials);\r
112 \r
113                 //let's get vertices and faces\r
114 #ifdef _IRR_DMF_DEBUG_\r
115                 os::Printer::log("Loading geometry");\r
116 #endif\r
117                 GetDMFVerticesFaces(dmfRawFile, verts, faces);\r
118 \r
119                 //create a meshbuffer for each material, then we'll remove empty ones\r
120 #ifdef _IRR_DMF_DEBUG_\r
121                 os::Printer::log("Creating meshbuffers.");\r
122 #endif\r
123                 for (i=0; i<header.numMaterials; i++)\r
124                 {\r
125                         //create a new SMeshBufferLightMap for each material\r
126                         SSkinMeshBuffer* buffer = new SSkinMeshBuffer();\r
127                         buffer->Material.MaterialType = video::EMT_LIGHTMAP_LIGHTING;\r
128                         buffer->Material.Wireframe = false;\r
129                         buffer->Material.Lighting = true;\r
130                         mesh->addMeshBuffer(buffer);\r
131                         buffer->drop();\r
132                 }\r
133 \r
134                 // Build the mesh buffers\r
135 #ifdef _IRR_DMF_DEBUG_\r
136                 os::Printer::log("Adding geometry to mesh.");\r
137 #endif\r
138                 for (i = 0; i < header.numFaces; i++)\r
139                 {\r
140 #ifdef _IRR_DMF_DEBUG_\r
141                 os::Printer::log("Polygon with #vertices", core::stringc(faces[i].numVerts).c_str());\r
142 #endif\r
143                         if (faces[i].numVerts < 3)\r
144                                 continue;\r
145 \r
146                         const core::vector3df normal =\r
147                                 core::triangle3df(verts[faces[i].firstVert].pos,\r
148                                                 verts[faces[i].firstVert+1].pos,\r
149                                                 verts[faces[i].firstVert+2].pos).getNormal().normalize();\r
150 \r
151                         SSkinMeshBuffer* meshBuffer = (SSkinMeshBuffer*)mesh->getMeshBuffer(\r
152                                         faces[i].materialID);\r
153 \r
154                         const bool use2TCoords = meshBuffer->Vertices_2TCoords.size() ||\r
155                                 materiali[faces[i].materialID].lightmapName.size();\r
156                         if (use2TCoords && meshBuffer->Vertices_Standard.size())\r
157                                 meshBuffer->convertTo2TCoords();\r
158                         const u32 base = meshBuffer->Vertices_2TCoords.size()?meshBuffer->Vertices_2TCoords.size():meshBuffer->Vertices_Standard.size();\r
159 \r
160                         // Add this face's verts\r
161                         if (use2TCoords)\r
162                         {\r
163                                 // make sure we have the proper type set\r
164                                 meshBuffer->VertexType=video::EVT_2TCOORDS;\r
165                                 for (u32 v = 0; v < faces[i].numVerts; v++)\r
166                                 {\r
167                                         const dmfVert& vv = verts[faces[i].firstVert + v];\r
168                                         video::S3DVertex2TCoords vert(vv.pos,\r
169                                                 normal, video::SColor(255,255,255,255), vv.tc, vv.lc);\r
170                                         if (materiali[faces[i].materialID].textureBlend==4 &&\r
171                                                         SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))\r
172                                         {\r
173                                                 vert.TCoords.set(vv.tc.X,-vv.tc.Y);\r
174                                         }\r
175                                         meshBuffer->Vertices_2TCoords.push_back(vert);\r
176                                 }\r
177                         }\r
178                         else\r
179                         {\r
180                                 for (u32 v = 0; v < faces[i].numVerts; v++)\r
181                                 {\r
182                                         const dmfVert& vv = verts[faces[i].firstVert + v];\r
183                                         video::S3DVertex vert(vv.pos,\r
184                                                 normal, video::SColor(255,255,255,255), vv.tc);\r
185                                         if (materiali[faces[i].materialID].textureBlend==4 &&\r
186                                                         SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))\r
187                                         {\r
188                                                 vert.TCoords.set(vv.tc.X,-vv.tc.Y);\r
189                                         }\r
190                                         meshBuffer->Vertices_Standard.push_back(vert);\r
191                                 }\r
192                         }\r
193 \r
194                         // Now add the indices\r
195                         // This weird loop turns convex polygons into triangle strips.\r
196                         // I do it this way instead of a simple fan because it usually\r
197                         // looks a lot better in wireframe, for example.\r
198                         u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center\r
199                         for (u32 v = 0; v < faces[i].numVerts - 2; v++)\r
200                         {\r
201                                 if (v & 1) // odd\r
202                                         c = h - 1;\r
203                                 else // even\r
204                                         c = l + 1;\r
205 \r
206                                 meshBuffer->Indices.push_back(base + h);\r
207                                 meshBuffer->Indices.push_back(base + l);\r
208                                 meshBuffer->Indices.push_back(base + c);\r
209 \r
210                                 if (v & 1) // odd\r
211                                         h--;\r
212                                 else // even\r
213                                         l++;\r
214                         }\r
215                 }\r
216 \r
217                 delete [] verts;\r
218                 delete [] faces;\r
219         }\r
220 \r
221         // delete all buffers without geometry in it.\r
222 #ifdef _IRR_DMF_DEBUG_\r
223         os::Printer::log("Cleaning meshbuffers.");\r
224 #endif\r
225         i = 0;\r
226         while(i < mesh->MeshBuffers.size())\r
227         {\r
228                 if (mesh->MeshBuffers[i]->getVertexCount() == 0 ||\r
229                         mesh->MeshBuffers[i]->getIndexCount() == 0)\r
230                 {\r
231                         // Meshbuffer is empty -- drop it\r
232                         mesh->MeshBuffers[i]->drop();\r
233                         mesh->MeshBuffers.erase(i);\r
234                         materiali.erase(i);\r
235                 }\r
236                 else\r
237                 {\r
238                         i++;\r
239                 }\r
240         }\r
241 \r
242 \r
243         {\r
244                 //load textures and lightmaps in materials.\r
245                 //don't worry if you receive a could not load texture, cause if you don't need\r
246                 //a particular material in your scene it will be loaded and then destroyed.\r
247 #ifdef _IRR_DMF_DEBUG_\r
248                 os::Printer::log("Loading textures.");\r
249 #endif\r
250                 const bool use_mat_dirs=!SceneMgr->getParameters()->getAttributeAsBool(DMF_IGNORE_MATERIALS_DIRS);\r
251 \r
252                 for (i=0; i<mesh->getMeshBufferCount(); i++)\r
253                 {\r
254                         //texture and lightmap\r
255                         video::ITexture *tex = 0;\r
256                         video::ITexture *lig = 0;\r
257 \r
258                         //current buffer to apply material\r
259                         video::SMaterial& mat = mesh->getMeshBuffer(i)->getMaterial();\r
260 \r
261                         //Primary texture is normal\r
262                         if (materiali[i].textureFlag==0)\r
263                         {\r
264                                 if (materiali[i].textureBlend==4)\r
265                                         driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);\r
266 \r
267                                 if ( use_mat_dirs )\r
268                                         addMaterialPath(materiali[i].textureName, materiali[i].pathName);\r
269                                 tex = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture( materiali[i].textureName ) : NULL;\r
270                         }\r
271                         //Primary texture is just a color\r
272                         else if(materiali[i].textureFlag==1)\r
273                         {\r
274                                 video::SColor color(axtoi(materiali[i].textureName.c_str()));\r
275 \r
276                                 //just for compatibility with older Irrlicht versions\r
277                                 //to support transparent materials\r
278                                 if (color.getAlpha()!=255 && materiali[i].textureBlend==4)\r
279                                         driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);\r
280 \r
281                                 video::IImage *immagine= driver->createImage(video::ECF_A8R8G8B8,\r
282                                         core::dimension2d<u32>(8,8));\r
283                                 immagine->fill(color);\r
284                                 tex = driver->addTexture("", immagine);\r
285                                 immagine->drop();\r
286 \r
287                                 //to support transparent materials\r
288                                 if (color.getAlpha()!=255 && materiali[i].textureBlend==4)\r
289                                 {\r
290                                         mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;\r
291                                         mat.MaterialTypeParam =(((f32) (color.getAlpha()-1))/255.0f);\r
292                                 }\r
293                         }\r
294 \r
295                         //Lightmap is present\r
296                         if (materiali[i].lightmapFlag == 0)\r
297                         {\r
298                                 if ( use_mat_dirs )\r
299                                         addMaterialPath(materiali[i].lightmapName, materiali[i].pathName);\r
300                                 lig = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(materiali[i].lightmapName) : NULL;\r
301                         }\r
302                         else //no lightmap\r
303                         {\r
304                                 mat.MaterialType = video::EMT_SOLID;\r
305                                 const f32 mult = 100.0f - header.dmfShadow;\r
306                                 mat.AmbientColor=header.dmfAmbient.getInterpolated(video::SColor(255,0,0,0),mult/100.f);\r
307                         }\r
308 \r
309                         if (materiali[i].textureBlend==4)\r
310                         {\r
311                                 mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;\r
312                                 mat.MaterialTypeParam =\r
313                                         SceneMgr->getParameters()->getAttributeAsFloat(DMF_ALPHA_CHANNEL_REF);\r
314                         }\r
315 \r
316                         //if texture is present mirror vertically owing to DeleD representation\r
317                         if (tex && header.dmfVersion<1.1)\r
318                         {\r
319                                 const core::dimension2d<u32> texsize = tex->getSize();\r
320                                 void* pp = tex->lock();\r
321                                 if (pp)\r
322                                 {\r
323                                         const video::ECOLOR_FORMAT format = tex->getColorFormat();\r
324                                         if (format == video::ECF_A1R5G5B5)\r
325                                         {\r
326                                                 s16* p = (s16*)pp;\r
327                                                 s16 tmp=0;\r
328                                                 for (u32 x=0; x<texsize.Width; x++)\r
329                                                         for (u32 y=0; y<texsize.Height/2; y++)\r
330                                                         {\r
331                                                                 tmp=p[y*texsize.Width + x];\r
332                                                                 p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];\r
333                                                                 p[(texsize.Height-y-1)*texsize.Width + x]=tmp;\r
334                                                         }\r
335                                         }\r
336                                         else\r
337                                         if (format == video::ECF_A8R8G8B8)\r
338                                         {\r
339                                                 s32* p = (s32*)pp;\r
340                                                 s32 tmp=0;\r
341                                                 for (u32 x=0; x<texsize.Width; x++)\r
342                                                         for (u32 y=0; y<texsize.Height/2; y++)\r
343                                                         {\r
344                                                                 tmp=p[y*texsize.Width + x];\r
345                                                                 p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];\r
346                                                                 p[(texsize.Height-y-1)*texsize.Width + x]=tmp;\r
347                                                         }\r
348                                         }\r
349                                 }\r
350                                 tex->unlock();\r
351                                 tex->regenerateMipMapLevels();\r
352                         }\r
353 \r
354                         //if lightmap is present mirror vertically owing to DeleD rapresentation\r
355                         if (lig && header.dmfVersion<1.1)\r
356                         {\r
357                                 const core::dimension2d<u32> ligsize=lig->getSize();\r
358                                 void* pp = lig->lock();\r
359                                 if (pp)\r
360                                 {\r
361                                         video::ECOLOR_FORMAT format = lig->getColorFormat();\r
362                                         if (format == video::ECF_A1R5G5B5)\r
363                                         {\r
364                                                 s16* p = (s16*)pp;\r
365                                                 s16 tmp=0;\r
366                                                 for (u32 x=0; x<ligsize.Width; x++)\r
367                                                 {\r
368                                                         for (u32 y=0; y<ligsize.Height/2; y++)\r
369                                                         {\r
370                                                                 tmp=p[y*ligsize.Width + x];\r
371                                                                 p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];\r
372                                                                 p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;\r
373                                                         }\r
374                                                 }\r
375                                         }\r
376                                         else if (format == video::ECF_A8R8G8B8)\r
377                                         {\r
378                                                 s32* p = (s32*)pp;\r
379                                                 s32 tmp=0;\r
380                                                 for (u32 x=0; x<ligsize.Width; x++)\r
381                                                 {\r
382                                                         for (u32 y=0; y<ligsize.Height/2; y++)\r
383                                                         {\r
384                                                                 tmp=p[y*ligsize.Width + x];\r
385                                                                 p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];\r
386                                                                 p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;\r
387                                                         }\r
388                                                 }\r
389                                         }\r
390                                 }\r
391                                 lig->unlock();\r
392                                 lig->regenerateMipMapLevels();\r
393                         }\r
394 \r
395                         mat.setTexture(0, tex);\r
396                         mat.setTexture(1, lig);\r
397                 }\r
398         }\r
399 \r
400         // create bounding box\r
401         for (i = 0; i < mesh->MeshBuffers.size(); ++i)\r
402         {\r
403                 mesh->MeshBuffers[i]->recalculateBoundingBox();\r
404         }\r
405         mesh->recalculateBoundingBox();\r
406 \r
407         // Set up an animated mesh to hold the mesh\r
408         SAnimatedMesh* AMesh = new SAnimatedMesh();\r
409         AMesh->Type = EAMT_UNKNOWN;\r
410         AMesh->addMesh(mesh);\r
411         AMesh->recalculateBoundingBox();\r
412         mesh->drop();\r
413 \r
414         return AMesh;\r
415 }\r
416 \r
417 \r
418 /** \brief Tell us if this file is able to be loaded by this class\r
419  based on the file extension (e.g. ".bsp")\r
420  \return true if file is loadable.*/\r
421 bool CDMFLoader::isALoadableFileExtension(const io::path& filename) const\r
422 {\r
423         return core::hasFileExtension ( filename, "dmf" );\r
424 }\r
425 \r
426 \r
427 } // end namespace scene\r
428 } // end namespace irr\r
429 \r
430 #endif // _IRR_COMPILE_WITH_DMF_LOADER_\r
431 \r