diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/COBJMeshFileLoader.cpp | 931 |
1 files changed, 0 insertions, 931 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/COBJMeshFileLoader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/COBJMeshFileLoader.cpp deleted file mode 100644 index 2bda5e8..0000000 --- a/libraries/irrlicht-1.8/source/Irrlicht/COBJMeshFileLoader.cpp +++ /dev/null | |||
@@ -1,931 +0,0 @@ | |||
1 | // Copyright (C) 2002-2012 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 | #include "IrrCompileConfig.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ | ||
7 | |||
8 | #include "COBJMeshFileLoader.h" | ||
9 | #include "IMeshManipulator.h" | ||
10 | #include "IVideoDriver.h" | ||
11 | #include "SMesh.h" | ||
12 | #include "SMeshBuffer.h" | ||
13 | #include "SAnimatedMesh.h" | ||
14 | #include "IReadFile.h" | ||
15 | #include "IAttributes.h" | ||
16 | #include "fast_atof.h" | ||
17 | #include "coreutil.h" | ||
18 | #include "os.h" | ||
19 | |||
20 | namespace irr | ||
21 | { | ||
22 | namespace scene | ||
23 | { | ||
24 | |||
25 | #ifdef _DEBUG | ||
26 | #define _IRR_DEBUG_OBJ_LOADER_ | ||
27 | #endif | ||
28 | |||
29 | static const u32 WORD_BUFFER_LENGTH = 512; | ||
30 | |||
31 | //! Constructor | ||
32 | COBJMeshFileLoader::COBJMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs) | ||
33 | : SceneManager(smgr), FileSystem(fs) | ||
34 | { | ||
35 | #ifdef _DEBUG | ||
36 | setDebugName("COBJMeshFileLoader"); | ||
37 | #endif | ||
38 | |||
39 | if (FileSystem) | ||
40 | FileSystem->grab(); | ||
41 | } | ||
42 | |||
43 | |||
44 | //! destructor | ||
45 | COBJMeshFileLoader::~COBJMeshFileLoader() | ||
46 | { | ||
47 | if (FileSystem) | ||
48 | FileSystem->drop(); | ||
49 | } | ||
50 | |||
51 | |||
52 | //! returns true if the file maybe is able to be loaded by this class | ||
53 | //! based on the file extension (e.g. ".bsp") | ||
54 | bool COBJMeshFileLoader::isALoadableFileExtension(const io::path& filename) const | ||
55 | { | ||
56 | return core::hasFileExtension ( filename, "obj" ); | ||
57 | } | ||
58 | |||
59 | |||
60 | //! creates/loads an animated mesh from the file. | ||
61 | //! \return Pointer to the created mesh. Returns 0 if loading failed. | ||
62 | //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). | ||
63 | //! See IReferenceCounted::drop() for more information. | ||
64 | IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file) | ||
65 | { | ||
66 | const long filesize = file->getSize(); | ||
67 | if (!filesize) | ||
68 | return 0; | ||
69 | |||
70 | const u32 WORD_BUFFER_LENGTH = 512; | ||
71 | |||
72 | core::array<core::vector3df> vertexBuffer; | ||
73 | core::array<core::vector3df> normalsBuffer; | ||
74 | core::array<core::vector2df> textureCoordBuffer; | ||
75 | |||
76 | SObjMtl * currMtl = new SObjMtl(); | ||
77 | Materials.push_back(currMtl); | ||
78 | u32 smoothingGroup=0; | ||
79 | |||
80 | const io::path fullName = file->getFileName(); | ||
81 | const io::path relPath = FileSystem->getFileDir(fullName)+"/"; | ||
82 | |||
83 | c8* buf = new c8[filesize]; | ||
84 | memset(buf, 0, filesize); | ||
85 | file->read((void*)buf, filesize); | ||
86 | const c8* const bufEnd = buf+filesize; | ||
87 | |||
88 | // Process obj information | ||
89 | const c8* bufPtr = buf; | ||
90 | core::stringc grpName, mtlName; | ||
91 | bool mtlChanged=false; | ||
92 | bool useGroups = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_GROUPS); | ||
93 | bool useMaterials = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_MATERIAL_FILES); | ||
94 | while(bufPtr != bufEnd) | ||
95 | { | ||
96 | switch(bufPtr[0]) | ||
97 | { | ||
98 | case 'm': // mtllib (material) | ||
99 | { | ||
100 | if (useMaterials) | ||
101 | { | ||
102 | c8 name[WORD_BUFFER_LENGTH]; | ||
103 | bufPtr = goAndCopyNextWord(name, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
104 | #ifdef _IRR_DEBUG_OBJ_LOADER_ | ||
105 | os::Printer::log("Reading material file",name); | ||
106 | #endif | ||
107 | readMTL(name, relPath); | ||
108 | } | ||
109 | } | ||
110 | break; | ||
111 | |||
112 | case 'v': // v, vn, vt | ||
113 | switch(bufPtr[1]) | ||
114 | { | ||
115 | case ' ': // vertex | ||
116 | { | ||
117 | core::vector3df vec; | ||
118 | bufPtr = readVec3(bufPtr, vec, bufEnd); | ||
119 | vertexBuffer.push_back(vec); | ||
120 | } | ||
121 | break; | ||
122 | |||
123 | case 'n': // normal | ||
124 | { | ||
125 | core::vector3df vec; | ||
126 | bufPtr = readVec3(bufPtr, vec, bufEnd); | ||
127 | normalsBuffer.push_back(vec); | ||
128 | } | ||
129 | break; | ||
130 | |||
131 | case 't': // texcoord | ||
132 | { | ||
133 | core::vector2df vec; | ||
134 | bufPtr = readUV(bufPtr, vec, bufEnd); | ||
135 | textureCoordBuffer.push_back(vec); | ||
136 | } | ||
137 | break; | ||
138 | } | ||
139 | break; | ||
140 | |||
141 | case 'g': // group name | ||
142 | { | ||
143 | c8 grp[WORD_BUFFER_LENGTH]; | ||
144 | bufPtr = goAndCopyNextWord(grp, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
145 | #ifdef _IRR_DEBUG_OBJ_LOADER_ | ||
146 | os::Printer::log("Loaded group start",grp, ELL_DEBUG); | ||
147 | #endif | ||
148 | if (useGroups) | ||
149 | { | ||
150 | if (0 != grp[0]) | ||
151 | grpName = grp; | ||
152 | else | ||
153 | grpName = "default"; | ||
154 | } | ||
155 | mtlChanged=true; | ||
156 | } | ||
157 | break; | ||
158 | |||
159 | case 's': // smoothing can be a group or off (equiv. to 0) | ||
160 | { | ||
161 | c8 smooth[WORD_BUFFER_LENGTH]; | ||
162 | bufPtr = goAndCopyNextWord(smooth, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
163 | #ifdef _IRR_DEBUG_OBJ_LOADER_ | ||
164 | os::Printer::log("Loaded smoothing group start",smooth, ELL_DEBUG); | ||
165 | #endif | ||
166 | if (core::stringc("off")==smooth) | ||
167 | smoothingGroup=0; | ||
168 | else | ||
169 | smoothingGroup=core::strtoul10(smooth); | ||
170 | } | ||
171 | break; | ||
172 | |||
173 | case 'u': // usemtl | ||
174 | // get name of material | ||
175 | { | ||
176 | c8 matName[WORD_BUFFER_LENGTH]; | ||
177 | bufPtr = goAndCopyNextWord(matName, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
178 | #ifdef _IRR_DEBUG_OBJ_LOADER_ | ||
179 | os::Printer::log("Loaded material start",matName, ELL_DEBUG); | ||
180 | #endif | ||
181 | mtlName=matName; | ||
182 | mtlChanged=true; | ||
183 | } | ||
184 | break; | ||
185 | |||
186 | case 'f': // face | ||
187 | { | ||
188 | c8 vertexWord[WORD_BUFFER_LENGTH]; // for retrieving vertex data | ||
189 | video::S3DVertex v; | ||
190 | // Assign vertex color from currently active material's diffuse color | ||
191 | if (mtlChanged) | ||
192 | { | ||
193 | // retrieve the material | ||
194 | SObjMtl *useMtl = findMtl(mtlName, grpName); | ||
195 | // only change material if we found it | ||
196 | if (useMtl) | ||
197 | currMtl = useMtl; | ||
198 | mtlChanged=false; | ||
199 | } | ||
200 | if (currMtl) | ||
201 | v.Color = currMtl->Meshbuffer->Material.DiffuseColor; | ||
202 | |||
203 | // get all vertices data in this face (current line of obj file) | ||
204 | const core::stringc wordBuffer = copyLine(bufPtr, bufEnd); | ||
205 | const c8* linePtr = wordBuffer.c_str(); | ||
206 | const c8* const endPtr = linePtr+wordBuffer.size(); | ||
207 | |||
208 | core::array<int> faceCorners; | ||
209 | faceCorners.reallocate(32); // should be large enough | ||
210 | |||
211 | // read in all vertices | ||
212 | linePtr = goNextWord(linePtr, endPtr); | ||
213 | while (0 != linePtr[0]) | ||
214 | { | ||
215 | // Array to communicate with retrieveVertexIndices() | ||
216 | // sends the buffer sizes and gets the actual indices | ||
217 | // if index not set returns -1 | ||
218 | s32 Idx[3]; | ||
219 | Idx[1] = Idx[2] = -1; | ||
220 | |||
221 | // read in next vertex's data | ||
222 | u32 wlength = copyWord(vertexWord, linePtr, WORD_BUFFER_LENGTH, endPtr); | ||
223 | // this function will also convert obj's 1-based index to c++'s 0-based index | ||
224 | retrieveVertexIndices(vertexWord, Idx, vertexWord+wlength+1, vertexBuffer.size(), textureCoordBuffer.size(), normalsBuffer.size()); | ||
225 | v.Pos = vertexBuffer[Idx[0]]; | ||
226 | if ( -1 != Idx[1] ) | ||
227 | v.TCoords = textureCoordBuffer[Idx[1]]; | ||
228 | else | ||
229 | v.TCoords.set(0.0f,0.0f); | ||
230 | if ( -1 != Idx[2] ) | ||
231 | v.Normal = normalsBuffer[Idx[2]]; | ||
232 | else | ||
233 | { | ||
234 | v.Normal.set(0.0f,0.0f,0.0f); | ||
235 | currMtl->RecalculateNormals=true; | ||
236 | } | ||
237 | |||
238 | int vertLocation; | ||
239 | core::map<video::S3DVertex, int>::Node* n = currMtl->VertMap.find(v); | ||
240 | if (n) | ||
241 | { | ||
242 | vertLocation = n->getValue(); | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | currMtl->Meshbuffer->Vertices.push_back(v); | ||
247 | vertLocation = currMtl->Meshbuffer->Vertices.size() -1; | ||
248 | currMtl->VertMap.insert(v, vertLocation); | ||
249 | } | ||
250 | |||
251 | faceCorners.push_back(vertLocation); | ||
252 | |||
253 | // go to next vertex | ||
254 | linePtr = goNextWord(linePtr, endPtr); | ||
255 | } | ||
256 | |||
257 | // triangulate the face | ||
258 | for ( u32 i = 1; i < faceCorners.size() - 1; ++i ) | ||
259 | { | ||
260 | // Add a triangle | ||
261 | currMtl->Meshbuffer->Indices.push_back( faceCorners[i+1] ); | ||
262 | currMtl->Meshbuffer->Indices.push_back( faceCorners[i] ); | ||
263 | currMtl->Meshbuffer->Indices.push_back( faceCorners[0] ); | ||
264 | } | ||
265 | faceCorners.set_used(0); // fast clear | ||
266 | faceCorners.reallocate(32); | ||
267 | } | ||
268 | break; | ||
269 | |||
270 | case '#': // comment | ||
271 | default: | ||
272 | break; | ||
273 | } // end switch(bufPtr[0]) | ||
274 | // eat up rest of line | ||
275 | bufPtr = goNextLine(bufPtr, bufEnd); | ||
276 | } // end while(bufPtr && (bufPtr-buf<filesize)) | ||
277 | |||
278 | SMesh* mesh = new SMesh(); | ||
279 | |||
280 | // Combine all the groups (meshbuffers) into the mesh | ||
281 | for ( u32 m = 0; m < Materials.size(); ++m ) | ||
282 | { | ||
283 | if ( Materials[m]->Meshbuffer->getIndexCount() > 0 ) | ||
284 | { | ||
285 | Materials[m]->Meshbuffer->recalculateBoundingBox(); | ||
286 | if (Materials[m]->RecalculateNormals) | ||
287 | SceneManager->getMeshManipulator()->recalculateNormals(Materials[m]->Meshbuffer); | ||
288 | if (Materials[m]->Meshbuffer->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID) | ||
289 | { | ||
290 | SMesh tmp; | ||
291 | tmp.addMeshBuffer(Materials[m]->Meshbuffer); | ||
292 | IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp); | ||
293 | mesh->addMeshBuffer(tangentMesh->getMeshBuffer(0)); | ||
294 | tangentMesh->drop(); | ||
295 | } | ||
296 | else | ||
297 | mesh->addMeshBuffer( Materials[m]->Meshbuffer ); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // Create the Animated mesh if there's anything in the mesh | ||
302 | SAnimatedMesh* animMesh = 0; | ||
303 | if ( 0 != mesh->getMeshBufferCount() ) | ||
304 | { | ||
305 | mesh->recalculateBoundingBox(); | ||
306 | animMesh = new SAnimatedMesh(); | ||
307 | animMesh->Type = EAMT_OBJ; | ||
308 | animMesh->addMesh(mesh); | ||
309 | animMesh->recalculateBoundingBox(); | ||
310 | } | ||
311 | |||
312 | // Clean up the allocate obj file contents | ||
313 | delete [] buf; | ||
314 | // more cleaning up | ||
315 | cleanUp(); | ||
316 | mesh->drop(); | ||
317 | |||
318 | return animMesh; | ||
319 | } | ||
320 | |||
321 | |||
322 | const c8* COBJMeshFileLoader::readTextures(const c8* bufPtr, const c8* const bufEnd, SObjMtl* currMaterial, const io::path& relPath) | ||
323 | { | ||
324 | u8 type=0; // map_Kd - diffuse color texture map | ||
325 | // map_Ks - specular color texture map | ||
326 | // map_Ka - ambient color texture map | ||
327 | // map_Ns - shininess texture map | ||
328 | if ((!strncmp(bufPtr,"map_bump",8)) || (!strncmp(bufPtr,"bump",4))) | ||
329 | type=1; // normal map | ||
330 | else if ((!strncmp(bufPtr,"map_d",5)) || (!strncmp(bufPtr,"map_opacity",11))) | ||
331 | type=2; // opacity map | ||
332 | else if (!strncmp(bufPtr,"map_refl",8)) | ||
333 | type=3; // reflection map | ||
334 | // extract new material's name | ||
335 | c8 textureNameBuf[WORD_BUFFER_LENGTH]; | ||
336 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
337 | |||
338 | f32 bumpiness = 6.0f; | ||
339 | bool clamp = false; | ||
340 | // handle options | ||
341 | while (textureNameBuf[0]=='-') | ||
342 | { | ||
343 | if (!strncmp(bufPtr,"-bm",3)) | ||
344 | { | ||
345 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
346 | currMaterial->Meshbuffer->Material.MaterialTypeParam=core::fast_atof(textureNameBuf); | ||
347 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
348 | continue; | ||
349 | } | ||
350 | else | ||
351 | if (!strncmp(bufPtr,"-blendu",7)) | ||
352 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
353 | else | ||
354 | if (!strncmp(bufPtr,"-blendv",7)) | ||
355 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
356 | else | ||
357 | if (!strncmp(bufPtr,"-cc",3)) | ||
358 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
359 | else | ||
360 | if (!strncmp(bufPtr,"-clamp",6)) | ||
361 | bufPtr = readBool(bufPtr, clamp, bufEnd); | ||
362 | else | ||
363 | if (!strncmp(bufPtr,"-texres",7)) | ||
364 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
365 | else | ||
366 | if (!strncmp(bufPtr,"-type",5)) | ||
367 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
368 | else | ||
369 | if (!strncmp(bufPtr,"-mm",3)) | ||
370 | { | ||
371 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
372 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
373 | } | ||
374 | else | ||
375 | if (!strncmp(bufPtr,"-o",2)) // texture coord translation | ||
376 | { | ||
377 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
378 | // next parameters are optional, so skip rest of loop if no number is found | ||
379 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
380 | if (!core::isdigit(textureNameBuf[0])) | ||
381 | continue; | ||
382 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
383 | if (!core::isdigit(textureNameBuf[0])) | ||
384 | continue; | ||
385 | } | ||
386 | else | ||
387 | if (!strncmp(bufPtr,"-s",2)) // texture coord scale | ||
388 | { | ||
389 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
390 | // next parameters are optional, so skip rest of loop if no number is found | ||
391 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
392 | if (!core::isdigit(textureNameBuf[0])) | ||
393 | continue; | ||
394 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
395 | if (!core::isdigit(textureNameBuf[0])) | ||
396 | continue; | ||
397 | } | ||
398 | else | ||
399 | if (!strncmp(bufPtr,"-t",2)) | ||
400 | { | ||
401 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
402 | // next parameters are optional, so skip rest of loop if no number is found | ||
403 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
404 | if (!core::isdigit(textureNameBuf[0])) | ||
405 | continue; | ||
406 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
407 | if (!core::isdigit(textureNameBuf[0])) | ||
408 | continue; | ||
409 | } | ||
410 | // get next word | ||
411 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
412 | } | ||
413 | |||
414 | if ((type==1) && (core::isdigit(textureNameBuf[0]))) | ||
415 | { | ||
416 | currMaterial->Meshbuffer->Material.MaterialTypeParam=core::fast_atof(textureNameBuf); | ||
417 | bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
418 | } | ||
419 | if (clamp) | ||
420 | currMaterial->Meshbuffer->Material.setFlag(video::EMF_TEXTURE_WRAP, video::ETC_CLAMP); | ||
421 | |||
422 | io::path texname(textureNameBuf); | ||
423 | texname.replace('\\', '/'); | ||
424 | |||
425 | video::ITexture * texture = 0; | ||
426 | bool newTexture=false; | ||
427 | if (texname.size()) | ||
428 | { | ||
429 | io::path texnameWithUserPath( SceneManager->getParameters()->getAttributeAsString(OBJ_TEXTURE_PATH) ); | ||
430 | if ( texnameWithUserPath.size() ) | ||
431 | { | ||
432 | texnameWithUserPath += '/'; | ||
433 | texnameWithUserPath += texname; | ||
434 | } | ||
435 | if (FileSystem->existFile(texnameWithUserPath)) | ||
436 | texture = SceneManager->getVideoDriver()->getTexture(texnameWithUserPath); | ||
437 | else if (FileSystem->existFile(texname)) | ||
438 | { | ||
439 | newTexture = SceneManager->getVideoDriver()->findTexture(texname) == 0; | ||
440 | texture = SceneManager->getVideoDriver()->getTexture(texname); | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | newTexture = SceneManager->getVideoDriver()->findTexture(relPath + texname) == 0; | ||
445 | // try to read in the relative path, the .obj is loaded from | ||
446 | texture = SceneManager->getVideoDriver()->getTexture( relPath + texname ); | ||
447 | } | ||
448 | } | ||
449 | if ( texture ) | ||
450 | { | ||
451 | if (type==0) | ||
452 | currMaterial->Meshbuffer->Material.setTexture(0, texture); | ||
453 | else if (type==1) | ||
454 | { | ||
455 | if (newTexture) | ||
456 | SceneManager->getVideoDriver()->makeNormalMapTexture(texture, bumpiness); | ||
457 | currMaterial->Meshbuffer->Material.setTexture(1, texture); | ||
458 | currMaterial->Meshbuffer->Material.MaterialType=video::EMT_PARALLAX_MAP_SOLID; | ||
459 | currMaterial->Meshbuffer->Material.MaterialTypeParam=0.035f; | ||
460 | } | ||
461 | else if (type==2) | ||
462 | { | ||
463 | currMaterial->Meshbuffer->Material.setTexture(0, texture); | ||
464 | currMaterial->Meshbuffer->Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; | ||
465 | } | ||
466 | else if (type==3) | ||
467 | { | ||
468 | // currMaterial->Meshbuffer->Material.Textures[1] = texture; | ||
469 | // currMaterial->Meshbuffer->Material.MaterialType=video::EMT_REFLECTION_2_LAYER; | ||
470 | } | ||
471 | // Set diffuse material color to white so as not to affect texture color | ||
472 | // Because Maya set diffuse color Kd to black when you use a diffuse color map | ||
473 | // But is this the right thing to do? | ||
474 | currMaterial->Meshbuffer->Material.DiffuseColor.set( | ||
475 | currMaterial->Meshbuffer->Material.DiffuseColor.getAlpha(), 255, 255, 255 ); | ||
476 | } | ||
477 | return bufPtr; | ||
478 | } | ||
479 | |||
480 | |||
481 | void COBJMeshFileLoader::readMTL(const c8* fileName, const io::path& relPath) | ||
482 | { | ||
483 | const io::path realFile(fileName); | ||
484 | io::IReadFile * mtlReader; | ||
485 | |||
486 | if (FileSystem->existFile(realFile)) | ||
487 | mtlReader = FileSystem->createAndOpenFile(realFile); | ||
488 | else if (FileSystem->existFile(relPath + realFile)) | ||
489 | mtlReader = FileSystem->createAndOpenFile(relPath + realFile); | ||
490 | else if (FileSystem->existFile(FileSystem->getFileBasename(realFile))) | ||
491 | mtlReader = FileSystem->createAndOpenFile(FileSystem->getFileBasename(realFile)); | ||
492 | else | ||
493 | mtlReader = FileSystem->createAndOpenFile(relPath + FileSystem->getFileBasename(realFile)); | ||
494 | if (!mtlReader) // fail to open and read file | ||
495 | { | ||
496 | os::Printer::log("Could not open material file", realFile, ELL_WARNING); | ||
497 | return; | ||
498 | } | ||
499 | |||
500 | const long filesize = mtlReader->getSize(); | ||
501 | if (!filesize) | ||
502 | { | ||
503 | os::Printer::log("Skipping empty material file", realFile, ELL_WARNING); | ||
504 | mtlReader->drop(); | ||
505 | return; | ||
506 | } | ||
507 | |||
508 | c8* buf = new c8[filesize]; | ||
509 | mtlReader->read((void*)buf, filesize); | ||
510 | const c8* bufEnd = buf+filesize; | ||
511 | |||
512 | SObjMtl* currMaterial = 0; | ||
513 | |||
514 | const c8* bufPtr = buf; | ||
515 | while(bufPtr != bufEnd) | ||
516 | { | ||
517 | switch(*bufPtr) | ||
518 | { | ||
519 | case 'n': // newmtl | ||
520 | { | ||
521 | // if there's an existing material, store it first | ||
522 | if ( currMaterial ) | ||
523 | Materials.push_back( currMaterial ); | ||
524 | |||
525 | // extract new material's name | ||
526 | c8 mtlNameBuf[WORD_BUFFER_LENGTH]; | ||
527 | bufPtr = goAndCopyNextWord(mtlNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
528 | |||
529 | currMaterial = new SObjMtl; | ||
530 | currMaterial->Name = mtlNameBuf; | ||
531 | } | ||
532 | break; | ||
533 | case 'i': // illum - illumination | ||
534 | if ( currMaterial ) | ||
535 | { | ||
536 | const u32 COLOR_BUFFER_LENGTH = 16; | ||
537 | c8 illumStr[COLOR_BUFFER_LENGTH]; | ||
538 | |||
539 | bufPtr = goAndCopyNextWord(illumStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
540 | currMaterial->Illumination = (c8)atol(illumStr); | ||
541 | } | ||
542 | break; | ||
543 | case 'N': | ||
544 | if ( currMaterial ) | ||
545 | { | ||
546 | switch(bufPtr[1]) | ||
547 | { | ||
548 | case 's': // Ns - shininess | ||
549 | { | ||
550 | const u32 COLOR_BUFFER_LENGTH = 16; | ||
551 | c8 nsStr[COLOR_BUFFER_LENGTH]; | ||
552 | |||
553 | bufPtr = goAndCopyNextWord(nsStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
554 | f32 shininessValue = core::fast_atof(nsStr); | ||
555 | |||
556 | // wavefront shininess is from [0, 1000], so scale for OpenGL | ||
557 | shininessValue *= 0.128f; | ||
558 | currMaterial->Meshbuffer->Material.Shininess = shininessValue; | ||
559 | } | ||
560 | break; | ||
561 | case 'i': // Ni - refraction index | ||
562 | { | ||
563 | c8 tmpbuf[WORD_BUFFER_LENGTH]; | ||
564 | bufPtr = goAndCopyNextWord(tmpbuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
565 | } | ||
566 | break; | ||
567 | } | ||
568 | } | ||
569 | break; | ||
570 | case 'K': | ||
571 | if ( currMaterial ) | ||
572 | { | ||
573 | switch(bufPtr[1]) | ||
574 | { | ||
575 | case 'd': // Kd = diffuse | ||
576 | { | ||
577 | bufPtr = readColor(bufPtr, currMaterial->Meshbuffer->Material.DiffuseColor, bufEnd); | ||
578 | |||
579 | } | ||
580 | break; | ||
581 | |||
582 | case 's': // Ks = specular | ||
583 | { | ||
584 | bufPtr = readColor(bufPtr, currMaterial->Meshbuffer->Material.SpecularColor, bufEnd); | ||
585 | } | ||
586 | break; | ||
587 | |||
588 | case 'a': // Ka = ambience | ||
589 | { | ||
590 | bufPtr=readColor(bufPtr, currMaterial->Meshbuffer->Material.AmbientColor, bufEnd); | ||
591 | } | ||
592 | break; | ||
593 | case 'e': // Ke = emissive | ||
594 | { | ||
595 | bufPtr=readColor(bufPtr, currMaterial->Meshbuffer->Material.EmissiveColor, bufEnd); | ||
596 | } | ||
597 | break; | ||
598 | } // end switch(bufPtr[1]) | ||
599 | } // end case 'K': if ( 0 != currMaterial )... | ||
600 | break; | ||
601 | case 'b': // bump | ||
602 | case 'm': // texture maps | ||
603 | if (currMaterial) | ||
604 | { | ||
605 | bufPtr=readTextures(bufPtr, bufEnd, currMaterial, relPath); | ||
606 | } | ||
607 | break; | ||
608 | case 'd': // d - transparency | ||
609 | if ( currMaterial ) | ||
610 | { | ||
611 | const u32 COLOR_BUFFER_LENGTH = 16; | ||
612 | c8 dStr[COLOR_BUFFER_LENGTH]; | ||
613 | |||
614 | bufPtr = goAndCopyNextWord(dStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
615 | f32 dValue = core::fast_atof(dStr); | ||
616 | |||
617 | currMaterial->Meshbuffer->Material.DiffuseColor.setAlpha( (s32)(dValue * 255) ); | ||
618 | if (dValue<1.0f) | ||
619 | currMaterial->Meshbuffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; | ||
620 | } | ||
621 | break; | ||
622 | case 'T': | ||
623 | if ( currMaterial ) | ||
624 | { | ||
625 | switch ( bufPtr[1] ) | ||
626 | { | ||
627 | case 'f': // Tf - Transmitivity | ||
628 | const u32 COLOR_BUFFER_LENGTH = 16; | ||
629 | c8 redStr[COLOR_BUFFER_LENGTH]; | ||
630 | c8 greenStr[COLOR_BUFFER_LENGTH]; | ||
631 | c8 blueStr[COLOR_BUFFER_LENGTH]; | ||
632 | |||
633 | bufPtr = goAndCopyNextWord(redStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
634 | bufPtr = goAndCopyNextWord(greenStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
635 | bufPtr = goAndCopyNextWord(blueStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
636 | |||
637 | f32 transparency = ( core::fast_atof(redStr) + core::fast_atof(greenStr) + core::fast_atof(blueStr) ) / 3; | ||
638 | |||
639 | currMaterial->Meshbuffer->Material.DiffuseColor.setAlpha( (s32)(transparency * 255) ); | ||
640 | if (transparency < 1.0f) | ||
641 | currMaterial->Meshbuffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; | ||
642 | } | ||
643 | } | ||
644 | break; | ||
645 | default: // comments or not recognised | ||
646 | break; | ||
647 | } // end switch(bufPtr[0]) | ||
648 | // go to next line | ||
649 | bufPtr = goNextLine(bufPtr, bufEnd); | ||
650 | } // end while (bufPtr) | ||
651 | |||
652 | // end of file. if there's an existing material, store it | ||
653 | if ( currMaterial ) | ||
654 | Materials.push_back( currMaterial ); | ||
655 | |||
656 | delete [] buf; | ||
657 | mtlReader->drop(); | ||
658 | } | ||
659 | |||
660 | |||
661 | //! Read RGB color | ||
662 | const c8* COBJMeshFileLoader::readColor(const c8* bufPtr, video::SColor& color, const c8* const bufEnd) | ||
663 | { | ||
664 | const u32 COLOR_BUFFER_LENGTH = 16; | ||
665 | c8 colStr[COLOR_BUFFER_LENGTH]; | ||
666 | |||
667 | color.setAlpha(255); | ||
668 | bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
669 | color.setRed((s32)(core::fast_atof(colStr) * 255.0f)); | ||
670 | bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
671 | color.setGreen((s32)(core::fast_atof(colStr) * 255.0f)); | ||
672 | bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); | ||
673 | color.setBlue((s32)(core::fast_atof(colStr) * 255.0f)); | ||
674 | return bufPtr; | ||
675 | } | ||
676 | |||
677 | |||
678 | //! Read 3d vector of floats | ||
679 | const c8* COBJMeshFileLoader::readVec3(const c8* bufPtr, core::vector3df& vec, const c8* const bufEnd) | ||
680 | { | ||
681 | const u32 WORD_BUFFER_LENGTH = 256; | ||
682 | c8 wordBuffer[WORD_BUFFER_LENGTH]; | ||
683 | |||
684 | bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
685 | vec.X=-core::fast_atof(wordBuffer); // change handedness | ||
686 | bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
687 | vec.Y=core::fast_atof(wordBuffer); | ||
688 | bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
689 | vec.Z=core::fast_atof(wordBuffer); | ||
690 | return bufPtr; | ||
691 | } | ||
692 | |||
693 | |||
694 | //! Read 2d vector of floats | ||
695 | const c8* COBJMeshFileLoader::readUV(const c8* bufPtr, core::vector2df& vec, const c8* const bufEnd) | ||
696 | { | ||
697 | const u32 WORD_BUFFER_LENGTH = 256; | ||
698 | c8 wordBuffer[WORD_BUFFER_LENGTH]; | ||
699 | |||
700 | bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
701 | vec.X=core::fast_atof(wordBuffer); | ||
702 | bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); | ||
703 | vec.Y=1-core::fast_atof(wordBuffer); // change handedness | ||
704 | return bufPtr; | ||
705 | } | ||
706 | |||
707 | |||
708 | //! Read boolean value represented as 'on' or 'off' | ||
709 | const c8* COBJMeshFileLoader::readBool(const c8* bufPtr, bool& tf, const c8* const bufEnd) | ||
710 | { | ||
711 | const u32 BUFFER_LENGTH = 8; | ||
712 | c8 tfStr[BUFFER_LENGTH]; | ||
713 | |||
714 | bufPtr = goAndCopyNextWord(tfStr, bufPtr, BUFFER_LENGTH, bufEnd); | ||
715 | tf = strcmp(tfStr, "off") != 0; | ||
716 | return bufPtr; | ||
717 | } | ||
718 | |||
719 | |||
720 | COBJMeshFileLoader::SObjMtl* COBJMeshFileLoader::findMtl(const core::stringc& mtlName, const core::stringc& grpName) | ||
721 | { | ||
722 | COBJMeshFileLoader::SObjMtl* defMaterial = 0; | ||
723 | // search existing Materials for best match | ||
724 | // exact match does return immediately, only name match means a new group | ||
725 | for (u32 i = 0; i < Materials.size(); ++i) | ||
726 | { | ||
727 | if ( Materials[i]->Name == mtlName ) | ||
728 | { | ||
729 | if ( Materials[i]->Group == grpName ) | ||
730 | return Materials[i]; | ||
731 | else | ||
732 | defMaterial = Materials[i]; | ||
733 | } | ||
734 | } | ||
735 | // we found a partial match | ||
736 | if (defMaterial) | ||
737 | { | ||
738 | Materials.push_back(new SObjMtl(*defMaterial)); | ||
739 | Materials.getLast()->Group = grpName; | ||
740 | return Materials.getLast(); | ||
741 | } | ||
742 | // we found a new group for a non-existant material | ||
743 | else if (grpName.size()) | ||
744 | { | ||
745 | Materials.push_back(new SObjMtl(*Materials[0])); | ||
746 | Materials.getLast()->Group = grpName; | ||
747 | return Materials.getLast(); | ||
748 | } | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | |||
753 | //! skip space characters and stop on first non-space | ||
754 | const c8* COBJMeshFileLoader::goFirstWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines) | ||
755 | { | ||
756 | // skip space characters | ||
757 | if (acrossNewlines) | ||
758 | while((buf != bufEnd) && core::isspace(*buf)) | ||
759 | ++buf; | ||
760 | else | ||
761 | while((buf != bufEnd) && core::isspace(*buf) && (*buf != '\n')) | ||
762 | ++buf; | ||
763 | |||
764 | return buf; | ||
765 | } | ||
766 | |||
767 | |||
768 | //! skip current word and stop at beginning of next one | ||
769 | const c8* COBJMeshFileLoader::goNextWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines) | ||
770 | { | ||
771 | // skip current word | ||
772 | while(( buf != bufEnd ) && !core::isspace(*buf)) | ||
773 | ++buf; | ||
774 | |||
775 | return goFirstWord(buf, bufEnd, acrossNewlines); | ||
776 | } | ||
777 | |||
778 | |||
779 | //! Read until line break is reached and stop at the next non-space character | ||
780 | const c8* COBJMeshFileLoader::goNextLine(const c8* buf, const c8* const bufEnd) | ||
781 | { | ||
782 | // look for newline characters | ||
783 | while(buf != bufEnd) | ||
784 | { | ||
785 | // found it, so leave | ||
786 | if (*buf=='\n' || *buf=='\r') | ||
787 | break; | ||
788 | ++buf; | ||
789 | } | ||
790 | return goFirstWord(buf, bufEnd); | ||
791 | } | ||
792 | |||
793 | |||
794 | u32 COBJMeshFileLoader::copyWord(c8* outBuf, const c8* const inBuf, u32 outBufLength, const c8* const bufEnd) | ||
795 | { | ||
796 | if (!outBufLength) | ||
797 | return 0; | ||
798 | if (!inBuf) | ||
799 | { | ||
800 | *outBuf = 0; | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | u32 i = 0; | ||
805 | while(inBuf[i]) | ||
806 | { | ||
807 | if (core::isspace(inBuf[i]) || &(inBuf[i]) == bufEnd) | ||
808 | break; | ||
809 | ++i; | ||
810 | } | ||
811 | |||
812 | u32 length = core::min_(i, outBufLength-1); | ||
813 | for (u32 j=0; j<length; ++j) | ||
814 | outBuf[j] = inBuf[j]; | ||
815 | |||
816 | outBuf[length] = 0; | ||
817 | return length; | ||
818 | } | ||
819 | |||
820 | |||
821 | core::stringc COBJMeshFileLoader::copyLine(const c8* inBuf, const c8* bufEnd) | ||
822 | { | ||
823 | if (!inBuf) | ||
824 | return core::stringc(); | ||
825 | |||
826 | const c8* ptr = inBuf; | ||
827 | while (ptr<bufEnd) | ||
828 | { | ||
829 | if (*ptr=='\n' || *ptr=='\r') | ||
830 | break; | ||
831 | ++ptr; | ||
832 | } | ||
833 | // we must avoid the +1 in case the array is used up | ||
834 | return core::stringc(inBuf, (u32)(ptr-inBuf+((ptr < bufEnd) ? 1 : 0))); | ||
835 | } | ||
836 | |||
837 | |||
838 | const c8* COBJMeshFileLoader::goAndCopyNextWord(c8* outBuf, const c8* inBuf, u32 outBufLength, const c8* bufEnd) | ||
839 | { | ||
840 | inBuf = goNextWord(inBuf, bufEnd, false); | ||
841 | copyWord(outBuf, inBuf, outBufLength, bufEnd); | ||
842 | return inBuf; | ||
843 | } | ||
844 | |||
845 | |||
846 | bool COBJMeshFileLoader::retrieveVertexIndices(c8* vertexData, s32* idx, const c8* bufEnd, u32 vbsize, u32 vtsize, u32 vnsize) | ||
847 | { | ||
848 | c8 word[16] = ""; | ||
849 | const c8* p = goFirstWord(vertexData, bufEnd); | ||
850 | u32 idxType = 0; // 0 = posIdx, 1 = texcoordIdx, 2 = normalIdx | ||
851 | |||
852 | u32 i = 0; | ||
853 | while ( p != bufEnd ) | ||
854 | { | ||
855 | if ( ( core::isdigit(*p)) || (*p == '-') ) | ||
856 | { | ||
857 | // build up the number | ||
858 | word[i++] = *p; | ||
859 | } | ||
860 | else if ( *p == '/' || *p == ' ' || *p == '\0' ) | ||
861 | { | ||
862 | // number is completed. Convert and store it | ||
863 | word[i] = '\0'; | ||
864 | // if no number was found index will become 0 and later on -1 by decrement | ||
865 | idx[idxType] = core::strtol10(word); | ||
866 | if (idx[idxType]<0) | ||
867 | { | ||
868 | switch (idxType) | ||
869 | { | ||
870 | case 0: | ||
871 | idx[idxType] += vbsize; | ||
872 | break; | ||
873 | case 1: | ||
874 | idx[idxType] += vtsize; | ||
875 | break; | ||
876 | case 2: | ||
877 | idx[idxType] += vnsize; | ||
878 | break; | ||
879 | } | ||
880 | } | ||
881 | else | ||
882 | idx[idxType]-=1; | ||
883 | |||
884 | // reset the word | ||
885 | word[0] = '\0'; | ||
886 | i = 0; | ||
887 | |||
888 | // go to the next kind of index type | ||
889 | if (*p == '/') | ||
890 | { | ||
891 | if ( ++idxType > 2 ) | ||
892 | { | ||
893 | // error checking, shouldn't reach here unless file is wrong | ||
894 | idxType = 0; | ||
895 | } | ||
896 | } | ||
897 | else | ||
898 | { | ||
899 | // set all missing values to disable (=-1) | ||
900 | while (++idxType < 3) | ||
901 | idx[idxType]=-1; | ||
902 | ++p; | ||
903 | break; // while | ||
904 | } | ||
905 | } | ||
906 | |||
907 | // go to the next char | ||
908 | ++p; | ||
909 | } | ||
910 | |||
911 | return true; | ||
912 | } | ||
913 | |||
914 | |||
915 | void COBJMeshFileLoader::cleanUp() | ||
916 | { | ||
917 | for (u32 i=0; i < Materials.size(); ++i ) | ||
918 | { | ||
919 | Materials[i]->Meshbuffer->drop(); | ||
920 | delete Materials[i]; | ||
921 | } | ||
922 | |||
923 | Materials.clear(); | ||
924 | } | ||
925 | |||
926 | |||
927 | } // end namespace scene | ||
928 | } // end namespace irr | ||
929 | |||
930 | #endif // _IRR_COMPILE_WITH_OBJ_LOADER_ | ||
931 | |||