1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2016, assimp team
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13 
14 * Redistributions of source code must retain the above
15   copyright notice, this list of conditions and the
16   following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19   copyright notice, this list of conditions and the
20   following disclaimer in the documentation and/or other
21   materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24   contributors may be used to endorse or promote products
25   derived from this software without specific prior
26   written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 
42 /** @file  MakeLeftHandedProcess.cpp
43  *  @brief Implementation of the post processing step to convert all
44  *  imported data to a left-handed coordinate system.
45  *
46  *  Face order & UV flip are also implemented here, for the sake of a
47  *  better location.
48  */
49 
50 
51 #include "ConvertToLHProcess.h"
52 #include <assimp/scene.h>
53 #include <assimp/postprocess.h>
54 #include <assimp/DefaultLogger.hpp>
55 
56 using namespace Assimp;
57 
58 #ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
59 
60 // ------------------------------------------------------------------------------------------------
61 // Constructor to be privately used by Importer
MakeLeftHandedProcess()62 MakeLeftHandedProcess::MakeLeftHandedProcess()
63 : BaseProcess() {
64     // empty
65 }
66 
67 // ------------------------------------------------------------------------------------------------
68 // Destructor, private as well
~MakeLeftHandedProcess()69 MakeLeftHandedProcess::~MakeLeftHandedProcess() {
70     // empty
71 }
72 
73 // ------------------------------------------------------------------------------------------------
74 // Returns whether the processing step is present in the given flag field.
IsActive(unsigned int pFlags) const75 bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
76 {
77     return 0 != (pFlags & aiProcess_MakeLeftHanded);
78 }
79 
80 // ------------------------------------------------------------------------------------------------
81 // Executes the post processing step on the given imported data.
Execute(aiScene * pScene)82 void MakeLeftHandedProcess::Execute( aiScene* pScene)
83 {
84     // Check for an existent root node to proceed
85     ai_assert(pScene->mRootNode != NULL);
86     DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
87 
88     // recursively convert all the nodes
89     ProcessNode( pScene->mRootNode, aiMatrix4x4());
90 
91     // process the meshes accordingly
92     for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
93         ProcessMesh( pScene->mMeshes[a]);
94 
95     // process the materials accordingly
96     for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
97         ProcessMaterial( pScene->mMaterials[a]);
98 
99     // transform all animation channels as well
100     for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
101     {
102         aiAnimation* anim = pScene->mAnimations[a];
103         for( unsigned int b = 0; b < anim->mNumChannels; b++)
104         {
105             aiNodeAnim* nodeAnim = anim->mChannels[b];
106             ProcessAnimation( nodeAnim);
107         }
108     }
109     DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
110 }
111 
112 // ------------------------------------------------------------------------------------------------
113 // Recursively converts a node, all of its children and all of its meshes
ProcessNode(aiNode * pNode,const aiMatrix4x4 & pParentGlobalRotation)114 void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
115 {
116     // mirror all base vectors at the local Z axis
117     pNode->mTransformation.c1 = -pNode->mTransformation.c1;
118     pNode->mTransformation.c2 = -pNode->mTransformation.c2;
119     pNode->mTransformation.c3 = -pNode->mTransformation.c3;
120     pNode->mTransformation.c4 = -pNode->mTransformation.c4;
121 
122     // now invert the Z axis again to keep the matrix determinant positive.
123     // The local meshes will be inverted accordingly so that the result should look just fine again.
124     pNode->mTransformation.a3 = -pNode->mTransformation.a3;
125     pNode->mTransformation.b3 = -pNode->mTransformation.b3;
126     pNode->mTransformation.c3 = -pNode->mTransformation.c3;
127     pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
128 
129     // continue for all children
130     for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
131         ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
132     }
133 }
134 
135 // ------------------------------------------------------------------------------------------------
136 // Converts a single mesh to left handed coordinates.
ProcessMesh(aiMesh * pMesh)137 void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
138 {
139     // mirror positions, normals and stuff along the Z axis
140     for( size_t a = 0; a < pMesh->mNumVertices; ++a)
141     {
142         pMesh->mVertices[a].z *= -1.0f;
143         if( pMesh->HasNormals())
144             pMesh->mNormals[a].z *= -1.0f;
145         if( pMesh->HasTangentsAndBitangents())
146         {
147             pMesh->mTangents[a].z *= -1.0f;
148             pMesh->mBitangents[a].z *= -1.0f;
149         }
150     }
151 
152     // mirror offset matrices of all bones
153     for( size_t a = 0; a < pMesh->mNumBones; ++a)
154     {
155         aiBone* bone = pMesh->mBones[a];
156         bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
157         bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
158         bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
159         bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
160         bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
161         bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
162     }
163 
164     // mirror bitangents as well as they're derived from the texture coords
165     if( pMesh->HasTangentsAndBitangents())
166     {
167         for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
168             pMesh->mBitangents[a] *= -1.0f;
169     }
170 }
171 
172 // ------------------------------------------------------------------------------------------------
173 // Converts a single material to left handed coordinates.
ProcessMaterial(aiMaterial * _mat)174 void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
175 {
176     aiMaterial* mat = (aiMaterial*)_mat;
177     for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
178         aiMaterialProperty* prop = mat->mProperties[a];
179 
180         // Mapping axis for UV mappings?
181         if (!::strcmp( prop->mKey.data, "$tex.mapaxis"))    {
182             ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
183             aiVector3D* pff = (aiVector3D*)prop->mData;
184 
185             pff->z *= -1.f;
186         }
187     }
188 }
189 
190 // ------------------------------------------------------------------------------------------------
191 // Converts the given animation to LH coordinates.
ProcessAnimation(aiNodeAnim * pAnim)192 void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
193 {
194     // position keys
195     for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
196         pAnim->mPositionKeys[a].mValue.z *= -1.0f;
197 
198     // rotation keys
199     for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
200     {
201         /* That's the safe version, but the float errors add up. So we try the short version instead
202         aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
203         rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
204         rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
205         aiQuaternion rotquat( rotmat);
206         pAnim->mRotationKeys[a].mValue = rotquat;
207         */
208         pAnim->mRotationKeys[a].mValue.x *= -1.0f;
209         pAnim->mRotationKeys[a].mValue.y *= -1.0f;
210     }
211 }
212 
213 #endif // !!  ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
214 #ifndef  ASSIMP_BUILD_NO_FLIPUVS_PROCESS
215 // # FlipUVsProcess
216 
217 // ------------------------------------------------------------------------------------------------
218 // Constructor to be privately used by Importer
FlipUVsProcess()219 FlipUVsProcess::FlipUVsProcess()
220 {}
221 
222 // ------------------------------------------------------------------------------------------------
223 // Destructor, private as well
~FlipUVsProcess()224 FlipUVsProcess::~FlipUVsProcess()
225 {}
226 
227 // ------------------------------------------------------------------------------------------------
228 // Returns whether the processing step is present in the given flag field.
IsActive(unsigned int pFlags) const229 bool FlipUVsProcess::IsActive( unsigned int pFlags) const
230 {
231     return 0 != (pFlags & aiProcess_FlipUVs);
232 }
233 
234 // ------------------------------------------------------------------------------------------------
235 // Executes the post processing step on the given imported data.
Execute(aiScene * pScene)236 void FlipUVsProcess::Execute( aiScene* pScene)
237 {
238     DefaultLogger::get()->debug("FlipUVsProcess begin");
239     for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
240         ProcessMesh(pScene->mMeshes[i]);
241 
242     for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
243         ProcessMaterial(pScene->mMaterials[i]);
244     DefaultLogger::get()->debug("FlipUVsProcess finished");
245 }
246 
247 // ------------------------------------------------------------------------------------------------
248 // Converts a single material
ProcessMaterial(aiMaterial * _mat)249 void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
250 {
251     aiMaterial* mat = (aiMaterial*)_mat;
252     for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
253         aiMaterialProperty* prop = mat->mProperties[a];
254         if( !prop ) {
255             DefaultLogger::get()->debug( "Property is null" );
256             continue;
257         }
258 
259         // UV transformation key?
260         if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))    {
261             ai_assert( prop->mDataLength >= sizeof(aiUVTransform));  /* something is wrong with the validation if we end up here */
262             aiUVTransform* uv = (aiUVTransform*)prop->mData;
263 
264             // just flip it, that's everything
265             uv->mTranslation.y *= -1.f;
266             uv->mRotation *= -1.f;
267         }
268     }
269 }
270 
271 // ------------------------------------------------------------------------------------------------
272 // Converts a single mesh
ProcessMesh(aiMesh * pMesh)273 void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
274 {
275     // mirror texture y coordinate
276     for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)   {
277         if( !pMesh->HasTextureCoords( a ) ) {
278             break;
279         }
280 
281         for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
282             pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
283         }
284     }
285 }
286 
287 #endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
288 #ifndef  ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
289 // # FlipWindingOrderProcess
290 
291 // ------------------------------------------------------------------------------------------------
292 // Constructor to be privately used by Importer
FlipWindingOrderProcess()293 FlipWindingOrderProcess::FlipWindingOrderProcess()
294 {}
295 
296 // ------------------------------------------------------------------------------------------------
297 // Destructor, private as well
~FlipWindingOrderProcess()298 FlipWindingOrderProcess::~FlipWindingOrderProcess()
299 {}
300 
301 // ------------------------------------------------------------------------------------------------
302 // Returns whether the processing step is present in the given flag field.
IsActive(unsigned int pFlags) const303 bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
304 {
305     return 0 != (pFlags & aiProcess_FlipWindingOrder);
306 }
307 
308 // ------------------------------------------------------------------------------------------------
309 // Executes the post processing step on the given imported data.
Execute(aiScene * pScene)310 void FlipWindingOrderProcess::Execute( aiScene* pScene)
311 {
312     DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
313     for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
314         ProcessMesh(pScene->mMeshes[i]);
315     DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
316 }
317 
318 // ------------------------------------------------------------------------------------------------
319 // Converts a single mesh
ProcessMesh(aiMesh * pMesh)320 void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
321 {
322     // invert the order of all faces in this mesh
323     for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
324     {
325         aiFace& face = pMesh->mFaces[a];
326         for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
327             std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
328     }
329 }
330 
331 #endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
332