1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2019, assimp team
6 
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
12 following 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 #include "ScaleProcess.h"
43 
44 #include <assimp/scene.h>
45 #include <assimp/postprocess.h>
46 #include <assimp/BaseImporter.h>
47 
48 namespace Assimp {
49 
ScaleProcess()50 ScaleProcess::ScaleProcess()
51 : BaseProcess()
52 , mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
53 }
54 
~ScaleProcess()55 ScaleProcess::~ScaleProcess() {
56     // empty
57 }
58 
setScale(ai_real scale)59 void ScaleProcess::setScale( ai_real scale ) {
60     mScale = scale;
61 }
62 
getScale() const63 ai_real ScaleProcess::getScale() const {
64     return mScale;
65 }
66 
IsActive(unsigned int pFlags) const67 bool ScaleProcess::IsActive( unsigned int pFlags ) const {
68     return ( pFlags & aiProcess_GlobalScale ) != 0;
69 }
70 
SetupProperties(const Importer * pImp)71 void ScaleProcess::SetupProperties( const Importer* pImp ) {
72     // User scaling
73     mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f );
74 
75     // File scaling * Application Scaling
76     float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f );
77 
78     // apply scale to the scale
79     // helps prevent bugs with backward compatibility for anyone using normal scaling.
80     mScale *= importerScale;
81 }
82 
Execute(aiScene * pScene)83 void ScaleProcess::Execute( aiScene* pScene ) {
84     if(mScale == 1.0f)  {
85         return; // nothing to scale
86     }
87 
88     ai_assert( mScale != 0 );
89     ai_assert( nullptr != pScene );
90     ai_assert( nullptr != pScene->mRootNode );
91 
92     if ( nullptr == pScene ) {
93         return;
94     }
95 
96     if ( nullptr == pScene->mRootNode ) {
97         return;
98     }
99 
100     // Process animations and update position transform to new unit system
101     for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ )
102     {
103         aiAnimation* animation = pScene->mAnimations[animationID];
104 
105         for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++)
106         {
107             aiNodeAnim* anim = animation->mChannels[animationChannel];
108 
109             for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++)
110             {
111                 aiVectorKey& vectorKey = anim->mPositionKeys[posKey];
112                 vectorKey.mValue *= mScale;
113             }
114         }
115     }
116 
117     for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++)
118     {
119         aiMesh *mesh = pScene->mMeshes[meshID];
120 
121         // Reconstruct mesh vertexes to the new unit system
122         for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++)
123         {
124             aiVector3D& vertex = mesh->mVertices[vertexID];
125             vertex *= mScale;
126         }
127 
128 
129         // bone placement / scaling
130         for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++)
131         {
132             // Reconstruct matrix by transform rather than by scale
133             // This prevent scale values being changed which can
134             // be meaningful in some cases
135             // like when you want the modeller to see 1:1 compatibility.
136             aiBone* bone = mesh->mBones[boneID];
137 
138             aiVector3D pos, scale;
139             aiQuaternion rotation;
140 
141             bone->mOffsetMatrix.Decompose( scale, rotation, pos);
142 
143             aiMatrix4x4 translation;
144             aiMatrix4x4::Translation( pos * mScale, translation );
145 
146             aiMatrix4x4 scaling;
147             aiMatrix4x4::Scaling( aiVector3D(scale), scaling );
148 
149             aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix());
150 
151             bone->mOffsetMatrix = translation * RotMatrix * scaling;
152         }
153 
154 
155         // animation mesh processing
156         // convert by position rather than scale.
157         for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++)
158         {
159             aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID];
160 
161             for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++)
162             {
163                 aiVector3D& vertex = animMesh->mVertices[vertexID];
164                 vertex *= mScale;
165             }
166         }
167     }
168 
169     traverseNodes( pScene->mRootNode );
170 }
171 
traverseNodes(aiNode * node,unsigned int nested_node_id)172 void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
173     applyScaling( node );
174 
175     for( size_t i = 0; i < node->mNumChildren; i++)
176     {
177         // recurse into the tree until we are done!
178         traverseNodes( node->mChildren[i], nested_node_id+1 );
179     }
180 }
181 
applyScaling(aiNode * currentNode)182 void ScaleProcess::applyScaling( aiNode *currentNode ) {
183     if ( nullptr != currentNode ) {
184         // Reconstruct matrix by transform rather than by scale
185         // This prevent scale values being changed which can
186         // be meaningful in some cases
187         // like when you want the modeller to
188         // see 1:1 compatibility.
189 
190         aiVector3D pos, scale;
191         aiQuaternion rotation;
192         currentNode->mTransformation.Decompose( scale, rotation, pos);
193 
194         aiMatrix4x4 translation;
195         aiMatrix4x4::Translation( pos * mScale, translation );
196 
197         aiMatrix4x4 scaling;
198 
199         // note: we do not use mScale here, this is on purpose.
200         aiMatrix4x4::Scaling( scale, scaling );
201 
202         aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix());
203 
204         currentNode->mTransformation = translation * RotMatrix * scaling;
205     }
206 }
207 
208 } // Namespace Assimp
209