From 959831f4ef5a3e797f576c3de08cd65032c997ad Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 18:54:10 +1000 Subject: Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard. --- .../source/Irrlicht/CMS3DMeshFileLoader.cpp | 1636 ++++++++++---------- 1 file changed, 818 insertions(+), 818 deletions(-) (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CMS3DMeshFileLoader.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CMS3DMeshFileLoader.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CMS3DMeshFileLoader.cpp index 9a88d49..af06188 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CMS3DMeshFileLoader.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -1,818 +1,818 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "IrrCompileConfig.h" -#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ - -#include "IReadFile.h" -#include "os.h" -#include "CMS3DMeshFileLoader.h" -#include "CSkinnedMesh.h" - - -namespace irr -{ -namespace scene -{ - -#ifdef _DEBUG -#define _IRR_DEBUG_MS3D_LOADER_ -#endif - -// byte-align structures -#include "irrpack.h" - -namespace { -// File header -struct MS3DHeader -{ - char ID[10]; - int Version; -} PACK_STRUCT; - -// Vertex information -struct MS3DVertex -{ - u8 Flags; - float Vertex[3]; - char BoneID; - u8 RefCount; -} PACK_STRUCT; - -// Triangle information -struct MS3DTriangle -{ - u16 Flags; - u16 VertexIndices[3]; - float VertexNormals[3][3]; - float S[3], T[3]; - u8 SmoothingGroup; - u8 GroupIndex; -} PACK_STRUCT; - -// Material information -struct MS3DMaterial -{ - char Name[32]; - float Ambient[4]; - float Diffuse[4]; - float Specular[4]; - float Emissive[4]; - float Shininess; // 0.0f - 128.0f - float Transparency; // 0.0f - 1.0f - u8 Mode; // 0, 1, 2 is unused now - char Texture[128]; - char Alphamap[128]; -} PACK_STRUCT; - -// Joint information -struct MS3DJoint -{ - u8 Flags; - char Name[32]; - char ParentName[32]; - float Rotation[3]; - float Translation[3]; - u16 NumRotationKeyframes; - u16 NumTranslationKeyframes; -} PACK_STRUCT; - -// Keyframe data -struct MS3DKeyframe -{ - float Time; - float Parameter[3]; -} PACK_STRUCT; - -// vertex weights in 1.8.x -struct MS3DVertexWeights -{ - char boneIds[3]; - u8 weights[3]; -} PACK_STRUCT; - -} // end namespace - -// Default alignment -#include "irrunpack.h" - -struct SGroup -{ - core::stringc Name; - core::array VertexIds; - u16 MaterialIdx; -}; - -//! Constructor -CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver) -: Driver(driver), AnimatedMesh(0) -{ - #ifdef _DEBUG - setDebugName("CMS3DMeshFileLoader"); - #endif -} - - -//! returns true if the file maybe is able to be loaded by this class -//! based on the file extension (e.g. ".bsp") -bool CMS3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const -{ - return core::hasFileExtension ( filename, "ms3d" ); -} - - -//! creates/loads an animated mesh from the file. -//! \return Pointer to the created mesh. Returns 0 if loading failed. -//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). -//! See IReferenceCounted::drop() for more information. -IAnimatedMesh* CMS3DMeshFileLoader::createMesh(io::IReadFile* file) -{ - if (!file) - return 0; - - AnimatedMesh = new CSkinnedMesh(); - - if ( load(file) ) - { - AnimatedMesh->finalize(); - } - else - { - AnimatedMesh->drop(); - AnimatedMesh = 0; - } - - return AnimatedMesh; -} - - -//! loads a milkshape file -bool CMS3DMeshFileLoader::load(io::IReadFile* file) -{ - if (!file) - return false; - - // find file size - const long fileSize = file->getSize(); - - // read whole file - - u8* buffer = new u8[fileSize]; - s32 read = file->read(buffer, fileSize); - if (read != fileSize) - { - delete [] buffer; - os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - - // read header - - const u8 *pPtr = (u8*)((void*)buffer); - MS3DHeader *pHeader = (MS3DHeader*)pPtr; - pPtr += sizeof(MS3DHeader); - - if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 ) - { - delete [] buffer; - os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - -#ifdef __BIG_ENDIAN__ - pHeader->Version = os::Byteswap::byteswap(pHeader->Version); -#endif - if ( pHeader->Version < 3 || pHeader->Version > 4 ) - { - delete [] buffer; - os::Printer::log("Only Milkshape3D version 3 and 4 (1.3 to 1.8) is supported. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Loaded header version", core::stringc(pHeader->Version).c_str()); -#endif - - // get pointers to data - - // vertices - u16 numVertices = *(u16*)pPtr; -#ifdef __BIG_ENDIAN__ - numVertices = os::Byteswap::byteswap(numVertices); -#endif -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Load vertices", core::stringc(numVertices).c_str()); -#endif - pPtr += sizeof(u16); - MS3DVertex *vertices = (MS3DVertex*)pPtr; - pPtr += sizeof(MS3DVertex) * numVertices; - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - for (u16 tmp=0; tmp buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - for (u16 tmp=0; tmp groups; - groups.reallocate(numGroups); - - //store groups - u32 i; - for (i=0; i buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - } - - // load materials - u16 numMaterials = *(u16*)pPtr; -#ifdef __BIG_ENDIAN__ - numMaterials = os::Byteswap::byteswap(numMaterials); -#endif -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Load Materials", core::stringc(numMaterials).c_str()); -#endif - pPtr += sizeof(u16); - - if(numMaterials == 0) - { - // if there are no materials, add at least one buffer - AnimatedMesh->addMeshBuffer(); - } - - for (i=0; iAmbient[j] = os::Byteswap::byteswap(material->Ambient[j]); - for (u16 j=0; j<4; ++j) - material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]); - for (u16 j=0; j<4; ++j) - material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]); - for (u16 j=0; j<4; ++j) - material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]); - material->Shininess = os::Byteswap::byteswap(material->Shininess); - material->Transparency = os::Byteswap::byteswap(material->Transparency); -#endif - pPtr += sizeof(MS3DMaterial); - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - - scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->addMeshBuffer(); - - tmpBuffer->Material.MaterialType = video::EMT_SOLID; - - tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor (); - tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor (); - tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor (); - tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor (); - tmpBuffer->Material.Shininess = material->Shininess; - - core::stringc TexturePath(material->Texture); - if (TexturePath.trim()!="") - { - TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false); - tmpBuffer->Material.setTexture(0, Driver->getTexture(TexturePath)); - } - - core::stringc AlphamapPath=(const c8*)material->Alphamap; - if (AlphamapPath.trim()!="") - { - AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false); - tmpBuffer->Material.setTexture(2, Driver->getTexture(AlphamapPath)); - } - } - - // animation time - f32 framesPerSecond = *(float*)pPtr; -#ifdef __BIG_ENDIAN__ - framesPerSecond = os::Byteswap::byteswap(framesPerSecond); -#endif -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("FPS", core::stringc(framesPerSecond).c_str()); -#endif - pPtr += sizeof(float) * 2; // fps and current time - - if (framesPerSecond<1.f) - framesPerSecond=1.f; - AnimatedMesh->setAnimationSpeed(framesPerSecond); - -// ignore, calculated inside SkinnedMesh -// s32 frameCount = *(int*)pPtr; -#ifdef __BIG_ENDIAN__ -// frameCount = os::Byteswap::byteswap(frameCount); -#endif - pPtr += sizeof(int); - - u16 jointCount = *(u16*)pPtr; -#ifdef __BIG_ENDIAN__ - jointCount = os::Byteswap::byteswap(jointCount); -#endif -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Joints", core::stringc(jointCount).c_str()); -#endif - pPtr += sizeof(u16); - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - - core::array parentNames; - parentNames.reallocate(jointCount); - - // load joints - for (i=0; iRotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]); - for (j=0; j<3; ++j) - pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]); - pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes); - pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes); -#endif - pPtr += sizeof(MS3DJoint); - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - - ISkinnedMesh::SJoint *jnt = AnimatedMesh->addJoint(); - - jnt->Name = pJoint->Name; -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Joint", jnt->Name.c_str()); - os::Printer::log("Rotation keyframes", core::stringc(pJoint->NumRotationKeyframes).c_str()); - os::Printer::log("Translation keyframes", core::stringc(pJoint->NumTranslationKeyframes).c_str()); -#endif - jnt->LocalMatrix.makeIdentity(); - jnt->LocalMatrix.setRotationRadians( - core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) ); - // convert right-handed to left-handed - jnt->LocalMatrix[2]=-jnt->LocalMatrix[2]; - jnt->LocalMatrix[6]=-jnt->LocalMatrix[6]; - jnt->LocalMatrix[8]=-jnt->LocalMatrix[8]; - jnt->LocalMatrix[9]=-jnt->LocalMatrix[9]; - - jnt->LocalMatrix.setTranslation( - core::vector3df(pJoint->Translation[0], pJoint->Translation[1], -pJoint->Translation[2]) ); - jnt->Animatedposition.set(jnt->LocalMatrix.getTranslation()); - jnt->Animatedrotation.set(jnt->LocalMatrix.getRotationDegrees()); - - parentNames.push_back( (c8*)pJoint->ParentName ); - - /*if (pJoint->NumRotationKeyframes || - pJoint->NumTranslationKeyframes) - HasAnimation = true; - */ - - // get rotation keyframes - const u16 numRotationKeyframes = pJoint->NumRotationKeyframes; - for (j=0; j < numRotationKeyframes; ++j) - { - MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; -#ifdef __BIG_ENDIAN__ - kf->Time = os::Byteswap::byteswap(kf->Time); - for (u32 l=0; l<3; ++l) - kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); -#endif - pPtr += sizeof(MS3DKeyframe); - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - - ISkinnedMesh::SRotationKey *k=AnimatedMesh->addRotationKey(jnt); - k->frame = kf->Time * framesPerSecond-1; - - core::matrix4 tmpMatrix; - - tmpMatrix.setRotationRadians( - core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) ); - // convert right-handed to left-handed - tmpMatrix[2]=-tmpMatrix[2]; - tmpMatrix[6]=-tmpMatrix[6]; - tmpMatrix[8]=-tmpMatrix[8]; - tmpMatrix[9]=-tmpMatrix[9]; - - tmpMatrix=jnt->LocalMatrix*tmpMatrix; - - // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility. - // Not tested so far if this was correct or wrong before quaternion fix! - k->rotation = core::quaternion(tmpMatrix.getTransposed()); - } - - // get translation keyframes - const u16 numTranslationKeyframes = pJoint->NumTranslationKeyframes; - for (j=0; jTime = os::Byteswap::byteswap(kf->Time); - for (u32 l=0; l<3; ++l) - kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); -#endif - pPtr += sizeof(MS3DKeyframe); - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - - ISkinnedMesh::SPositionKey *k=AnimatedMesh->addPositionKey(jnt); - k->frame = kf->Time * framesPerSecond-1; - - k->position = core::vector3df - (kf->Parameter[0]+pJoint->Translation[0], - kf->Parameter[1]+pJoint->Translation[1], - -kf->Parameter[2]-pJoint->Translation[2]); - } - } - - core::array vertexWeights; - f32 weightFactor=0; - - if (jointCount && (pHeader->Version == 4) && (pPtr < buffer+fileSize)) - { - s32 subVersion = *(s32*)pPtr; // comment subVersion, always 1 -#ifdef __BIG_ENDIAN__ - subVersion = os::Byteswap::byteswap(subVersion); -#endif - pPtr += sizeof(s32); - - for (u32 j=0; j<4; ++j) // four comment groups - { -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Skipping comment group", core::stringc(j+1).c_str()); -#endif - u32 numComments = *(u32*)pPtr; -#ifdef __BIG_ENDIAN__ - numComments = os::Byteswap::byteswap(numComments); -#endif - pPtr += sizeof(u32); - for (i=0; i buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - } - - if (pPtr < buffer+fileSize) - { - subVersion = *(s32*)pPtr; // vertex subVersion, 1 or 2 -#ifdef __BIG_ENDIAN__ - subVersion = os::Byteswap::byteswap(subVersion); -#endif - if (subVersion==1) - weightFactor=1.f/255.f; - else - weightFactor=1.f/100.f; - pPtr += sizeof(s32); - -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Reading vertex weights"); -#endif - // read vertex weights, ignoring data 'extra' from 1.8.2 - vertexWeights.reallocate(numVertices); - const char offset = (subVersion==1)?6:10; - for (i=0; i buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); - return false; - } - } - - if (pPtr < buffer+fileSize) - { - subVersion = *(s32*)pPtr; // joint subVersion, 1 or 2 -#ifdef __BIG_ENDIAN__ - subVersion = os::Byteswap::byteswap(subVersion); -#endif - pPtr += sizeof(s32); - // skip joint colors -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Skip joint color"); -#endif - pPtr += 3*sizeof(float)*jointCount; - - if (pPtr > buffer+fileSize) - { - delete [] buffer; - os::Printer::log("Loading failed. Corrupted data found", file->getFileName(), ELL_ERROR); - return false; - } - } - - if (pPtr < buffer+fileSize) - { - subVersion = *(s32*)pPtr; // model subVersion, 1 or 2 -#ifdef __BIG_ENDIAN__ - subVersion = os::Byteswap::byteswap(subVersion); -#endif - pPtr += sizeof(s32); -#ifdef _IRR_DEBUG_MS3D_LOADER_ - os::Printer::log("Skip model extra information"); -#endif - // now the model extra information would follow - // we also skip this for now - } - } - - //find parent of every joint - for (u32 jointnum=0; jointnumgetAllJoints().size(); ++jointnum) - { - for (u32 j2=0; j2getAllJoints().size(); ++j2) - { - if (jointnum != j2 && parentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name ) - { - AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]); - break; - } - } - } - - // create vertices and indices, attach them to the joints. - video::S3DVertex v; - core::array *Vertices; - core::array Indices; - - for (i=0; igetMeshBuffers()[tmp]->Vertices_Standard; - - for (s32 j = 2; j!=-1; --j) - { - const u32 vertidx = triangles[i].VertexIndices[j]; - - v.TCoords.X = triangles[i].S[j]; - v.TCoords.Y = triangles[i].T[j]; - - v.Normal.X = triangles[i].VertexNormals[j][0]; - v.Normal.Y = triangles[i].VertexNormals[j][1]; - v.Normal.Z = triangles[i].VertexNormals[j][2]; - - if(triangles[i].GroupIndex < groups.size() && - groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size()) - v.Color = AnimatedMesh->getMeshBuffers()[groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor; - else - v.Color.set(255,255,255,255); - - v.Pos.X = vertices[vertidx].Vertex[0]; - v.Pos.Y = vertices[vertidx].Vertex[1]; - v.Pos.Z = vertices[vertidx].Vertex[2]; - - // check if we already have this vertex in our vertex array - s32 index = -1; - for (u32 iV = 0; iV < Vertices->size(); ++iV) - { - if (v == (*Vertices)[iV]) - { - index = (s32)iV; - break; - } - } - - if (index == -1) - { - index = Vertices->size(); - const u32 matidx = groups[triangles[i].GroupIndex].MaterialIdx; - if (vertexWeights.size()==0) - { - const s32 boneid = vertices[vertidx].BoneID; - if ((u32)boneid < AnimatedMesh->getAllJoints().size()) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - w->strength = 1.0f; - w->vertex_id = index; - } - } - else if (jointCount) // new weights from 1.8.x - { - f32 sum = 1.0f; - s32 boneid = vertices[vertidx].BoneID; - if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[0] != 0)) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - sum -= (w->strength = vertexWeights[vertidx].weights[0]*weightFactor); - w->vertex_id = index; - } - boneid = vertexWeights[vertidx].boneIds[0]; - if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[1] != 0)) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - sum -= (w->strength = vertexWeights[vertidx].weights[1]*weightFactor); - w->vertex_id = index; - } - boneid = vertexWeights[vertidx].boneIds[1]; - if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[2] != 0)) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - sum -= (w->strength = vertexWeights[vertidx].weights[2]*weightFactor); - w->vertex_id = index; - } - boneid = vertexWeights[vertidx].boneIds[2]; - if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (sum > 0.f)) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - w->strength = sum; - w->vertex_id = index; - } - // fallback, if no bone chosen. Seems to be an error in the specs - boneid = vertices[vertidx].BoneID; - if ((sum == 1.f) && ((u32)boneid < AnimatedMesh->getAllJoints().size())) - { - ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); - w->buffer_id = matidx; - w->strength = 1.f; - w->vertex_id = index; - } - } - - Vertices->push_back(v); - } - Indices.push_back(index); - } - } - - //create groups - s32 iIndex = -1; - for (i=0; i= AnimatedMesh->getMeshBuffers().size()) - grp.MaterialIdx = 0; - - core::array& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices; - - for (u32 k=0; k < grp.VertexIds.size(); ++k) - for (u32 l=0; l<3; ++l) - indices.push_back(Indices[++iIndex]); - } - - delete [] buffer; - - return true; -} - - -core::stringc CMS3DMeshFileLoader::stripPathFromString(const core::stringc& inString, bool returnPath) const -{ - s32 slashIndex=inString.findLast('/'); // forward slash - s32 backSlash=inString.findLast('\\'); // back slash - - if (backSlash>slashIndex) slashIndex=backSlash; - - if (slashIndex==-1)//no slashes found - { - if (returnPath) - return core::stringc(); //no path to return - else - return inString; - } - - if (returnPath) - return inString.subString(0, slashIndex + 1); - else - return inString.subString(slashIndex+1, inString.size() - (slashIndex+1)); -} - - -} // end namespace scene -} // end namespace irr - -#endif +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CMS3DMeshFileLoader.h" +#include "CSkinnedMesh.h" + + +namespace irr +{ +namespace scene +{ + +#ifdef _DEBUG +#define _IRR_DEBUG_MS3D_LOADER_ +#endif + +// byte-align structures +#include "irrpack.h" + +namespace { +// File header +struct MS3DHeader +{ + char ID[10]; + int Version; +} PACK_STRUCT; + +// Vertex information +struct MS3DVertex +{ + u8 Flags; + float Vertex[3]; + char BoneID; + u8 RefCount; +} PACK_STRUCT; + +// Triangle information +struct MS3DTriangle +{ + u16 Flags; + u16 VertexIndices[3]; + float VertexNormals[3][3]; + float S[3], T[3]; + u8 SmoothingGroup; + u8 GroupIndex; +} PACK_STRUCT; + +// Material information +struct MS3DMaterial +{ + char Name[32]; + float Ambient[4]; + float Diffuse[4]; + float Specular[4]; + float Emissive[4]; + float Shininess; // 0.0f - 128.0f + float Transparency; // 0.0f - 1.0f + u8 Mode; // 0, 1, 2 is unused now + char Texture[128]; + char Alphamap[128]; +} PACK_STRUCT; + +// Joint information +struct MS3DJoint +{ + u8 Flags; + char Name[32]; + char ParentName[32]; + float Rotation[3]; + float Translation[3]; + u16 NumRotationKeyframes; + u16 NumTranslationKeyframes; +} PACK_STRUCT; + +// Keyframe data +struct MS3DKeyframe +{ + float Time; + float Parameter[3]; +} PACK_STRUCT; + +// vertex weights in 1.8.x +struct MS3DVertexWeights +{ + char boneIds[3]; + u8 weights[3]; +} PACK_STRUCT; + +} // end namespace + +// Default alignment +#include "irrunpack.h" + +struct SGroup +{ + core::stringc Name; + core::array VertexIds; + u16 MaterialIdx; +}; + +//! Constructor +CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver) +: Driver(driver), AnimatedMesh(0) +{ + #ifdef _DEBUG + setDebugName("CMS3DMeshFileLoader"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMS3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "ms3d" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CMS3DMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + AnimatedMesh = new CSkinnedMesh(); + + if ( load(file) ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + + +//! loads a milkshape file +bool CMS3DMeshFileLoader::load(io::IReadFile* file) +{ + if (!file) + return false; + + // find file size + const long fileSize = file->getSize(); + + // read whole file + + u8* buffer = new u8[fileSize]; + s32 read = file->read(buffer, fileSize); + if (read != fileSize) + { + delete [] buffer; + os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + + // read header + + const u8 *pPtr = (u8*)((void*)buffer); + MS3DHeader *pHeader = (MS3DHeader*)pPtr; + pPtr += sizeof(MS3DHeader); + + if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 ) + { + delete [] buffer; + os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + +#ifdef __BIG_ENDIAN__ + pHeader->Version = os::Byteswap::byteswap(pHeader->Version); +#endif + if ( pHeader->Version < 3 || pHeader->Version > 4 ) + { + delete [] buffer; + os::Printer::log("Only Milkshape3D version 3 and 4 (1.3 to 1.8) is supported. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Loaded header version", core::stringc(pHeader->Version).c_str()); +#endif + + // get pointers to data + + // vertices + u16 numVertices = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + numVertices = os::Byteswap::byteswap(numVertices); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Load vertices", core::stringc(numVertices).c_str()); +#endif + pPtr += sizeof(u16); + MS3DVertex *vertices = (MS3DVertex*)pPtr; + pPtr += sizeof(MS3DVertex) * numVertices; + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + for (u16 tmp=0; tmp buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + for (u16 tmp=0; tmp groups; + groups.reallocate(numGroups); + + //store groups + u32 i; + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + // load materials + u16 numMaterials = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + numMaterials = os::Byteswap::byteswap(numMaterials); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Load Materials", core::stringc(numMaterials).c_str()); +#endif + pPtr += sizeof(u16); + + if(numMaterials == 0) + { + // if there are no materials, add at least one buffer + AnimatedMesh->addMeshBuffer(); + } + + for (i=0; iAmbient[j] = os::Byteswap::byteswap(material->Ambient[j]); + for (u16 j=0; j<4; ++j) + material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]); + for (u16 j=0; j<4; ++j) + material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]); + for (u16 j=0; j<4; ++j) + material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]); + material->Shininess = os::Byteswap::byteswap(material->Shininess); + material->Transparency = os::Byteswap::byteswap(material->Transparency); +#endif + pPtr += sizeof(MS3DMaterial); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->addMeshBuffer(); + + tmpBuffer->Material.MaterialType = video::EMT_SOLID; + + tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor (); + tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor (); + tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor (); + tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor (); + tmpBuffer->Material.Shininess = material->Shininess; + + core::stringc TexturePath(material->Texture); + if (TexturePath.trim()!="") + { + TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false); + tmpBuffer->Material.setTexture(0, Driver->getTexture(TexturePath)); + } + + core::stringc AlphamapPath=(const c8*)material->Alphamap; + if (AlphamapPath.trim()!="") + { + AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false); + tmpBuffer->Material.setTexture(2, Driver->getTexture(AlphamapPath)); + } + } + + // animation time + f32 framesPerSecond = *(float*)pPtr; +#ifdef __BIG_ENDIAN__ + framesPerSecond = os::Byteswap::byteswap(framesPerSecond); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("FPS", core::stringc(framesPerSecond).c_str()); +#endif + pPtr += sizeof(float) * 2; // fps and current time + + if (framesPerSecond<1.f) + framesPerSecond=1.f; + AnimatedMesh->setAnimationSpeed(framesPerSecond); + +// ignore, calculated inside SkinnedMesh +// s32 frameCount = *(int*)pPtr; +#ifdef __BIG_ENDIAN__ +// frameCount = os::Byteswap::byteswap(frameCount); +#endif + pPtr += sizeof(int); + + u16 jointCount = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + jointCount = os::Byteswap::byteswap(jointCount); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Joints", core::stringc(jointCount).c_str()); +#endif + pPtr += sizeof(u16); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + core::array parentNames; + parentNames.reallocate(jointCount); + + // load joints + for (i=0; iRotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]); + for (j=0; j<3; ++j) + pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]); + pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes); + pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes); +#endif + pPtr += sizeof(MS3DJoint); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SJoint *jnt = AnimatedMesh->addJoint(); + + jnt->Name = pJoint->Name; +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Joint", jnt->Name.c_str()); + os::Printer::log("Rotation keyframes", core::stringc(pJoint->NumRotationKeyframes).c_str()); + os::Printer::log("Translation keyframes", core::stringc(pJoint->NumTranslationKeyframes).c_str()); +#endif + jnt->LocalMatrix.makeIdentity(); + jnt->LocalMatrix.setRotationRadians( + core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) ); + // convert right-handed to left-handed + jnt->LocalMatrix[2]=-jnt->LocalMatrix[2]; + jnt->LocalMatrix[6]=-jnt->LocalMatrix[6]; + jnt->LocalMatrix[8]=-jnt->LocalMatrix[8]; + jnt->LocalMatrix[9]=-jnt->LocalMatrix[9]; + + jnt->LocalMatrix.setTranslation( + core::vector3df(pJoint->Translation[0], pJoint->Translation[1], -pJoint->Translation[2]) ); + jnt->Animatedposition.set(jnt->LocalMatrix.getTranslation()); + jnt->Animatedrotation.set(jnt->LocalMatrix.getRotationDegrees()); + + parentNames.push_back( (c8*)pJoint->ParentName ); + + /*if (pJoint->NumRotationKeyframes || + pJoint->NumTranslationKeyframes) + HasAnimation = true; + */ + + // get rotation keyframes + const u16 numRotationKeyframes = pJoint->NumRotationKeyframes; + for (j=0; j < numRotationKeyframes; ++j) + { + MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; +#ifdef __BIG_ENDIAN__ + kf->Time = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SRotationKey *k=AnimatedMesh->addRotationKey(jnt); + k->frame = kf->Time * framesPerSecond-1; + + core::matrix4 tmpMatrix; + + tmpMatrix.setRotationRadians( + core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) ); + // convert right-handed to left-handed + tmpMatrix[2]=-tmpMatrix[2]; + tmpMatrix[6]=-tmpMatrix[6]; + tmpMatrix[8]=-tmpMatrix[8]; + tmpMatrix[9]=-tmpMatrix[9]; + + tmpMatrix=jnt->LocalMatrix*tmpMatrix; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + k->rotation = core::quaternion(tmpMatrix.getTransposed()); + } + + // get translation keyframes + const u16 numTranslationKeyframes = pJoint->NumTranslationKeyframes; + for (j=0; jTime = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SPositionKey *k=AnimatedMesh->addPositionKey(jnt); + k->frame = kf->Time * framesPerSecond-1; + + k->position = core::vector3df + (kf->Parameter[0]+pJoint->Translation[0], + kf->Parameter[1]+pJoint->Translation[1], + -kf->Parameter[2]-pJoint->Translation[2]); + } + } + + core::array vertexWeights; + f32 weightFactor=0; + + if (jointCount && (pHeader->Version == 4) && (pPtr < buffer+fileSize)) + { + s32 subVersion = *(s32*)pPtr; // comment subVersion, always 1 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); + + for (u32 j=0; j<4; ++j) // four comment groups + { +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skipping comment group", core::stringc(j+1).c_str()); +#endif + u32 numComments = *(u32*)pPtr; +#ifdef __BIG_ENDIAN__ + numComments = os::Byteswap::byteswap(numComments); +#endif + pPtr += sizeof(u32); + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // vertex subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + if (subVersion==1) + weightFactor=1.f/255.f; + else + weightFactor=1.f/100.f; + pPtr += sizeof(s32); + +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Reading vertex weights"); +#endif + // read vertex weights, ignoring data 'extra' from 1.8.2 + vertexWeights.reallocate(numVertices); + const char offset = (subVersion==1)?6:10; + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // joint subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); + // skip joint colors +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skip joint color"); +#endif + pPtr += 3*sizeof(float)*jointCount; + + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // model subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skip model extra information"); +#endif + // now the model extra information would follow + // we also skip this for now + } + } + + //find parent of every joint + for (u32 jointnum=0; jointnumgetAllJoints().size(); ++jointnum) + { + for (u32 j2=0; j2getAllJoints().size(); ++j2) + { + if (jointnum != j2 && parentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name ) + { + AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]); + break; + } + } + } + + // create vertices and indices, attach them to the joints. + video::S3DVertex v; + core::array *Vertices; + core::array Indices; + + for (i=0; igetMeshBuffers()[tmp]->Vertices_Standard; + + for (s32 j = 2; j!=-1; --j) + { + const u32 vertidx = triangles[i].VertexIndices[j]; + + v.TCoords.X = triangles[i].S[j]; + v.TCoords.Y = triangles[i].T[j]; + + v.Normal.X = triangles[i].VertexNormals[j][0]; + v.Normal.Y = triangles[i].VertexNormals[j][1]; + v.Normal.Z = triangles[i].VertexNormals[j][2]; + + if(triangles[i].GroupIndex < groups.size() && + groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size()) + v.Color = AnimatedMesh->getMeshBuffers()[groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor; + else + v.Color.set(255,255,255,255); + + v.Pos.X = vertices[vertidx].Vertex[0]; + v.Pos.Y = vertices[vertidx].Vertex[1]; + v.Pos.Z = vertices[vertidx].Vertex[2]; + + // check if we already have this vertex in our vertex array + s32 index = -1; + for (u32 iV = 0; iV < Vertices->size(); ++iV) + { + if (v == (*Vertices)[iV]) + { + index = (s32)iV; + break; + } + } + + if (index == -1) + { + index = Vertices->size(); + const u32 matidx = groups[triangles[i].GroupIndex].MaterialIdx; + if (vertexWeights.size()==0) + { + const s32 boneid = vertices[vertidx].BoneID; + if ((u32)boneid < AnimatedMesh->getAllJoints().size()) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = 1.0f; + w->vertex_id = index; + } + } + else if (jointCount) // new weights from 1.8.x + { + f32 sum = 1.0f; + s32 boneid = vertices[vertidx].BoneID; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[0] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[0]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[0]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[1] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[1]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[1]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[2] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[2]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[2]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (sum > 0.f)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = sum; + w->vertex_id = index; + } + // fallback, if no bone chosen. Seems to be an error in the specs + boneid = vertices[vertidx].BoneID; + if ((sum == 1.f) && ((u32)boneid < AnimatedMesh->getAllJoints().size())) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = 1.f; + w->vertex_id = index; + } + } + + Vertices->push_back(v); + } + Indices.push_back(index); + } + } + + //create groups + s32 iIndex = -1; + for (i=0; i= AnimatedMesh->getMeshBuffers().size()) + grp.MaterialIdx = 0; + + core::array& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices; + + for (u32 k=0; k < grp.VertexIds.size(); ++k) + for (u32 l=0; l<3; ++l) + indices.push_back(Indices[++iIndex]); + } + + delete [] buffer; + + return true; +} + + +core::stringc CMS3DMeshFileLoader::stripPathFromString(const core::stringc& inString, bool returnPath) const +{ + s32 slashIndex=inString.findLast('/'); // forward slash + s32 backSlash=inString.findLast('\\'); // back slash + + if (backSlash>slashIndex) slashIndex=backSlash; + + if (slashIndex==-1)//no slashes found + { + if (returnPath) + return core::stringc(); //no path to return + else + return inString; + } + + if (returnPath) + return inString.subString(0, slashIndex + 1); + else + return inString.subString(slashIndex+1, inString.size() - (slashIndex+1)); +} + + +} // end namespace scene +} // end namespace irr + +#endif -- cgit v1.1