/Irrlicht/CDMFLoader.cpp

http://myjeh.googlecode.com/ · C++ · 437 lines · 324 code · 52 blank · 61 comment · 77 complexity · 316aa51d20b2330c248fe4a46158f189 MD5 · raw file

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