nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file Implementation of the MDC importer class */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_MDC_IMPORTER nuclear@0: nuclear@0: // internal headers nuclear@0: #include "MDCLoader.h" nuclear@0: #include "MD3FileData.h" nuclear@0: #include "MDCNormalTable.h" // shouldn't be included by other units nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: using namespace Assimp::MDC; nuclear@0: nuclear@0: static const aiImporterDesc desc = { nuclear@0: "Return To Castle Wolfenstein Mesh Importer", nuclear@0: "", nuclear@0: "", nuclear@0: "", nuclear@0: aiImporterFlags_SupportBinaryFlavour, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: "mdc" nuclear@0: }; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void MDC::BuildVertex(const Frame& frame, nuclear@0: const BaseVertex& bvert, nuclear@0: const CompressedVertex& cvert, nuclear@0: aiVector3D& vXYZOut, nuclear@0: aiVector3D& vNorOut) nuclear@0: { nuclear@0: // compute the position nuclear@0: const float xd = (cvert.xd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; nuclear@0: const float yd = (cvert.yd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; nuclear@0: const float zd = (cvert.zd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING; nuclear@0: vXYZOut.x = frame.localOrigin.x + AI_MDC_BASE_SCALING * (bvert.x + xd); nuclear@0: vXYZOut.y = frame.localOrigin.y + AI_MDC_BASE_SCALING * (bvert.y + yd); nuclear@0: vXYZOut.z = frame.localOrigin.z + AI_MDC_BASE_SCALING * (bvert.z + zd); nuclear@0: nuclear@0: // compute the normal vector .. ehm ... lookup it in the table :-) nuclear@0: vNorOut.x = mdcNormals[cvert.nd][0]; nuclear@0: vNorOut.y = mdcNormals[cvert.nd][1]; nuclear@0: vNorOut.z = mdcNormals[cvert.nd][2]; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Constructor to be privately used by Importer nuclear@0: MDCImporter::MDCImporter() nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Destructor, private as well nuclear@0: MDCImporter::~MDCImporter() nuclear@0: { nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the class can handle the format of the given file. nuclear@0: bool MDCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const nuclear@0: { nuclear@0: const std::string extension = GetExtension(pFile); nuclear@0: if (extension == "mdc") nuclear@0: return true; nuclear@0: nuclear@0: // if check for extension is not enough, check for the magic tokens nuclear@0: if (!extension.length() || checkSig) { nuclear@0: uint32_t tokens[1]; nuclear@0: tokens[0] = AI_MDC_MAGIC_NUMBER_LE; nuclear@0: return CheckMagicToken(pIOHandler,pFile,tokens,1); nuclear@0: } nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiImporterDesc* MDCImporter::GetInfo () const nuclear@0: { nuclear@0: return &desc; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Validate the header of the given MDC file nuclear@0: void MDCImporter::ValidateHeader() nuclear@0: { nuclear@0: AI_SWAP4( this->pcHeader->ulVersion ); nuclear@0: AI_SWAP4( this->pcHeader->ulFlags ); nuclear@0: AI_SWAP4( this->pcHeader->ulNumFrames ); nuclear@0: AI_SWAP4( this->pcHeader->ulNumTags ); nuclear@0: AI_SWAP4( this->pcHeader->ulNumSurfaces ); nuclear@0: AI_SWAP4( this->pcHeader->ulNumSkins ); nuclear@0: AI_SWAP4( this->pcHeader->ulOffsetBorderFrames ); nuclear@0: nuclear@0: if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE && nuclear@0: pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) nuclear@0: { nuclear@0: char szBuffer[5]; nuclear@0: szBuffer[0] = ((char*)&pcHeader->ulIdent)[0]; nuclear@0: szBuffer[1] = ((char*)&pcHeader->ulIdent)[1]; nuclear@0: szBuffer[2] = ((char*)&pcHeader->ulIdent)[2]; nuclear@0: szBuffer[3] = ((char*)&pcHeader->ulIdent)[3]; nuclear@0: szBuffer[4] = '\0'; nuclear@0: nuclear@0: throw DeadlyImportError("Invalid MDC magic word: should be IDPC, the " nuclear@0: "magic word found is " + std::string( szBuffer )); nuclear@0: } nuclear@0: nuclear@0: if (pcHeader->ulVersion != AI_MDC_VERSION) nuclear@0: DefaultLogger::get()->warn("Unsupported MDC file version (2 (AI_MDC_VERSION) was expected)"); nuclear@0: nuclear@0: if (pcHeader->ulOffsetBorderFrames + pcHeader->ulNumFrames * sizeof(MDC::Frame) > this->fileSize || nuclear@0: pcHeader->ulOffsetSurfaces + pcHeader->ulNumSurfaces * sizeof(MDC::Surface) > this->fileSize) nuclear@0: { nuclear@0: throw DeadlyImportError("Some of the offset values in the MDC header are invalid " nuclear@0: "and point to something behind the file."); nuclear@0: } nuclear@0: nuclear@0: if (this->configFrameID >= this->pcHeader->ulNumFrames) nuclear@0: throw DeadlyImportError("The requested frame is not available"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Validate the header of a given MDC file surface nuclear@0: void MDCImporter::ValidateSurfaceHeader(BE_NCONST MDC::Surface* pcSurf) nuclear@0: { nuclear@0: AI_SWAP4(pcSurf->ulFlags); nuclear@0: AI_SWAP4(pcSurf->ulNumCompFrames); nuclear@0: AI_SWAP4(pcSurf->ulNumBaseFrames); nuclear@0: AI_SWAP4(pcSurf->ulNumShaders); nuclear@0: AI_SWAP4(pcSurf->ulNumVertices); nuclear@0: AI_SWAP4(pcSurf->ulNumTriangles); nuclear@0: AI_SWAP4(pcSurf->ulOffsetTriangles); nuclear@0: AI_SWAP4(pcSurf->ulOffsetTexCoords); nuclear@0: AI_SWAP4(pcSurf->ulOffsetBaseVerts); nuclear@0: AI_SWAP4(pcSurf->ulOffsetCompVerts); nuclear@0: AI_SWAP4(pcSurf->ulOffsetFrameBaseFrames); nuclear@0: AI_SWAP4(pcSurf->ulOffsetFrameCompFrames); nuclear@0: AI_SWAP4(pcSurf->ulOffsetEnd); nuclear@0: nuclear@0: const unsigned int iMax = this->fileSize - (unsigned int)((int8_t*)pcSurf-(int8_t*)pcHeader); nuclear@0: nuclear@0: if (pcSurf->ulOffsetBaseVerts + pcSurf->ulNumVertices * sizeof(MDC::BaseVertex) > iMax || nuclear@0: (pcSurf->ulNumCompFrames && pcSurf->ulOffsetCompVerts + pcSurf->ulNumVertices * sizeof(MDC::CompressedVertex) > iMax) || nuclear@0: pcSurf->ulOffsetTriangles + pcSurf->ulNumTriangles * sizeof(MDC::Triangle) > iMax || nuclear@0: pcSurf->ulOffsetTexCoords + pcSurf->ulNumVertices * sizeof(MDC::TexturCoord) > iMax || nuclear@0: pcSurf->ulOffsetShaders + pcSurf->ulNumShaders * sizeof(MDC::Shader) > iMax || nuclear@0: pcSurf->ulOffsetFrameBaseFrames + pcSurf->ulNumBaseFrames * 2 > iMax || nuclear@0: (pcSurf->ulNumCompFrames && pcSurf->ulOffsetFrameCompFrames + pcSurf->ulNumCompFrames * 2 > iMax)) nuclear@0: { nuclear@0: throw DeadlyImportError("Some of the offset values in the MDC surface header " nuclear@0: "are invalid and point somewhere behind the file."); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Setup configuration properties nuclear@0: void MDCImporter::SetupProperties(const Importer* pImp) nuclear@0: { nuclear@0: // The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the nuclear@0: // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. nuclear@0: if(static_cast(-1) == (configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDC_KEYFRAME,-1))){ nuclear@0: configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Imports the given file into the given scene structure. nuclear@0: void MDCImporter::InternReadFile( nuclear@0: const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) nuclear@0: { nuclear@0: boost::scoped_ptr file( pIOHandler->Open( pFile)); nuclear@0: nuclear@0: // Check whether we can read from the file nuclear@0: if( file.get() == NULL) nuclear@0: throw DeadlyImportError( "Failed to open MDC file " + pFile + "."); nuclear@0: nuclear@0: // check whether the mdc file is large enough to contain the file header nuclear@0: fileSize = (unsigned int)file->FileSize(); nuclear@0: if( fileSize < sizeof(MDC::Header)) nuclear@0: throw DeadlyImportError( "MDC File is too small."); nuclear@0: nuclear@0: std::vector mBuffer2(fileSize); nuclear@0: file->Read( &mBuffer2[0], 1, fileSize); nuclear@0: mBuffer = &mBuffer2[0]; nuclear@0: nuclear@0: // validate the file header nuclear@0: this->pcHeader = (BE_NCONST MDC::Header*)this->mBuffer; nuclear@0: this->ValidateHeader(); nuclear@0: nuclear@0: std::vector aszShaders; nuclear@0: nuclear@0: // get a pointer to the frame we want to read nuclear@0: BE_NCONST MDC::Frame* pcFrame = (BE_NCONST MDC::Frame*)(this->mBuffer+ nuclear@0: this->pcHeader->ulOffsetBorderFrames); nuclear@0: nuclear@0: // no need to swap the other members, we won't need them nuclear@0: pcFrame += configFrameID; nuclear@0: AI_SWAP4( pcFrame->localOrigin[0] ); nuclear@0: AI_SWAP4( pcFrame->localOrigin[1] ); nuclear@0: AI_SWAP4( pcFrame->localOrigin[2] ); nuclear@0: nuclear@0: // get the number of valid surfaces nuclear@0: BE_NCONST MDC::Surface* pcSurface, *pcSurface2; nuclear@0: pcSurface = pcSurface2 = new (mBuffer + pcHeader->ulOffsetSurfaces) MDC::Surface; nuclear@0: unsigned int iNumShaders = 0; nuclear@0: for (unsigned int i = 0; i < pcHeader->ulNumSurfaces;++i) nuclear@0: { nuclear@0: // validate the surface header nuclear@0: this->ValidateSurfaceHeader(pcSurface2); nuclear@0: nuclear@0: if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles)++pScene->mNumMeshes; nuclear@0: iNumShaders += pcSurface2->ulNumShaders; nuclear@0: pcSurface2 = new ((int8_t*)pcSurface2 + pcSurface2->ulOffsetEnd) MDC::Surface; nuclear@0: } nuclear@0: aszShaders.reserve(iNumShaders); nuclear@0: pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; nuclear@0: nuclear@0: // necessary that we don't crash if an exception occurs nuclear@0: for (unsigned int i = 0; i < pScene->mNumMeshes;++i) nuclear@0: pScene->mMeshes[i] = NULL; nuclear@0: nuclear@0: // now read all surfaces nuclear@0: unsigned int iDefaultMatIndex = UINT_MAX; nuclear@0: for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces;++i) nuclear@0: { nuclear@0: if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles)continue; nuclear@0: aiMesh* pcMesh = pScene->mMeshes[iNum++] = new aiMesh(); nuclear@0: nuclear@0: pcMesh->mNumFaces = pcSurface->ulNumTriangles; nuclear@0: pcMesh->mNumVertices = pcMesh->mNumFaces * 3; nuclear@0: nuclear@0: // store the name of the surface for use as node name. nuclear@0: // FIX: make sure there is a 0 termination nuclear@0: const_cast(pcSurface->ucName[AI_MDC_MAXQPATH-1]) = '\0'; nuclear@0: pcMesh->mTextureCoords[3] = (aiVector3D*)pcSurface->ucName; nuclear@0: nuclear@0: // go to the first shader in the file. ignore the others. nuclear@0: if (pcSurface->ulNumShaders) nuclear@0: { nuclear@0: const MDC::Shader* pcShader = (const MDC::Shader*)((int8_t*)pcSurface + pcSurface->ulOffsetShaders); nuclear@0: pcMesh->mMaterialIndex = (unsigned int)aszShaders.size(); nuclear@0: nuclear@0: // create a new shader nuclear@0: aszShaders.push_back(std::string( pcShader->ucName, std::min( nuclear@0: ::strlen(pcShader->ucName),sizeof(pcShader->ucName)) )); nuclear@0: } nuclear@0: // need to create a default material nuclear@0: else if (UINT_MAX == iDefaultMatIndex) nuclear@0: { nuclear@0: pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size(); nuclear@0: aszShaders.push_back(std::string()); nuclear@0: } nuclear@0: // otherwise assign a reference to the default material nuclear@0: else pcMesh->mMaterialIndex = iDefaultMatIndex; nuclear@0: nuclear@0: // allocate output storage for the mesh nuclear@0: aiVector3D* pcVertCur = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; nuclear@0: aiVector3D* pcNorCur = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; nuclear@0: aiVector3D* pcUVCur = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; nuclear@0: aiFace* pcFaceCur = pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; nuclear@0: nuclear@0: // create all vertices/faces nuclear@0: BE_NCONST MDC::Triangle* pcTriangle = (BE_NCONST MDC::Triangle*) nuclear@0: ((int8_t*)pcSurface+pcSurface->ulOffsetTriangles); nuclear@0: nuclear@0: BE_NCONST MDC::TexturCoord* const pcUVs = (BE_NCONST MDC::TexturCoord*) nuclear@0: ((int8_t*)pcSurface+pcSurface->ulOffsetTexCoords); nuclear@0: nuclear@0: // get a pointer to the uncompressed vertices nuclear@0: int16_t iOfs = *((int16_t*) ((int8_t*) pcSurface + nuclear@0: pcSurface->ulOffsetFrameBaseFrames) + this->configFrameID); nuclear@0: nuclear@0: AI_SWAP2(iOfs); nuclear@0: nuclear@0: BE_NCONST MDC::BaseVertex* const pcVerts = (BE_NCONST MDC::BaseVertex*) nuclear@0: ((int8_t*)pcSurface+pcSurface->ulOffsetBaseVerts) + nuclear@0: ((int)iOfs * pcSurface->ulNumVertices * 4); nuclear@0: nuclear@0: // do the main swapping stuff ... nuclear@0: #if (defined AI_BUILD_BIG_ENDIAN) nuclear@0: nuclear@0: // swap all triangles nuclear@0: for (unsigned int i = 0; i < pcSurface->ulNumTriangles;++i) nuclear@0: { nuclear@0: AI_SWAP4( pcTriangle[i].aiIndices[0] ); nuclear@0: AI_SWAP4( pcTriangle[i].aiIndices[1] ); nuclear@0: AI_SWAP4( pcTriangle[i].aiIndices[2] ); nuclear@0: } nuclear@0: nuclear@0: // swap all vertices nuclear@0: for (unsigned int i = 0; i < pcSurface->ulNumVertices*pcSurface->ulNumBaseFrames;++i) nuclear@0: { nuclear@0: AI_SWAP2( pcVerts->normal ); nuclear@0: AI_SWAP2( pcVerts->x ); nuclear@0: AI_SWAP2( pcVerts->y ); nuclear@0: AI_SWAP2( pcVerts->z ); nuclear@0: } nuclear@0: nuclear@0: // swap all texture coordinates nuclear@0: for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i) nuclear@0: { nuclear@0: AI_SWAP4( pcUVs->v ); nuclear@0: AI_SWAP4( pcUVs->v ); nuclear@0: } nuclear@0: nuclear@0: #endif nuclear@0: nuclear@0: const MDC::CompressedVertex* pcCVerts = NULL; nuclear@0: int16_t* mdcCompVert = NULL; nuclear@0: nuclear@0: // access compressed frames for large frame numbers, but never for the first nuclear@0: if( this->configFrameID && pcSurface->ulNumCompFrames > 0 ) nuclear@0: { nuclear@0: mdcCompVert = (int16_t*) ((int8_t*)pcSurface+pcSurface->ulOffsetFrameCompFrames) + this->configFrameID; nuclear@0: AI_SWAP2P(mdcCompVert); nuclear@0: if( *mdcCompVert >= 0 ) nuclear@0: { nuclear@0: pcCVerts = (const MDC::CompressedVertex*)((int8_t*)pcSurface + nuclear@0: pcSurface->ulOffsetCompVerts) + *mdcCompVert * pcSurface->ulNumVertices; nuclear@0: } nuclear@0: else mdcCompVert = NULL; nuclear@0: } nuclear@0: nuclear@0: // copy all faces nuclear@0: for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles;++iFace, nuclear@0: ++pcTriangle,++pcFaceCur) nuclear@0: { nuclear@0: const unsigned int iOutIndex = iFace*3; nuclear@0: pcFaceCur->mNumIndices = 3; nuclear@0: pcFaceCur->mIndices = new unsigned int[3]; nuclear@0: nuclear@0: for (unsigned int iIndex = 0; iIndex < 3;++iIndex, nuclear@0: ++pcVertCur,++pcUVCur,++pcNorCur) nuclear@0: { nuclear@0: uint32_t quak = pcTriangle->aiIndices[iIndex]; nuclear@0: if (quak >= pcSurface->ulNumVertices) nuclear@0: { nuclear@0: DefaultLogger::get()->error("MDC vertex index is out of range"); nuclear@0: quak = pcSurface->ulNumVertices-1; nuclear@0: } nuclear@0: nuclear@0: // compressed vertices? nuclear@0: if (mdcCompVert) nuclear@0: { nuclear@0: MDC::BuildVertex(*pcFrame,pcVerts[quak],pcCVerts[quak], nuclear@0: *pcVertCur,*pcNorCur); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // copy position nuclear@0: pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING; nuclear@0: pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING; nuclear@0: pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING; nuclear@0: nuclear@0: // copy normals nuclear@0: MD3::LatLngNormalToVec3( pcVerts[quak].normal, &pcNorCur->x ); nuclear@0: nuclear@0: // copy texture coordinates nuclear@0: pcUVCur->x = pcUVs[quak].u; nuclear@0: pcUVCur->y = 1.0f-pcUVs[quak].v; // DX to OGL nuclear@0: } nuclear@0: pcVertCur->x += pcFrame->localOrigin[0] ; nuclear@0: pcVertCur->y += pcFrame->localOrigin[1] ; nuclear@0: pcVertCur->z += pcFrame->localOrigin[2] ; nuclear@0: } nuclear@0: nuclear@0: // swap the face order - DX to OGL nuclear@0: pcFaceCur->mIndices[0] = iOutIndex + 2; nuclear@0: pcFaceCur->mIndices[1] = iOutIndex + 1; nuclear@0: pcFaceCur->mIndices[2] = iOutIndex + 0; nuclear@0: } nuclear@0: nuclear@0: pcSurface = new ((int8_t*)pcSurface + pcSurface->ulOffsetEnd) MDC::Surface; nuclear@0: } nuclear@0: nuclear@0: // create a flat node graph with a root node and one child for each surface nuclear@0: if (!pScene->mNumMeshes) nuclear@0: throw DeadlyImportError( "Invalid MDC file: File contains no valid mesh"); nuclear@0: else if (1 == pScene->mNumMeshes) nuclear@0: { nuclear@0: pScene->mRootNode = new aiNode(); nuclear@0: pScene->mRootNode->mName.Set(std::string((const char*)pScene->mMeshes[0]->mTextureCoords[3])); nuclear@0: pScene->mRootNode->mNumMeshes = 1; nuclear@0: pScene->mRootNode->mMeshes = new unsigned int[1]; nuclear@0: pScene->mRootNode->mMeshes[0] = 0; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: pScene->mRootNode = new aiNode(); nuclear@0: pScene->mRootNode->mNumChildren = pScene->mNumMeshes; nuclear@0: pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes]; nuclear@0: pScene->mRootNode->mName.Set(""); nuclear@0: for (unsigned int i = 0; i < pScene->mNumMeshes;++i) nuclear@0: { nuclear@0: aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode(); nuclear@0: pcNode->mParent = pScene->mRootNode; nuclear@0: pcNode->mName.Set(std::string((const char*)pScene->mMeshes[i]->mTextureCoords[3])); nuclear@0: pcNode->mNumMeshes = 1; nuclear@0: pcNode->mMeshes = new unsigned int[1]; nuclear@0: pcNode->mMeshes[0] = i; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // make sure we invalidate the pointer to the mesh name nuclear@0: for (unsigned int i = 0; i < pScene->mNumMeshes;++i) nuclear@0: pScene->mMeshes[i]->mTextureCoords[3] = NULL; nuclear@0: nuclear@0: // create materials nuclear@0: pScene->mNumMaterials = (unsigned int)aszShaders.size(); nuclear@0: pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; nuclear@0: for (unsigned int i = 0; i < pScene->mNumMaterials;++i) nuclear@0: { nuclear@0: aiMaterial* pcMat = new aiMaterial(); nuclear@0: pScene->mMaterials[i] = pcMat; nuclear@0: nuclear@0: const std::string& name = aszShaders[i]; nuclear@0: nuclear@0: int iMode = (int)aiShadingMode_Gouraud; nuclear@0: pcMat->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); nuclear@0: nuclear@0: // add a small ambient color value - RtCW seems to have one nuclear@0: aiColor3D clr; nuclear@0: clr.b = clr.g = clr.r = 0.05f; nuclear@0: pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); nuclear@0: nuclear@0: if (name.length())clr.b = clr.g = clr.r = 1.0f; nuclear@0: else clr.b = clr.g = clr.r = 0.6f; nuclear@0: nuclear@0: pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); nuclear@0: pcMat->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); nuclear@0: nuclear@0: if (name.length()) nuclear@0: { nuclear@0: aiString path; nuclear@0: path.Set(name); nuclear@0: pcMat->AddProperty(&path,AI_MATKEY_TEXTURE_DIFFUSE(0)); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_MDC_IMPORTER