diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index ae3614dd9..f8fe533d3 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -310,8 +310,7 @@ void MD2Importer::InternReadFile( const std::string& pFile, DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped."); } } - else - { + else { // apply a default material aiColor3D clr; clr.b = clr.g = clr.r = 0.6f; @@ -338,8 +337,7 @@ void MD2Importer::InternReadFile( const std::string& pFile, unsigned int iCurrent = 0; float fDivisorU = 1.0f,fDivisorV = 1.0f; - if (m_pcHeader->numTexCoords) - { + if (m_pcHeader->numTexCoords) { // allocate storage for texture coordinates, too pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices]; pcMesh->mNumUVComponents[0] = 2; @@ -356,8 +354,7 @@ void MD2Importer::InternReadFile( const std::string& pFile, else fDivisorV = (float)m_pcHeader->skinHeight; } - for (unsigned int i = 0; i < (unsigned int)m_pcHeader->numTriangles;++i) - { + for (unsigned int i = 0; i < (unsigned int)m_pcHeader->numTriangles;++i) { // Allocate the face pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3]; pScene->mMeshes[0]->mFaces[i].mNumIndices = 3; @@ -365,12 +362,11 @@ void MD2Importer::InternReadFile( const std::string& pFile, // copy texture coordinates // check whether they are different from the previous value at this index. // In this case, create a full separate set of vertices/normals/texcoords - for (unsigned int c = 0; c < 3;++c,++iCurrent) - { + for (unsigned int c = 0; c < 3;++c,++iCurrent) { + // validate vertex indices register unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c]; - if (iIndex >= m_pcHeader->numVertices) - { + if (iIndex >= m_pcHeader->numVertices) { DefaultLogger::get()->error("MD2: Vertex index is outside the allowed range"); iIndex = m_pcHeader->numVertices-1; } @@ -391,9 +387,9 @@ void MD2Importer::InternReadFile( const std::string& pFile, aiVector3D& vNormal = pcMesh->mNormals[iCurrent]; LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal); - // invert z for proper output coordinate system - vNormal.z *= -1.0f; - vec.z *= -1.0f; + // flip z and y to become right-handed + std::swap((float&)vNormal.z,(float&)vNormal.y); + std::swap((float&)vec.z,(float&)vec.y); if (m_pcHeader->numTexCoords) { // validate texture coordinates diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index 26907185a..8ae3354a6 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -531,7 +531,7 @@ bool MD3Importer::ReadMultipartFile() aiNode* tag_torso, *tag_head; std::vector attach; - DefaultLogger::get()->info("Multi-part MD3 player model: lower, upper and head parts are joined"); + DefaultLogger::get()->info("Multi part MD3 player model: lower, upper and head parts are joined"); // ensure we won't try to load ourselves recursively BatchLoader::PropertyMap props; @@ -552,21 +552,21 @@ bool MD3Importer::ReadMultipartFile() // ... and get them. We need all of them. scene_lower = batch.GetImport(_lower); if (!scene_lower) { - DefaultLogger::get()->error("M3D: Failed to read multipart model, lower.md3 fails to load"); + DefaultLogger::get()->error("M3D: Failed to read multi part model, lower.md3 fails to load"); failure = "lower"; goto error_cleanup; } scene_upper = batch.GetImport(_upper); if (!scene_upper) { - DefaultLogger::get()->error("M3D: Failed to read multipart model, upper.md3 fails to load"); + DefaultLogger::get()->error("M3D: Failed to read multi part model, upper.md3 fails to load"); failure = "upper"; goto error_cleanup; } scene_head = batch.GetImport(_head); if (!scene_head) { - DefaultLogger::get()->error("M3D: Failed to read multipart model, head.md3 fails to load"); + DefaultLogger::get()->error("M3D: Failed to read multi part model, head.md3 fails to load"); failure = "head"; goto error_cleanup; } @@ -580,7 +580,7 @@ bool MD3Importer::ReadMultipartFile() // tag_torso tag_torso = scene_lower->mRootNode->FindNode("tag_torso"); if (!tag_torso) { - DefaultLogger::get()->error("M3D: Failed to find attachment tag for multipart model: tag_torso expected"); + DefaultLogger::get()->error("M3D: Failed to find attachment tag for multi part model: tag_torso expected"); goto error_cleanup; } scene_upper->mRootNode->mName.Set("upper"); @@ -589,7 +589,7 @@ bool MD3Importer::ReadMultipartFile() // tag_head tag_head = scene_upper->mRootNode->FindNode("tag_head"); if (!tag_head) { - DefaultLogger::get()->error("M3D: Failed to find attachment tag for multipart model: tag_head expected"); + DefaultLogger::get()->error("M3D: Failed to find attachment tag for multi part model: tag_head expected"); goto error_cleanup; } scene_head->mRootNode->mName.Set("head"); @@ -601,6 +601,12 @@ bool MD3Importer::ReadMultipartFile() RemoveSingleNodeFromList (scene_upper->mRootNode->FindNode("tag_torso")); RemoveSingleNodeFromList (scene_head-> mRootNode->FindNode("tag_head" )); + // Undo the rotations which we applied to the coordinate systems. We're + // working in global Quake space here + scene_head->mRootNode->mTransformation = aiMatrix4x4(); + scene_lower->mRootNode->mTransformation = aiMatrix4x4(); + scene_upper->mRootNode->mTransformation = aiMatrix4x4(); + // and merge the scenes SceneCombiner::MergeScenes(&mScene,master, attach, AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | @@ -608,6 +614,10 @@ bool MD3Importer::ReadMultipartFile() AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS | (!configSpeedFlag ? AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY : 0)); + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + mScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); + return true; error_cleanup: @@ -673,10 +683,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, // get base path and file name // todo ... move to PathConverter - std::string::size_type s = mFile.find_last_of('/'); - if (s == std::string::npos) { - s = mFile.find_last_of('\\'); - } + std::string::size_type s = mFile.find_last_of("/\\"); if (s == std::string::npos) { s = 0; } @@ -907,8 +914,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, // Ensure correct endianess #ifdef AI_BUILD_BIG_ENDIAN - for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i) - { + for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i) { AI_SWAP2( pcVertices[i].NORMAL ); AI_SWAP2( pcVertices[i].X ); AI_SWAP2( pcVertices[i].Y ); @@ -917,8 +923,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, AI_SWAP4( pcUVs[i].U ); AI_SWAP4( pcUVs[i].U ); } - for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) - { + for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) { AI_SWAP4(pcTriangles[i].INDEXES[0]); AI_SWAP4(pcTriangles[i].INDEXES[1]); AI_SWAP4(pcTriangles[i].INDEXES[2]); @@ -939,34 +944,31 @@ void MD3Importer::InternReadFile( const std::string& pFile, // Fill in all triangles unsigned int iCurrent = 0; - for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i) - { + for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i) { pcMesh->mFaces[i].mIndices = new unsigned int[3]; pcMesh->mFaces[i].mNumIndices = 3; unsigned int iTemp = iCurrent; - for (unsigned int c = 0; c < 3;++c,++iCurrent) - { + for (unsigned int c = 0; c < 3;++c,++iCurrent) { pcMesh->mFaces[i].mIndices[c] = iCurrent; // Read vertices - pcMesh->mVertices[iCurrent].x = pcVertices[ pcTriangles->INDEXES[c]].X*AI_MD3_XYZ_SCALE; - pcMesh->mVertices[iCurrent].y = pcVertices[ pcTriangles->INDEXES[c]].Y*AI_MD3_XYZ_SCALE; - pcMesh->mVertices[iCurrent].z = pcVertices[ pcTriangles->INDEXES[c]].Z*AI_MD3_XYZ_SCALE; + aiVector3D& vec = pcMesh->mVertices[iCurrent]; + vec.x = pcVertices[ pcTriangles->INDEXES[c]].X*AI_MD3_XYZ_SCALE; + vec.y = pcVertices[ pcTriangles->INDEXES[c]].Y*AI_MD3_XYZ_SCALE; + vec.z = pcVertices[ pcTriangles->INDEXES[c]].Z*AI_MD3_XYZ_SCALE; // Convert the normal vector to uncompressed float3 format - LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL, - (float*)&pcMesh->mNormals[iCurrent]); + aiVector3D& nor = pcMesh->mNormals[iCurrent]; + LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,(float*)&nor); // Read texture coordinates pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U; pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V; } // Flip face order if necessary - if (!shader || shader->cull == Q3Shader::CULL_CCW) { - pcMesh->mFaces[i].mIndices[0] = iTemp+2; - pcMesh->mFaces[i].mIndices[1] = iTemp+1; - pcMesh->mFaces[i].mIndices[2] = iTemp+0; + if (!shader || shader->cull == Q3Shader::CULL_CW) { + std::swap(pcMesh->mFaces[i].mIndices[2],pcMesh->mFaces[i].mIndices[1]); } pcTriangles++; } @@ -1008,7 +1010,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, AI_SWAP4(pcTags->origin.y); AI_SWAP4(pcTags->origin.z); - // Copy local origin + // Copy local origin, again flip z,y nd->mTransformation.a4 = pcTags->origin.x; nd->mTransformation.b4 = pcTags->origin.y; nd->mTransformation.c4 = pcTags->origin.z; @@ -1025,6 +1027,10 @@ void MD3Importer::InternReadFile( const std::string& pFile, for (unsigned int i = 0; i < pScene->mNumMeshes;++i) pScene->mRootNode->mMeshes[i] = i; + + // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system + pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); } #endif // !! ASSIMP_BUILD_NO_MD3_IMPORTER diff --git a/code/MD3Loader.h b/code/MD3Loader.h index 509b358d8..0a5b80ccc 100644 --- a/code/MD3Loader.h +++ b/code/MD3Loader.h @@ -145,7 +145,7 @@ struct ShaderMapBlock struct ShaderDataBlock { ShaderDataBlock() - : cull (CULL_CCW) + : cull (CULL_CW) {} //! Name of referenced data element diff --git a/doc/dox.h b/doc/dox.h index ab9edf4c1..8219a5b7b 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -551,12 +551,12 @@ By contrast, some other environments use left-handed coordinate systems, a promi DirectX. If you need the imported data to be in a left-handed coordinate system, supply the #aiProcess_MakeLeftHanded flag to the ReadFile() function call. -The output face winding is counter-clockwise. Use #aiProcess_FlipWindingOrder to get CW data. +The output face winding is clockwise. Use #aiProcess_FlipWindingOrder to get CCW data. @code x0 - x2 - x1 + x1 + x2 @endcode The output UV coordinate system has its origin in the lower-left corner: diff --git a/include/aiMesh.h b/include/aiMesh.h index 33558e821..a8dd13862 100644 --- a/include/aiMesh.h +++ b/include/aiMesh.h @@ -63,12 +63,14 @@ extern "C" { * a special post-processing step which splits meshes with *different* * primitive types mixed up (e.g. lines and triangles) in several, 'clean' * submeshes. Furthermore there is a configuration option, - * AI_CONFIG_PP_SBP_REMOVE, to force SortByPType to remove specific primitive - * types from the scene - completely. In most cases you'll propably want to - * set this config to + * #AI_CONFIG_PP_SBP_REMOVE, to force #aiProcess_SortByPType to remove + * specific primitive types from the imported scene - completely. In most cases + * you'll probably want to set this setting to * @code * aiPrimitiveType_LINE|aiPrimitiveType_POINT * @endcode + * @note Take a look at the @link data Data Structures page @endlink for + * more information on the layout and winding order of a face. */ struct aiFace { diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index 1756c99a4..eb1a39176 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -436,14 +436,14 @@ enum aiPostProcessSteps aiProcess_FlipUVs = 0x80000000, /* don't change */ // ------------------------------------------------------------------------- - /**
This step adjusts the output face winding order to be clock-wise. + /**
This step adjusts the output face winding order to be ccw. * - * The default face winding order is counter-clockwise. + * The default face winding order is clockwise. *
Output face order: * @code - * x0 + * x1 * - * x1 + * x0 * x2 * @endcode */ @@ -461,10 +461,9 @@ enum aiPostProcessSteps /** @def aiProcess_ConvertToLeftHanded * @brief Shortcut flag for Direct3D-based applications. * - * Supersedes the #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and - * #aiProcess_FlipWindingOrder flags. The output data matches Direct3D's conventions: - * left-handed geometry, upper-left origin for UV coordinates and finally clockwise - * face order, suitable for CCW culling. + * Supersedes the #aiProcess_MakeLeftHanded and #aiProcess_FlipUVs and + * The output data matches Direct3D's conventions: left-handed geometry, upper-left + * origin for UV coordinates and finally clockwise face order, suitable for CCW culling. * * @deprecated */