vrshoot
diff libs/assimp/MD2Loader.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/MD2Loader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,426 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +#include "AssimpPCH.h" 1.46 +#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER 1.47 + 1.48 +/** @file Implementation of the MD2 importer class */ 1.49 +#include "MD2Loader.h" 1.50 +#include "ByteSwap.h" 1.51 +#include "MD2NormalTable.h" // shouldn't be included by other units 1.52 + 1.53 +using namespace Assimp; 1.54 +using namespace Assimp::MD2; 1.55 + 1.56 + 1.57 +// helper macro to determine the size of an array 1.58 +#if (!defined ARRAYSIZE) 1.59 +# define ARRAYSIZE(_array) (int(sizeof(_array) / sizeof(_array[0]))) 1.60 +#endif 1.61 + 1.62 +static const aiImporterDesc desc = { 1.63 + "Quake II Mesh Importer", 1.64 + "", 1.65 + "", 1.66 + "", 1.67 + aiImporterFlags_SupportBinaryFlavour, 1.68 + 0, 1.69 + 0, 1.70 + 0, 1.71 + 0, 1.72 + "md2" 1.73 +}; 1.74 + 1.75 +// ------------------------------------------------------------------------------------------------ 1.76 +// Helper function to lookup a normal in Quake 2's precalculated table 1.77 +void MD2::LookupNormalIndex(uint8_t iNormalIndex,aiVector3D& vOut) 1.78 +{ 1.79 + // make sure the normal index has a valid value 1.80 + if (iNormalIndex >= ARRAYSIZE(g_avNormals)) { 1.81 + DefaultLogger::get()->warn("Index overflow in Quake II normal vector list"); 1.82 + iNormalIndex = ARRAYSIZE(g_avNormals) - 1; 1.83 + } 1.84 + vOut = *((const aiVector3D*)(&g_avNormals[iNormalIndex])); 1.85 +} 1.86 + 1.87 + 1.88 +// ------------------------------------------------------------------------------------------------ 1.89 +// Constructor to be privately used by Importer 1.90 +MD2Importer::MD2Importer() 1.91 +{} 1.92 + 1.93 +// ------------------------------------------------------------------------------------------------ 1.94 +// Destructor, private as well 1.95 +MD2Importer::~MD2Importer() 1.96 +{} 1.97 + 1.98 +// ------------------------------------------------------------------------------------------------ 1.99 +// Returns whether the class can handle the format of the given file. 1.100 +bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.101 +{ 1.102 + const std::string extension = GetExtension(pFile); 1.103 + if (extension == "md2") 1.104 + return true; 1.105 + 1.106 + // if check for extension is not enough, check for the magic tokens 1.107 + if (!extension.length() || checkSig) { 1.108 + uint32_t tokens[1]; 1.109 + tokens[0] = AI_MD2_MAGIC_NUMBER_LE; 1.110 + return CheckMagicToken(pIOHandler,pFile,tokens,1); 1.111 + } 1.112 + return false; 1.113 +} 1.114 + 1.115 +// ------------------------------------------------------------------------------------------------ 1.116 +// Get a list of all extensions supported by this loader 1.117 +const aiImporterDesc* MD2Importer::GetInfo () const 1.118 +{ 1.119 + return &desc; 1.120 +} 1.121 + 1.122 +// ------------------------------------------------------------------------------------------------ 1.123 +// Setup configuration properties 1.124 +void MD2Importer::SetupProperties(const Importer* pImp) 1.125 +{ 1.126 + // The 1.127 + // AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the 1.128 + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. 1.129 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD2_KEYFRAME,-1); 1.130 + if(static_cast<unsigned int>(-1) == configFrameID){ 1.131 + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); 1.132 + } 1.133 +} 1.134 +// ------------------------------------------------------------------------------------------------ 1.135 +// Validate the file header 1.136 +void MD2Importer::ValidateHeader( ) 1.137 +{ 1.138 + // check magic number 1.139 + if (m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_BE && 1.140 + m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_LE) 1.141 + { 1.142 + char szBuffer[5]; 1.143 + szBuffer[0] = ((char*)&m_pcHeader->magic)[0]; 1.144 + szBuffer[1] = ((char*)&m_pcHeader->magic)[1]; 1.145 + szBuffer[2] = ((char*)&m_pcHeader->magic)[2]; 1.146 + szBuffer[3] = ((char*)&m_pcHeader->magic)[3]; 1.147 + szBuffer[4] = '\0'; 1.148 + 1.149 + throw DeadlyImportError("Invalid MD2 magic word: should be IDP2, the " 1.150 + "magic word found is " + std::string(szBuffer)); 1.151 + } 1.152 + 1.153 + // check file format version 1.154 + if (m_pcHeader->version != 8) 1.155 + DefaultLogger::get()->warn( "Unsupported md2 file version. Continuing happily ..."); 1.156 + 1.157 + // check some values whether they are valid 1.158 + if (0 == m_pcHeader->numFrames) 1.159 + throw DeadlyImportError( "Invalid md2 file: NUM_FRAMES is 0"); 1.160 + 1.161 + if (m_pcHeader->offsetEnd > (uint32_t)fileSize) 1.162 + throw DeadlyImportError( "Invalid md2 file: File is too small"); 1.163 + 1.164 + if (m_pcHeader->offsetSkins + m_pcHeader->numSkins * sizeof (MD2::Skin) >= fileSize || 1.165 + m_pcHeader->offsetTexCoords + m_pcHeader->numTexCoords * sizeof (MD2::TexCoord) >= fileSize || 1.166 + m_pcHeader->offsetTriangles + m_pcHeader->numTriangles * sizeof (MD2::Triangle) >= fileSize || 1.167 + m_pcHeader->offsetFrames + m_pcHeader->numFrames * sizeof (MD2::Frame) >= fileSize || 1.168 + m_pcHeader->offsetEnd > fileSize) 1.169 + { 1.170 + throw DeadlyImportError("Invalid MD2 header: some offsets are outside the file"); 1.171 + } 1.172 + 1.173 + if (m_pcHeader->numSkins > AI_MD2_MAX_SKINS) 1.174 + DefaultLogger::get()->warn("The model contains more skins than Quake 2 supports"); 1.175 + if ( m_pcHeader->numFrames > AI_MD2_MAX_FRAMES) 1.176 + DefaultLogger::get()->warn("The model contains more frames than Quake 2 supports"); 1.177 + if (m_pcHeader->numVertices > AI_MD2_MAX_VERTS) 1.178 + DefaultLogger::get()->warn("The model contains more vertices than Quake 2 supports"); 1.179 + 1.180 + if (m_pcHeader->numFrames <= configFrameID ) 1.181 + throw DeadlyImportError("The requested frame is not existing the file"); 1.182 +} 1.183 + 1.184 +// ------------------------------------------------------------------------------------------------ 1.185 +// Imports the given file into the given scene structure. 1.186 +void MD2Importer::InternReadFile( const std::string& pFile, 1.187 + aiScene* pScene, IOSystem* pIOHandler) 1.188 +{ 1.189 + boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); 1.190 + 1.191 + // Check whether we can read from the file 1.192 + if( file.get() == NULL) 1.193 + throw DeadlyImportError( "Failed to open MD2 file " + pFile + ""); 1.194 + 1.195 + // check whether the md3 file is large enough to contain 1.196 + // at least the file header 1.197 + fileSize = (unsigned int)file->FileSize(); 1.198 + if( fileSize < sizeof(MD2::Header)) 1.199 + throw DeadlyImportError( "MD2 File is too small"); 1.200 + 1.201 + std::vector<uint8_t> mBuffer2(fileSize); 1.202 + file->Read(&mBuffer2[0], 1, fileSize); 1.203 + mBuffer = &mBuffer2[0]; 1.204 + 1.205 + 1.206 + m_pcHeader = (BE_NCONST MD2::Header*)mBuffer; 1.207 + 1.208 +#ifdef AI_BUILD_BIG_ENDIAN 1.209 + 1.210 + ByteSwap::Swap4(&m_pcHeader->frameSize); 1.211 + ByteSwap::Swap4(&m_pcHeader->magic); 1.212 + ByteSwap::Swap4(&m_pcHeader->numFrames); 1.213 + ByteSwap::Swap4(&m_pcHeader->numGlCommands); 1.214 + ByteSwap::Swap4(&m_pcHeader->numSkins); 1.215 + ByteSwap::Swap4(&m_pcHeader->numTexCoords); 1.216 + ByteSwap::Swap4(&m_pcHeader->numTriangles); 1.217 + ByteSwap::Swap4(&m_pcHeader->numVertices); 1.218 + ByteSwap::Swap4(&m_pcHeader->offsetEnd); 1.219 + ByteSwap::Swap4(&m_pcHeader->offsetFrames); 1.220 + ByteSwap::Swap4(&m_pcHeader->offsetGlCommands); 1.221 + ByteSwap::Swap4(&m_pcHeader->offsetSkins); 1.222 + ByteSwap::Swap4(&m_pcHeader->offsetTexCoords); 1.223 + ByteSwap::Swap4(&m_pcHeader->offsetTriangles); 1.224 + ByteSwap::Swap4(&m_pcHeader->skinHeight); 1.225 + ByteSwap::Swap4(&m_pcHeader->skinWidth); 1.226 + ByteSwap::Swap4(&m_pcHeader->version); 1.227 + 1.228 +#endif 1.229 + 1.230 + ValidateHeader(); 1.231 + 1.232 + // there won't be more than one mesh inside the file 1.233 + pScene->mNumMaterials = 1; 1.234 + pScene->mRootNode = new aiNode(); 1.235 + pScene->mRootNode->mNumMeshes = 1; 1.236 + pScene->mRootNode->mMeshes = new unsigned int[1]; 1.237 + pScene->mRootNode->mMeshes[0] = 0; 1.238 + pScene->mMaterials = new aiMaterial*[1]; 1.239 + pScene->mMaterials[0] = new aiMaterial(); 1.240 + pScene->mNumMeshes = 1; 1.241 + pScene->mMeshes = new aiMesh*[1]; 1.242 + 1.243 + aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh(); 1.244 + pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.245 + 1.246 + // navigate to the begin of the frame data 1.247 + BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*) 1.248 + m_pcHeader + m_pcHeader->offsetFrames); 1.249 + 1.250 + pcFrame += configFrameID; 1.251 + 1.252 + // navigate to the begin of the triangle data 1.253 + MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*) 1.254 + m_pcHeader + m_pcHeader->offsetTriangles); 1.255 + 1.256 + // navigate to the begin of the tex coords data 1.257 + BE_NCONST MD2::TexCoord* pcTexCoords = (BE_NCONST MD2::TexCoord*) ((uint8_t*) 1.258 + m_pcHeader + m_pcHeader->offsetTexCoords); 1.259 + 1.260 + // navigate to the begin of the vertex data 1.261 + BE_NCONST MD2::Vertex* pcVerts = (BE_NCONST MD2::Vertex*) (pcFrame->vertices); 1.262 + 1.263 +#ifdef AI_BUILD_BIG_ENDIAN 1.264 + for (uint32_t i = 0; i< m_pcHeader->numTriangles; ++i) 1.265 + { 1.266 + for (unsigned int p = 0; p < 3;++p) 1.267 + { 1.268 + ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]); 1.269 + ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]); 1.270 + } 1.271 + } 1.272 + for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i) 1.273 + { 1.274 + ByteSwap::Swap2(& pcTexCoords[i].s); 1.275 + ByteSwap::Swap2(& pcTexCoords[i].t); 1.276 + } 1.277 + ByteSwap::Swap4( & pcFrame->scale[0] ); 1.278 + ByteSwap::Swap4( & pcFrame->scale[1] ); 1.279 + ByteSwap::Swap4( & pcFrame->scale[2] ); 1.280 + ByteSwap::Swap4( & pcFrame->translate[0] ); 1.281 + ByteSwap::Swap4( & pcFrame->translate[1] ); 1.282 + ByteSwap::Swap4( & pcFrame->translate[2] ); 1.283 +#endif 1.284 + 1.285 + pcMesh->mNumFaces = m_pcHeader->numTriangles; 1.286 + pcMesh->mFaces = new aiFace[m_pcHeader->numTriangles]; 1.287 + 1.288 + // allocate output storage 1.289 + pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3; 1.290 + pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices]; 1.291 + pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices]; 1.292 + 1.293 + // Not sure whether there are MD2 files without texture coordinates 1.294 + // NOTE: texture coordinates can be there without a texture, 1.295 + // but a texture can't be there without a valid UV channel 1.296 + aiMaterial* pcHelper = (aiMaterial*)pScene->mMaterials[0]; 1.297 + const int iMode = (int)aiShadingMode_Gouraud; 1.298 + pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL); 1.299 + 1.300 + if (m_pcHeader->numTexCoords && m_pcHeader->numSkins) 1.301 + { 1.302 + // navigate to the first texture associated with the mesh 1.303 + const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)m_pcHeader + 1.304 + m_pcHeader->offsetSkins); 1.305 + 1.306 + aiColor3D clr; 1.307 + clr.b = clr.g = clr.r = 1.0f; 1.308 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); 1.309 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR); 1.310 + 1.311 + clr.b = clr.g = clr.r = 0.05f; 1.312 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT); 1.313 + 1.314 + if (pcSkins->name[0]) 1.315 + { 1.316 + aiString szString; 1.317 + const size_t iLen = ::strlen(pcSkins->name); 1.318 + ::memcpy(szString.data,pcSkins->name,iLen); 1.319 + szString.data[iLen] = '\0'; 1.320 + szString.length = iLen; 1.321 + 1.322 + pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.323 + } 1.324 + else{ 1.325 + DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped."); 1.326 + } 1.327 + } 1.328 + else { 1.329 + // apply a default material 1.330 + aiColor3D clr; 1.331 + clr.b = clr.g = clr.r = 0.6f; 1.332 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); 1.333 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR); 1.334 + 1.335 + clr.b = clr.g = clr.r = 0.05f; 1.336 + pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT); 1.337 + 1.338 + aiString szName; 1.339 + szName.Set(AI_DEFAULT_MATERIAL_NAME); 1.340 + pcHelper->AddProperty(&szName,AI_MATKEY_NAME); 1.341 + 1.342 + aiString sz; 1.343 + 1.344 + // TODO: Try to guess the name of the texture file from the model file name 1.345 + 1.346 + sz.Set("$texture_dummy.bmp"); 1.347 + pcHelper->AddProperty(&sz,AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.348 + } 1.349 + 1.350 + 1.351 + // now read all triangles of the first frame, apply scaling and translation 1.352 + unsigned int iCurrent = 0; 1.353 + 1.354 + float fDivisorU = 1.0f,fDivisorV = 1.0f; 1.355 + if (m_pcHeader->numTexCoords) { 1.356 + // allocate storage for texture coordinates, too 1.357 + pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; 1.358 + pcMesh->mNumUVComponents[0] = 2; 1.359 + 1.360 + // check whether the skin width or height are zero (this would 1.361 + // cause a division through zero) 1.362 + if (!m_pcHeader->skinWidth) { 1.363 + DefaultLogger::get()->error("MD2: No valid skin width given"); 1.364 + } 1.365 + else fDivisorU = (float)m_pcHeader->skinWidth; 1.366 + if (!m_pcHeader->skinHeight){ 1.367 + DefaultLogger::get()->error("MD2: No valid skin height given"); 1.368 + } 1.369 + else fDivisorV = (float)m_pcHeader->skinHeight; 1.370 + } 1.371 + 1.372 + for (unsigned int i = 0; i < (unsigned int)m_pcHeader->numTriangles;++i) { 1.373 + // Allocate the face 1.374 + pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3]; 1.375 + pScene->mMeshes[0]->mFaces[i].mNumIndices = 3; 1.376 + 1.377 + // copy texture coordinates 1.378 + // check whether they are different from the previous value at this index. 1.379 + // In this case, create a full separate set of vertices/normals/texcoords 1.380 + for (unsigned int c = 0; c < 3;++c,++iCurrent) { 1.381 + 1.382 + // validate vertex indices 1.383 + register unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c]; 1.384 + if (iIndex >= m_pcHeader->numVertices) { 1.385 + DefaultLogger::get()->error("MD2: Vertex index is outside the allowed range"); 1.386 + iIndex = m_pcHeader->numVertices-1; 1.387 + } 1.388 + 1.389 + // read x,y, and z component of the vertex 1.390 + aiVector3D& vec = pcMesh->mVertices[iCurrent]; 1.391 + 1.392 + vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0]; 1.393 + vec.x += pcFrame->translate[0]; 1.394 + 1.395 + vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1]; 1.396 + vec.y += pcFrame->translate[1]; 1.397 + 1.398 + vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2]; 1.399 + vec.z += pcFrame->translate[2]; 1.400 + 1.401 + // read the normal vector from the precalculated normal table 1.402 + aiVector3D& vNormal = pcMesh->mNormals[iCurrent]; 1.403 + LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal); 1.404 + 1.405 + // flip z and y to become right-handed 1.406 + std::swap((float&)vNormal.z,(float&)vNormal.y); 1.407 + std::swap((float&)vec.z,(float&)vec.y); 1.408 + 1.409 + if (m_pcHeader->numTexCoords) { 1.410 + // validate texture coordinates 1.411 + iIndex = pcTriangles[i].textureIndices[c]; 1.412 + if (iIndex >= m_pcHeader->numTexCoords) { 1.413 + DefaultLogger::get()->error("MD2: UV index is outside the allowed range"); 1.414 + iIndex = m_pcHeader->numTexCoords-1; 1.415 + } 1.416 + 1.417 + aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent]; 1.418 + 1.419 + // the texture coordinates are absolute values but we 1.420 + // need relative values between 0 and 1 1.421 + pcOut.x = pcTexCoords[iIndex].s / fDivisorU; 1.422 + pcOut.y = 1.f-pcTexCoords[iIndex].t / fDivisorV; 1.423 + } 1.424 + pScene->mMeshes[0]->mFaces[i].mIndices[c] = iCurrent; 1.425 + } 1.426 + } 1.427 +} 1.428 + 1.429 +#endif // !! ASSIMP_BUILD_NO_MD2_IMPORTER