PageRenderTime 85ms CodeModel.GetById 30ms app.highlight 44ms RepoModel.GetById 2ms app.codeStats 1ms

/Irrlicht/CDMFLoader.cpp

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