1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
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.
11
CDMFLoader by Salvatore Russo (September 2005)
13
See the header file for additional information including use and distribution rights.
16
#include "IrrCompileConfig.h"
17
#ifdef _IRR_COMPILE_WITH_DMF_LOADER_
20
#define _IRR_DMF_DEBUG_
24
#include "CDMFLoader.h"
25
#include "ISceneManager.h"
26
#include "IAttributes.h"
27
#include "SAnimatedMesh.h"
28
#include "SSkinMeshBuffer.h"
29
#include "irrString.h"
31
#include "dmfsupport.h"
39
CDMFLoader::CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys)
40
: SceneMgr(smgr), FileSystem(filesys)
43
IReferenceCounted::setDebugName("CDMFLoader");
48
void CDMFLoader::findFile(bool use_mat_dirs, const core::stringc& path, const core::stringc& matPath, core::stringc& filename)
50
// path + texpath + full name
51
if (use_mat_dirs && FileSystem->existFile(path+matPath+filename))
52
filename = path+matPath+filename;
54
else if (FileSystem->existFile(path+filename))
55
filename = path+filename;
56
// path + texpath + base name
57
else if (use_mat_dirs && FileSystem->existFile(path+matPath+FileSystem->getFileBasename(filename)))
58
filename = path+matPath+FileSystem->getFileBasename(filename);
60
else if (FileSystem->existFile(path+FileSystem->getFileBasename(filename)))
61
filename = path+FileSystem->getFileBasename(filename);
62
// texpath + full name
63
else if (use_mat_dirs && FileSystem->existFile(matPath+filename))
64
filename = matPath+filename;
65
// texpath + base name
66
else if (use_mat_dirs && FileSystem->existFile(matPath+FileSystem->getFileBasename(filename)))
67
filename = matPath+FileSystem->getFileBasename(filename);
69
else if (FileSystem->existFile(FileSystem->getFileBasename(filename)))
70
filename = FileSystem->getFileBasename(filename);
74
/**Creates/loads an animated mesh from the file.
75
\return Pointer to the created mesh. Returns 0 if loading failed.
76
If you no longer need the mesh, you should call IAnimatedMesh::drop().
77
See IReferenceCounted::drop() for more information.*/
78
IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file)
82
video::IVideoDriver* driver = SceneMgr->getVideoDriver();
85
StringList dmfRawFile;
86
LoadFromFile(file, dmfRawFile);
88
if (dmfRawFile.size()==0)
91
SMesh * mesh = new SMesh();
98
core::array<dmfMaterial> materiali;
99
if (GetDMFHeader(dmfRawFile, header))
101
//let's set ambient light
102
SceneMgr->setAmbientLight(header.dmfAmbient);
104
//let's create the correct number of materials, vertices and faces
105
dmfVert *verts=new dmfVert[header.numVertices];
106
dmfFace *faces=new dmfFace[header.numFaces];
108
//let's get the materials
109
#ifdef _IRR_DMF_DEBUG_
110
os::Printer::log("Loading materials", core::stringc(header.numMaterials).c_str());
112
GetDMFMaterials(dmfRawFile, materiali, header.numMaterials);
114
//let's get vertices and faces
115
#ifdef _IRR_DMF_DEBUG_
116
os::Printer::log("Loading geometry");
118
GetDMFVerticesFaces(dmfRawFile, verts, faces);
120
//create a meshbuffer for each material, then we'll remove empty ones
121
#ifdef _IRR_DMF_DEBUG_
122
os::Printer::log("Creating meshbuffers.");
124
for (i=0; i<header.numMaterials; i++)
126
//create a new SMeshBufferLightMap for each material
127
SSkinMeshBuffer* buffer = new SSkinMeshBuffer();
128
buffer->Material.MaterialType = video::EMT_LIGHTMAP_LIGHTING;
129
buffer->Material.Wireframe = false;
130
buffer->Material.Lighting = true;
131
mesh->addMeshBuffer(buffer);
135
// Build the mesh buffers
136
#ifdef _IRR_DMF_DEBUG_
137
os::Printer::log("Adding geometry to mesh.");
139
for (i = 0; i < header.numFaces; i++)
141
#ifdef _IRR_DMF_DEBUG_
142
os::Printer::log("Polygon with #vertices", core::stringc(faces[i].numVerts).c_str());
144
if (faces[i].numVerts < 3)
147
const core::vector3df normal =
148
core::triangle3df(verts[faces[i].firstVert].pos,
149
verts[faces[i].firstVert+1].pos,
150
verts[faces[i].firstVert+2].pos).getNormal().normalize();
152
SSkinMeshBuffer* meshBuffer = (SSkinMeshBuffer*)mesh->getMeshBuffer(
153
faces[i].materialID);
155
const bool use2TCoords = meshBuffer->Vertices_2TCoords.size() ||
156
materiali[faces[i].materialID].lightmapName.size();
157
if (use2TCoords && meshBuffer->Vertices_Standard.size())
158
meshBuffer->convertTo2TCoords();
159
const u32 base = meshBuffer->Vertices_2TCoords.size()?meshBuffer->Vertices_2TCoords.size():meshBuffer->Vertices_Standard.size();
161
// Add this face's verts
164
// make sure we have the proper type set
165
meshBuffer->VertexType=video::EVT_2TCOORDS;
166
for (u32 v = 0; v < faces[i].numVerts; v++)
168
const dmfVert& vv = verts[faces[i].firstVert + v];
169
video::S3DVertex2TCoords vert(vv.pos,
170
normal, video::SColor(255,255,255,255), vv.tc, vv.lc);
171
if (materiali[faces[i].materialID].textureBlend==4 &&
172
SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))
174
vert.TCoords.set(vv.tc.X,-vv.tc.Y);
176
meshBuffer->Vertices_2TCoords.push_back(vert);
181
for (u32 v = 0; v < faces[i].numVerts; v++)
183
const dmfVert& vv = verts[faces[i].firstVert + v];
184
video::S3DVertex vert(vv.pos,
185
normal, video::SColor(255,255,255,255), vv.tc);
186
if (materiali[faces[i].materialID].textureBlend==4 &&
187
SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))
189
vert.TCoords.set(vv.tc.X,-vv.tc.Y);
191
meshBuffer->Vertices_Standard.push_back(vert);
195
// Now add the indices
196
// This weird loop turns convex polygons into triangle strips.
197
// I do it this way instead of a simple fan because it usually
198
// looks a lot better in wireframe, for example.
199
u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center
200
for (u32 v = 0; v < faces[i].numVerts - 2; v++)
207
meshBuffer->Indices.push_back(base + h);
208
meshBuffer->Indices.push_back(base + l);
209
meshBuffer->Indices.push_back(base + c);
222
// delete all buffers without geometry in it.
223
#ifdef _IRR_DMF_DEBUG_
224
os::Printer::log("Cleaning meshbuffers.");
227
while(i < mesh->MeshBuffers.size())
229
if (mesh->MeshBuffers[i]->getVertexCount() == 0 ||
230
mesh->MeshBuffers[i]->getIndexCount() == 0)
232
// Meshbuffer is empty -- drop it
233
mesh->MeshBuffers[i]->drop();
234
mesh->MeshBuffers.erase(i);
245
//load textures and lightmaps in materials.
246
//don't worry if you receive a could not load texture, cause if you don't need
247
//a particular material in your scene it will be loaded and then destroyed.
248
#ifdef _IRR_DMF_DEBUG_
249
os::Printer::log("Loading textures.");
251
const bool use_mat_dirs=!SceneMgr->getParameters()->getAttributeAsBool(DMF_IGNORE_MATERIALS_DIRS);
254
if ( SceneMgr->getParameters()->existsAttribute(DMF_TEXTURE_PATH) )
255
path = SceneMgr->getParameters()->getAttributeAsString(DMF_TEXTURE_PATH);
257
path = FileSystem->getFileDir(file->getFileName());
260
for (i=0; i<mesh->getMeshBufferCount(); i++)
262
//texture and lightmap
263
video::ITexture *tex = 0;
264
video::ITexture *lig = 0;
266
//current buffer to apply material
267
video::SMaterial& mat = mesh->getMeshBuffer(i)->getMaterial();
269
//Primary texture is normal
270
if (materiali[i].textureFlag==0)
272
if (materiali[i].textureBlend==4)
273
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
274
findFile(use_mat_dirs, path, materiali[i].pathName, materiali[i].textureName);
275
tex = driver->getTexture(materiali[i].textureName);
277
//Primary texture is just a colour
278
else if(materiali[i].textureFlag==1)
280
video::SColor color(axtoi(materiali[i].textureName.c_str()));
282
//just for compatibility with older Irrlicht versions
283
//to support transparent materials
284
if (color.getAlpha()!=255 && materiali[i].textureBlend==4)
285
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
287
video::IImage *immagine= driver->createImage(video::ECF_A8R8G8B8,
288
core::dimension2d<u32>(8,8));
289
immagine->fill(color);
290
tex = driver->addTexture("", immagine);
293
//to support transparent materials
294
if (color.getAlpha()!=255 && materiali[i].textureBlend==4)
296
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
297
mat.MaterialTypeParam =(((f32) (color.getAlpha()-1))/255.0f);
301
//Lightmap is present
302
if (materiali[i].lightmapFlag == 0)
304
findFile(use_mat_dirs, path, materiali[i].pathName, materiali[i].lightmapName);
305
lig = driver->getTexture(materiali[i].lightmapName);
309
mat.MaterialType = video::EMT_SOLID;
310
const f32 mult = 100.0f - header.dmfShadow;
311
mat.AmbientColor=header.dmfAmbient.getInterpolated(video::SColor(255,0,0,0),mult/100.f);
314
if (materiali[i].textureBlend==4)
316
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
317
mat.MaterialTypeParam =
318
SceneMgr->getParameters()->getAttributeAsFloat(DMF_ALPHA_CHANNEL_REF);
321
//if texture is present mirror vertically owing to DeleD representation
322
if (tex && header.dmfVersion<1.1)
324
const core::dimension2d<u32> texsize = tex->getSize();
325
void* pp = tex->lock();
328
const video::ECOLOR_FORMAT format = tex->getColorFormat();
329
if (format == video::ECF_A1R5G5B5)
333
for (u32 x=0; x<texsize.Width; x++)
334
for (u32 y=0; y<texsize.Height/2; y++)
336
tmp=p[y*texsize.Width + x];
337
p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];
338
p[(texsize.Height-y-1)*texsize.Width + x]=tmp;
342
if (format == video::ECF_A8R8G8B8)
346
for (u32 x=0; x<texsize.Width; x++)
347
for (u32 y=0; y<texsize.Height/2; y++)
349
tmp=p[y*texsize.Width + x];
350
p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];
351
p[(texsize.Height-y-1)*texsize.Width + x]=tmp;
356
tex->regenerateMipMapLevels();
359
//if lightmap is present mirror vertically owing to DeleD rapresentation
360
if (lig && header.dmfVersion<1.1)
362
const core::dimension2d<u32> ligsize=lig->getSize();
363
void* pp = lig->lock();
366
video::ECOLOR_FORMAT format = lig->getColorFormat();
367
if (format == video::ECF_A1R5G5B5)
371
for (u32 x=0; x<ligsize.Width; x++)
373
for (u32 y=0; y<ligsize.Height/2; y++)
375
tmp=p[y*ligsize.Width + x];
376
p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];
377
p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;
381
else if (format == video::ECF_A8R8G8B8)
385
for (u32 x=0; x<ligsize.Width; x++)
387
for (u32 y=0; y<ligsize.Height/2; y++)
389
tmp=p[y*ligsize.Width + x];
390
p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];
391
p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;
397
lig->regenerateMipMapLevels();
400
mat.setTexture(0, tex);
401
mat.setTexture(1, lig);
405
// create bounding box
406
for (i = 0; i < mesh->MeshBuffers.size(); ++i)
408
mesh->MeshBuffers[i]->recalculateBoundingBox();
410
mesh->recalculateBoundingBox();
412
// Set up an animated mesh to hold the mesh
413
SAnimatedMesh* AMesh = new SAnimatedMesh();
414
AMesh->Type = EAMT_UNKNOWN;
415
AMesh->addMesh(mesh);
416
AMesh->recalculateBoundingBox();
423
/** \brief Tell us if this file is able to be loaded by this class
424
based on the file extension (e.g. ".bsp")
425
\return true if file is loadable.*/
426
bool CDMFLoader::isALoadableFileExtension(const io::path& filename) const
428
return core::hasFileExtension ( filename, "dmf" );
432
} // end namespace scene
433
} // end namespace irr
435
#endif // _IRR_COMPILE_WITH_DMF_LOADER_