1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // 2019 additional alignment and big_endian fixes by Corto and Salas00
\r
3 // This file is part of the "Irrlicht Engine".
\r
4 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
6 #include "IrrCompileConfig.h"
\r
7 #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
\r
9 #include "IReadFile.h"
\r
11 #include "CMS3DMeshFileLoader.h"
\r
12 #include "CSkinnedMesh.h"
\r
21 #define _IRR_DEBUG_MS3D_LOADER_
\r
24 // byte-align structures
\r
25 #include "irrpack.h"
\r
35 // Vertex information
\r
46 #define MS3DVERTEX_NUM_PAD_BYTES 5
\r
48 // Triangle information
\r
52 u16 VertexIndices[3];
\r
53 float VertexNormals[3][3];
\r
60 #define MS3DTRIANGLE_NUM_PAD_BYTES 2
\r
62 // Material information
\r
70 float Shininess; // 0.0f - 128.0f
\r
71 float Transparency; // 0.0f - 1.0f
\r
72 u8 Mode; // 0, 1, 2 is unused now
\r
78 #define MS3DMATERIAL_NUM_PAD_BYTES 3
\r
80 // Joint information
\r
86 char ParentName[32];
\r
88 float Translation[3];
\r
89 u16 NumRotationKeyframes;
\r
90 u16 NumTranslationKeyframes;
\r
93 #define MS3DJOINT_NUM_PAD_BYTES 3
\r
102 // vertex weights in 1.8.x
\r
103 struct MS3DVertexWeights
\r
111 // Default alignment
\r
112 #include "irrunpack.h"
\r
114 // Get float encoded in little endian in way not causing troubles when floats have to be memory aligned.
\r
115 static inline float get_unaligned_le_float(const u8 *ptr)
\r
121 #ifdef __BIG_ENDIAN__
\r
127 tmp.f = *(float*)ptr;
\r
135 core::stringc Name;
\r
136 core::array<u16> VertexIds;
\r
141 CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver)
\r
142 : Driver(driver), AnimatedMesh(0)
\r
145 setDebugName("CMS3DMeshFileLoader");
\r
150 //! returns true if the file maybe is able to be loaded by this class
\r
151 //! based on the file extension (e.g. ".bsp")
\r
152 bool CMS3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
\r
154 return core::hasFileExtension ( filename, "ms3d" );
\r
158 //! creates/loads an animated mesh from the file.
\r
159 //! \return Pointer to the created mesh. Returns 0 if loading failed.
\r
160 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
\r
161 //! See IReferenceCounted::drop() for more information.
\r
162 IAnimatedMesh* CMS3DMeshFileLoader::createMesh(io::IReadFile* file)
\r
167 AnimatedMesh = new CSkinnedMesh();
\r
171 AnimatedMesh->finalize();
\r
175 AnimatedMesh->drop();
\r
179 return AnimatedMesh;
\r
183 //! loads a milkshape file
\r
184 bool CMS3DMeshFileLoader::load(io::IReadFile* file)
\r
190 const long fileSize = file->getSize();
\r
194 u8* buffer = new u8[fileSize];
\r
195 size_t read = file->read(buffer, fileSize);
\r
196 if (read != (size_t)fileSize)
\r
199 os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR);
\r
205 const u8 *pPtr = (u8*)((void*)buffer);
\r
206 MS3DHeader *pHeader = (MS3DHeader*)pPtr;
\r
207 pPtr += sizeof(MS3DHeader);
\r
209 if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 )
\r
212 os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR);
\r
216 #ifdef __BIG_ENDIAN__
\r
217 pHeader->Version = os::Byteswap::byteswap(pHeader->Version);
\r
219 if ( pHeader->Version < 3 || pHeader->Version > 4 )
\r
222 os::Printer::log("Only Milkshape3D version 3 and 4 (1.3 to 1.8) is supported. Loading failed", file->getFileName(), ELL_ERROR);
\r
225 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
226 os::Printer::log("Loaded header version", core::stringc(pHeader->Version).c_str());
\r
229 // get pointers to data
\r
232 u16 numVertices = *(u16*)pPtr;
\r
233 #ifdef __BIG_ENDIAN__
\r
234 numVertices = os::Byteswap::byteswap(numVertices);
\r
236 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
237 os::Printer::log("Load vertices", core::stringc(numVertices).c_str());
\r
240 pPtr += sizeof(u16);
\r
241 MS3DVertex *vertices = new MS3DVertex[numVertices];
\r
242 if (pPtr + ((sizeof(MS3DVertex) - MS3DVERTEX_NUM_PAD_BYTES) * numVertices) > buffer+fileSize)
\r
245 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
248 for (u16 tmp=0; tmp<numVertices; ++tmp)
\r
250 //printf("&vertices[tmp].Vertex[0] = %p (%d)\n", &vertices[tmp].Vertex[0], (int)((long long)(&vertices[tmp].Vertex[0]) % 4));
\r
251 memcpy(&vertices[tmp].Flags, pPtr, sizeof(struct MS3DVertex) - MS3DVERTEX_NUM_PAD_BYTES);
\r
252 #ifdef __BIG_ENDIAN__
\r
253 vertices[tmp].Vertex[0] = os::Byteswap::byteswap(vertices[tmp].Vertex[0]);
\r
254 vertices[tmp].Vertex[1] = os::Byteswap::byteswap(vertices[tmp].Vertex[1]);
\r
255 vertices[tmp].Vertex[2] = -os::Byteswap::byteswap(vertices[tmp].Vertex[2]);
\r
257 vertices[tmp].Vertex[2] = -vertices[tmp].Vertex[2];
\r
259 // Go to the next vertex structure
\r
260 pPtr += sizeof(struct MS3DVertex) - MS3DVERTEX_NUM_PAD_BYTES;
\r
264 u16 numTriangles = *(u16*)pPtr;
\r
265 #ifdef __BIG_ENDIAN__
\r
266 numTriangles = os::Byteswap::byteswap(numTriangles);
\r
268 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
269 os::Printer::log("Load Triangles", core::stringc(numTriangles).c_str());
\r
271 pPtr += sizeof(u16);
\r
272 MS3DTriangle *triangles = new MS3DTriangle[numTriangles];
\r
273 if (pPtr + ((sizeof(MS3DTriangle) - MS3DTRIANGLE_NUM_PAD_BYTES) * numTriangles) > buffer+fileSize)
\r
276 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
279 for (u16 tmp=0; tmp<numTriangles; ++tmp)
\r
281 memcpy(&triangles[tmp].Flags, pPtr, sizeof(struct MS3DTriangle) - MS3DTRIANGLE_NUM_PAD_BYTES);
\r
282 #ifdef __BIG_ENDIAN__
\r
283 triangles[tmp].Flags = os::Byteswap::byteswap(triangles[tmp].Flags);
\r
284 for (u16 j=0; j<3; ++j)
\r
286 triangles[tmp].VertexIndices[j] = os::Byteswap::byteswap(triangles[tmp].VertexIndices[j]);
\r
287 triangles[tmp].VertexNormals[j][0] = os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][0]);
\r
288 triangles[tmp].VertexNormals[j][1] = os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][1]);
\r
289 triangles[tmp].VertexNormals[j][2] = -os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][2]);
\r
290 triangles[tmp].S[j] = os::Byteswap::byteswap(triangles[tmp].S[j]);
\r
291 triangles[tmp].T[j] = os::Byteswap::byteswap(triangles[tmp].T[j]);
\r
294 triangles[tmp].VertexNormals[0][2] = -triangles[tmp].VertexNormals[0][2];
\r
295 triangles[tmp].VertexNormals[1][2] = -triangles[tmp].VertexNormals[1][2];
\r
296 triangles[tmp].VertexNormals[2][2] = -triangles[tmp].VertexNormals[2][2];
\r
298 // Go to the next triangle structure
\r
299 pPtr += sizeof(struct MS3DTriangle) - MS3DTRIANGLE_NUM_PAD_BYTES;
\r
303 u16 numGroups = *(u16*)pPtr;
\r
304 #ifdef __BIG_ENDIAN__
\r
305 numGroups = os::Byteswap::byteswap(numGroups);
\r
307 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
308 os::Printer::log("Load Groups", core::stringc(numGroups).c_str());
\r
310 pPtr += sizeof(u16);
\r
312 core::array<SGroup> groups;
\r
313 groups.reallocate(numGroups);
\r
317 for (i=0; i<numGroups; ++i)
\r
319 groups.push_back(SGroup());
\r
320 SGroup& grp = groups.getLast();
\r
322 // The byte flag is before the name, so add 1
\r
323 grp.Name = ((const c8*) pPtr) + 1;
\r
325 pPtr += 33; // name and 1 byte flags
\r
326 u16 triangleCount = *(u16*)pPtr;
\r
327 #ifdef __BIG_ENDIAN__
\r
328 triangleCount = os::Byteswap::byteswap(triangleCount);
\r
330 pPtr += sizeof(u16);
\r
331 grp.VertexIds.reallocate(triangleCount);
\r
333 //pPtr += sizeof(u16) * triangleCount; // triangle indices
\r
334 for (u16 j=0; j<triangleCount; ++j)
\r
336 #ifdef __BIG_ENDIAN__
\r
337 grp.VertexIds.push_back(os::Byteswap::byteswap(*(u16*)pPtr));
\r
339 grp.VertexIds.push_back(*(u16*)pPtr);
\r
341 pPtr += sizeof (u16);
\r
344 grp.MaterialIdx = *(u8*)pPtr;
\r
345 if (grp.MaterialIdx == 255)
\r
346 grp.MaterialIdx = 0;
\r
348 pPtr += sizeof(c8); // material index
\r
349 if (pPtr > buffer+fileSize)
\r
352 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
358 u16 numMaterials = *(u16*)pPtr;
\r
359 #ifdef __BIG_ENDIAN__
\r
360 numMaterials = os::Byteswap::byteswap(numMaterials);
\r
362 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
363 os::Printer::log("Load Materials", core::stringc(numMaterials).c_str());
\r
365 pPtr += sizeof(u16);
\r
367 if(numMaterials == 0)
\r
369 // if there are no materials, add at least one buffer
\r
370 AnimatedMesh->addMeshBuffer();
\r
373 MS3DMaterial *material = new MS3DMaterial;
\r
374 for (i=0; i<numMaterials; ++i)
\r
376 memcpy(material, pPtr, sizeof(struct MS3DMaterial) - MS3DMATERIAL_NUM_PAD_BYTES);
\r
377 #ifdef __BIG_ENDIAN__
\r
378 for (u16 j=0; j<4; ++j)
\r
379 material->Ambient[j] = os::Byteswap::byteswap(material->Ambient[j]);
\r
380 for (u16 j=0; j<4; ++j)
\r
381 material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]);
\r
382 for (u16 j=0; j<4; ++j)
\r
383 material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]);
\r
384 for (u16 j=0; j<4; ++j)
\r
385 material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]);
\r
386 material->Shininess = os::Byteswap::byteswap(material->Shininess);
\r
387 material->Transparency = os::Byteswap::byteswap(material->Transparency);
\r
389 pPtr += (sizeof(MS3DMaterial) - MS3DMATERIAL_NUM_PAD_BYTES);
\r
390 if (pPtr > buffer+fileSize)
\r
393 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
397 scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->addMeshBuffer();
\r
399 tmpBuffer->Material.MaterialType = video::EMT_SOLID;
\r
401 tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor ();
\r
402 tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor ();
\r
403 tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor ();
\r
404 tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor ();
\r
405 tmpBuffer->Material.Shininess = material->Shininess;
\r
407 core::stringc TexturePath(material->Texture);
\r
408 if (TexturePath.trim()!="")
\r
410 TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false);
\r
411 tmpBuffer->Material.setTexture(0, Driver->getTexture(TexturePath));
\r
414 core::stringc AlphamapPath=(const c8*)material->Alphamap;
\r
415 if (AlphamapPath.trim()!="")
\r
417 AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false);
\r
418 tmpBuffer->Material.setTexture(2, Driver->getTexture(AlphamapPath));
\r
426 f32 framesPerSecond = get_unaligned_le_float(pPtr);
\r
428 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
429 os::Printer::log("FPS", core::stringc(framesPerSecond).c_str());
\r
431 pPtr += sizeof(float) * 2; // fps and current time
\r
433 if (framesPerSecond<1.f)
\r
434 framesPerSecond=1.f;
\r
435 AnimatedMesh->setAnimationSpeed(framesPerSecond);
\r
437 // ignore, calculated inside SkinnedMesh
\r
438 // s32 frameCount = *(int*)pPtr;
\r
439 #ifdef __BIG_ENDIAN__
\r
440 // frameCount = os::Byteswap::byteswap(frameCount);
\r
442 pPtr += sizeof(int);
\r
444 u16 jointCount = *(u16*)pPtr;
\r
445 #ifdef __BIG_ENDIAN__
\r
446 jointCount = os::Byteswap::byteswap(jointCount);
\r
448 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
449 os::Printer::log("Joints", core::stringc(jointCount).c_str());
\r
451 pPtr += sizeof(u16);
\r
452 if (pPtr > buffer+fileSize)
\r
455 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
459 core::array<core::stringc> parentNames;
\r
460 parentNames.reallocate(jointCount);
\r
463 for (i=0; i<jointCount; ++i)
\r
466 MS3DJoint *pJoint = new MS3DJoint;
\r
467 //printf("&pJoint->Rotation[0] = %p (%d)\n", &pJoint->Rotation[0], (int)((long long)(&pJoint->Rotation[0]) % 4));
\r
468 memcpy(&pJoint->Flags, pPtr, sizeof(MS3DJoint) - MS3DJOINT_NUM_PAD_BYTES);
\r
470 #ifdef __BIG_ENDIAN__
\r
471 for (j=0; j<3; ++j)
\r
472 pJoint->Rotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]);
\r
473 for (j=0; j<3; ++j)
\r
474 pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]);
\r
475 pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes);
\r
476 pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes);
\r
478 pPtr = pPtr + sizeof(MS3DJoint) - MS3DJOINT_NUM_PAD_BYTES;
\r
479 if (pPtr > buffer+fileSize)
\r
482 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
486 ISkinnedMesh::SJoint *jnt = AnimatedMesh->addJoint();
\r
488 jnt->Name = pJoint->Name;
\r
489 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
490 os::Printer::log("Joint", jnt->Name.c_str());
\r
491 os::Printer::log("Rotation keyframes", core::stringc(pJoint->NumRotationKeyframes).c_str());
\r
492 os::Printer::log("Translation keyframes", core::stringc(pJoint->NumTranslationKeyframes).c_str());
\r
494 jnt->LocalMatrix.makeIdentity();
\r
495 jnt->LocalMatrix.setRotationRadians(
\r
496 core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) );
\r
497 // convert right-handed to left-handed
\r
498 jnt->LocalMatrix[2]=-jnt->LocalMatrix[2];
\r
499 jnt->LocalMatrix[6]=-jnt->LocalMatrix[6];
\r
500 jnt->LocalMatrix[8]=-jnt->LocalMatrix[8];
\r
501 jnt->LocalMatrix[9]=-jnt->LocalMatrix[9];
\r
503 jnt->LocalMatrix.setTranslation(
\r
504 core::vector3df(pJoint->Translation[0], pJoint->Translation[1], -pJoint->Translation[2]) );
\r
505 jnt->Animatedposition.set(jnt->LocalMatrix.getTranslation());
\r
506 jnt->Animatedrotation.set(jnt->LocalMatrix.getRotationDegrees());
\r
508 parentNames.push_back( (c8*)pJoint->ParentName );
\r
510 /*if (pJoint->NumRotationKeyframes ||
\r
511 pJoint->NumTranslationKeyframes)
\r
512 HasAnimation = true;
\r
515 MS3DKeyframe* kf = new MS3DKeyframe;
\r
517 // get rotation keyframes
\r
518 const u16 numRotationKeyframes = pJoint->NumRotationKeyframes;
\r
519 for (j=0; j < numRotationKeyframes; ++j)
\r
521 memcpy(kf, pPtr, sizeof(MS3DKeyframe));
\r
522 //printf("rotation kf = %p (%d)\n", kf, (int)((long long)kf % 4));
\r
523 #ifdef __BIG_ENDIAN__
\r
524 kf->Time = os::Byteswap::byteswap(kf->Time);
\r
525 for (u32 l=0; l<3; ++l)
\r
526 kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]);
\r
528 pPtr += sizeof(MS3DKeyframe);
\r
529 if (pPtr > buffer+fileSize)
\r
532 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
536 ISkinnedMesh::SRotationKey *k=AnimatedMesh->addRotationKey(jnt);
\r
537 k->frame = kf->Time * framesPerSecond-1;
\r
539 core::matrix4 tmpMatrix;
\r
541 tmpMatrix.setRotationRadians(
\r
542 core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) );
\r
543 // convert right-handed to left-handed
\r
544 tmpMatrix[2]=-tmpMatrix[2];
\r
545 tmpMatrix[6]=-tmpMatrix[6];
\r
546 tmpMatrix[8]=-tmpMatrix[8];
\r
547 tmpMatrix[9]=-tmpMatrix[9];
\r
549 tmpMatrix=jnt->LocalMatrix*tmpMatrix;
\r
551 // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility.
\r
552 // Not tested so far if this was correct or wrong before quaternion fix!
\r
553 k->rotation = core::quaternion(tmpMatrix.getTransposed());
\r
556 // get translation keyframes
\r
557 const u16 numTranslationKeyframes = pJoint->NumTranslationKeyframes;
\r
558 for (j=0; j<numTranslationKeyframes; ++j)
\r
560 memcpy(kf, pPtr, sizeof(MS3DKeyframe));
\r
561 //printf("translation kf = %p (%d)\n", kf, (int)((long long)kf % 4));
\r
563 #ifdef __BIG_ENDIAN__
\r
564 kf->Time = os::Byteswap::byteswap(kf->Time);
\r
565 for (u32 l=0; l<3; ++l)
\r
566 kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]);
\r
568 pPtr += sizeof(MS3DKeyframe);
\r
569 if (pPtr > buffer+fileSize)
\r
572 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
576 ISkinnedMesh::SPositionKey *k=AnimatedMesh->addPositionKey(jnt);
\r
577 k->frame = kf->Time * framesPerSecond-1;
\r
579 k->position = core::vector3df
\r
580 (kf->Parameter[0]+pJoint->Translation[0],
\r
581 kf->Parameter[1]+pJoint->Translation[1],
\r
582 -kf->Parameter[2]-pJoint->Translation[2]);
\r
589 core::array<MS3DVertexWeights> vertexWeights;
\r
590 f32 weightFactor=0;
\r
592 if (jointCount && (pHeader->Version == 4) && (pPtr < buffer+fileSize))
\r
594 s32 subVersion = *(s32*)pPtr; // comment subVersion, always 1
\r
595 #ifdef __BIG_ENDIAN__
\r
596 subVersion = os::Byteswap::byteswap(subVersion);
\r
598 pPtr += sizeof(s32);
\r
600 for (u32 j=0; j<4; ++j) // four comment groups
\r
602 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
603 os::Printer::log("Skipping comment group", core::stringc(j+1).c_str());
\r
605 u32 numComments = *(u32*)pPtr;
\r
606 #ifdef __BIG_ENDIAN__
\r
607 numComments = os::Byteswap::byteswap(numComments);
\r
609 pPtr += sizeof(u32);
\r
610 for (i=0; i<numComments; ++i)
\r
612 // according to scorpiomidget this field does
\r
613 // not exist for model comments. So avoid to
\r
616 pPtr += sizeof(s32); // index
\r
617 s32 commentLength = *(s32*)pPtr;
\r
618 #ifdef __BIG_ENDIAN__
\r
619 commentLength = os::Byteswap::byteswap(commentLength);
\r
621 pPtr += sizeof(s32);
\r
622 pPtr += commentLength;
\r
625 if (pPtr > buffer+fileSize)
\r
628 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
633 if (pPtr < buffer+fileSize)
\r
635 subVersion = *(s32*)pPtr; // vertex subVersion, 1 or 2
\r
636 #ifdef __BIG_ENDIAN__
\r
637 subVersion = os::Byteswap::byteswap(subVersion);
\r
640 weightFactor=1.f/255.f;
\r
642 weightFactor=1.f/100.f;
\r
643 pPtr += sizeof(s32);
\r
645 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
646 os::Printer::log("Reading vertex weights");
\r
648 // read vertex weights, ignoring data 'extra' from 1.8.2
\r
649 vertexWeights.reallocate(numVertices);
\r
650 const char offset = (subVersion==1)?6:10;
\r
651 for (i=0; i<numVertices; ++i)
\r
653 vertexWeights.push_back(*(MS3DVertexWeights*)pPtr);
\r
657 if (pPtr > buffer+fileSize)
\r
660 os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
\r
665 if (pPtr < buffer+fileSize)
\r
667 subVersion = *(s32*)pPtr; // joint subVersion, 1 or 2
\r
668 #ifdef __BIG_ENDIAN__
\r
669 subVersion = os::Byteswap::byteswap(subVersion);
\r
671 pPtr += sizeof(s32);
\r
672 // skip joint colors
\r
673 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
674 os::Printer::log("Skip joint color");
\r
676 pPtr += 3*sizeof(float)*jointCount;
\r
678 if (pPtr > buffer+fileSize)
\r
681 os::Printer::log("Loading failed. Corrupted data found", file->getFileName(), ELL_ERROR);
\r
686 if (pPtr < buffer+fileSize)
\r
688 subVersion = *(s32*)pPtr; // model subVersion, 1 or 2
\r
689 #ifdef __BIG_ENDIAN__
\r
690 subVersion = os::Byteswap::byteswap(subVersion);
\r
692 pPtr += sizeof(s32);
\r
693 #ifdef _IRR_DEBUG_MS3D_LOADER_
\r
694 os::Printer::log("Skip model extra information");
\r
696 // now the model extra information would follow
\r
697 // we also skip this for now
\r
701 //find parent of every joint
\r
702 for (u32 jointnum=0; jointnum<AnimatedMesh->getAllJoints().size(); ++jointnum)
\r
704 for (u32 j2=0; j2<AnimatedMesh->getAllJoints().size(); ++j2)
\r
706 if (jointnum != j2 && parentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name )
\r
708 AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]);
\r
714 // create vertices and indices, attach them to the joints.
\r
715 video::S3DVertex v;
\r
716 core::array<video::S3DVertex> *Vertices;
\r
717 core::array<u16> Indices;
\r
719 for (i=0; i<numTriangles; ++i)
\r
721 u32 tmp = groups[triangles[i].GroupIndex].MaterialIdx;
\r
722 Vertices = &AnimatedMesh->getMeshBuffers()[tmp]->Vertices_Standard;
\r
724 for (s32 j = 2; j!=-1; --j)
\r
726 const u32 vertidx = triangles[i].VertexIndices[j];
\r
728 v.TCoords.X = triangles[i].S[j];
\r
729 v.TCoords.Y = triangles[i].T[j];
\r
731 v.Normal.X = triangles[i].VertexNormals[j][0];
\r
732 v.Normal.Y = triangles[i].VertexNormals[j][1];
\r
733 v.Normal.Z = triangles[i].VertexNormals[j][2];
\r
735 if(triangles[i].GroupIndex < groups.size() &&
\r
736 groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size())
\r
737 v.Color = AnimatedMesh->getMeshBuffers()[groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor;
\r
739 v.Color.set(255,255,255,255);
\r
741 v.Pos.X = vertices[vertidx].Vertex[0];
\r
742 v.Pos.Y = vertices[vertidx].Vertex[1];
\r
743 v.Pos.Z = vertices[vertidx].Vertex[2];
\r
745 // check if we already have this vertex in our vertex array
\r
747 for (u32 iV = 0; iV < Vertices->size(); ++iV)
\r
749 if (v == (*Vertices)[iV])
\r
758 index = Vertices->size();
\r
759 const u32 matidx = groups[triangles[i].GroupIndex].MaterialIdx;
\r
760 if (vertexWeights.size()==0)
\r
762 const s32 boneid = vertices[vertidx].BoneID;
\r
763 if ((u32)boneid < AnimatedMesh->getAllJoints().size())
\r
765 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
766 w->buffer_id = matidx;
\r
767 w->strength = 1.0f;
\r
768 w->vertex_id = index;
\r
771 else if (jointCount) // new weights from 1.8.x
\r
774 s32 boneid = vertices[vertidx].BoneID;
\r
775 if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[0] != 0))
\r
777 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
778 w->buffer_id = matidx;
\r
779 sum -= (w->strength = vertexWeights[vertidx].weights[0]*weightFactor);
\r
780 w->vertex_id = index;
\r
782 boneid = vertexWeights[vertidx].boneIds[0];
\r
783 if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[1] != 0))
\r
785 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
786 w->buffer_id = matidx;
\r
787 sum -= (w->strength = vertexWeights[vertidx].weights[1]*weightFactor);
\r
788 w->vertex_id = index;
\r
790 boneid = vertexWeights[vertidx].boneIds[1];
\r
791 if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[2] != 0))
\r
793 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
794 w->buffer_id = matidx;
\r
795 sum -= (w->strength = vertexWeights[vertidx].weights[2]*weightFactor);
\r
796 w->vertex_id = index;
\r
798 boneid = vertexWeights[vertidx].boneIds[2];
\r
799 if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (sum > 0.f))
\r
801 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
802 w->buffer_id = matidx;
\r
804 w->vertex_id = index;
\r
806 // fallback, if no bone chosen. Seems to be an error in the specs
\r
807 boneid = vertices[vertidx].BoneID;
\r
808 if ((sum == 1.f) && ((u32)boneid < AnimatedMesh->getAllJoints().size()))
\r
810 ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
\r
811 w->buffer_id = matidx;
\r
813 w->vertex_id = index;
\r
817 Vertices->push_back(v);
\r
819 Indices.push_back(index);
\r
825 for (i=0; i<groups.size(); ++i)
\r
827 SGroup& grp = groups[i];
\r
829 if (grp.MaterialIdx >= AnimatedMesh->getMeshBuffers().size())
\r
830 grp.MaterialIdx = 0;
\r
832 core::array<u16>& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices;
\r
834 for (u32 k=0; k < grp.VertexIds.size(); ++k)
\r
835 for (u32 l=0; l<3; ++l)
\r
836 indices.push_back(Indices[++iIndex]);
\r
840 delete [] triangles;
\r
841 delete [] vertices;
\r
847 core::stringc CMS3DMeshFileLoader::stripPathFromString(const core::stringc& inString, bool returnPath) const
\r
849 s32 slashIndex=inString.findLast('/'); // forward slash
\r
850 s32 backSlash=inString.findLast('\\'); // back slash
\r
852 if (backSlash>slashIndex) slashIndex=backSlash;
\r
854 if (slashIndex==-1)//no slashes found
\r
857 return core::stringc(); //no path to return
\r
863 return inString.subString(0, slashIndex + 1);
\r
865 return inString.subString(slashIndex+1, inString.size() - (slashIndex+1));
\r
869 } // end namespace scene
\r
870 } // end namespace irr
\r