vrshoot
view libs/assimp/FindInstancesProcess.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
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:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file FindInstancesProcess.cpp
43 * @brief Implementation of the aiProcess_FindInstances postprocessing step
44 */
46 #include "AssimpPCH.h"
47 #include "FindInstancesProcess.h"
49 using namespace Assimp;
51 // ------------------------------------------------------------------------------------------------
52 // Constructor to be privately used by Importer
53 FindInstancesProcess::FindInstancesProcess()
54 : configSpeedFlag (false)
55 {}
57 // ------------------------------------------------------------------------------------------------
58 // Destructor, private as well
59 FindInstancesProcess::~FindInstancesProcess()
60 {}
62 // ------------------------------------------------------------------------------------------------
63 // Returns whether the processing step is present in the given flag field.
64 bool FindInstancesProcess::IsActive( unsigned int pFlags) const
65 {
66 // FindInstances makes absolutely no sense together with PreTransformVertices
67 // fixme: spawn error message somewhere else?
68 return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices);
69 }
71 // ------------------------------------------------------------------------------------------------
72 // Setup properties for the step
73 void FindInstancesProcess::SetupProperties(const Importer* pImp)
74 {
75 // AI_CONFIG_FAVOUR_SPEED
76 configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0));
77 }
79 // ------------------------------------------------------------------------------------------------
80 // Compare the bones of two meshes
81 bool CompareBones(const aiMesh* orig, const aiMesh* inst)
82 {
83 for (unsigned int i = 0; i < orig->mNumBones;++i) {
84 aiBone* aha = orig->mBones[i];
85 aiBone* oha = inst->mBones[i];
87 if (aha->mNumWeights != oha->mNumWeights ||
88 aha->mOffsetMatrix != oha->mOffsetMatrix ||
89 aha->mNumWeights != oha->mNumWeights) {
90 return false;
91 }
93 // compare weight per weight ---
94 for (unsigned int n = 0; n < aha->mNumWeights;++n) {
95 if (aha->mWeights[n].mVertexId != oha->mWeights[n].mVertexId ||
96 (aha->mWeights[n].mWeight - oha->mWeights[n].mWeight) < 10e-3f) {
97 return false;
98 }
99 }
100 }
101 return true;
102 }
104 // ------------------------------------------------------------------------------------------------
105 // Update mesh indices in the node graph
106 void UpdateMeshIndices(aiNode* node, unsigned int* lookup)
107 {
108 for (unsigned int n = 0; n < node->mNumMeshes;++n)
109 node->mMeshes[n] = lookup[node->mMeshes[n]];
111 for (unsigned int n = 0; n < node->mNumChildren;++n)
112 UpdateMeshIndices(node->mChildren[n],lookup);
113 }
115 // ------------------------------------------------------------------------------------------------
116 // Executes the post processing step on the given imported data.
117 void FindInstancesProcess::Execute( aiScene* pScene)
118 {
119 DefaultLogger::get()->debug("FindInstancesProcess begin");
120 if (pScene->mNumMeshes) {
122 // use a pseudo hash for all meshes in the scene to quickly find
123 // the ones which are possibly equal. This step is executed early
124 // in the pipeline, so we could, depending on the file format,
125 // have several thousand small meshes. That's too much for a brute
126 // everyone-against-everyone check involving up to 10 comparisons
127 // each.
128 boost::scoped_array<uint64_t> hashes (new uint64_t[pScene->mNumMeshes]);
129 boost::scoped_array<unsigned int> remapping (new unsigned int[pScene->mNumMeshes]);
131 unsigned int numMeshesOut = 0;
132 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
134 aiMesh* inst = pScene->mMeshes[i];
135 hashes[i] = GetMeshHash(inst);
137 for (int a = i-1; a >= 0; --a) {
138 if (hashes[i] == hashes[a])
139 {
140 aiMesh* orig = pScene->mMeshes[a];
141 if (!orig)
142 continue;
144 // check for hash collision .. we needn't check
145 // the vertex format, it *must* match due to the
146 // (brilliant) construction of the hash
147 if (orig->mNumBones != inst->mNumBones ||
148 orig->mNumFaces != inst->mNumFaces ||
149 orig->mNumVertices != inst->mNumVertices ||
150 orig->mMaterialIndex != inst->mMaterialIndex ||
151 orig->mPrimitiveTypes != inst->mPrimitiveTypes)
152 continue;
154 // up to now the meshes are equal. find an appropriate
155 // epsilon to compare position differences against
156 float epsilon = ComputePositionEpsilon(inst);
157 epsilon *= epsilon;
159 // now compare vertex positions, normals,
160 // tangents and bitangents using this epsilon.
161 if (orig->HasPositions()) {
162 if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon))
163 continue;
164 }
165 if (orig->HasNormals()) {
166 if(!CompareArrays(orig->mNormals,inst->mNormals,orig->mNumVertices,epsilon))
167 continue;
168 }
169 if (orig->HasTangentsAndBitangents()) {
170 if (!CompareArrays(orig->mTangents,inst->mTangents,orig->mNumVertices,epsilon) ||
171 !CompareArrays(orig->mBitangents,inst->mBitangents,orig->mNumVertices,epsilon))
172 continue;
173 }
175 // use a constant epsilon for colors and UV coordinates
176 static const float uvEpsilon = 10e-4f;
178 {
179 unsigned int i, end = orig->GetNumUVChannels();
180 for(i = 0; i < end; ++i) {
181 if (!orig->mTextureCoords[i]) {
182 continue;
183 }
184 if(!CompareArrays(orig->mTextureCoords[i],inst->mTextureCoords[i],orig->mNumVertices,uvEpsilon)) {
185 break;
186 }
187 }
188 if (i != end) {
189 continue;
190 }
191 }
192 {
193 unsigned int i, end = orig->GetNumColorChannels();
194 for(i = 0; i < end; ++i) {
195 if (!orig->mColors[i]) {
196 continue;
197 }
198 if(!CompareArrays(orig->mColors[i],inst->mColors[i],orig->mNumVertices,uvEpsilon)) {
199 break;
200 }
201 }
202 if (i != end) {
203 continue;
204 }
205 }
207 // These two checks are actually quite expensive and almost *never* required.
208 // Almost. That's why they're still here. But there's no reason to do them
209 // in speed-targeted imports.
210 if (!configSpeedFlag) {
212 // It seems to be strange, but we really need to check whether the
213 // bones are identical too. Although it's extremely unprobable
214 // that they're not if control reaches here, we need to deal
215 // with unprobable cases, too. It could still be that there are
216 // equal shapes which are deformed differently.
217 if (!CompareBones(orig,inst))
218 continue;
220 // For completeness ... compare even the index buffers for equality
221 // face order & winding order doesn't care. Input data is in verbose format.
222 boost::scoped_array<unsigned int> ftbl_orig(new unsigned int[orig->mNumVertices]);
223 boost::scoped_array<unsigned int> ftbl_inst(new unsigned int[orig->mNumVertices]);
225 for (unsigned int tt = 0; tt < orig->mNumFaces;++tt) {
226 aiFace& f = orig->mFaces[tt];
227 for (unsigned int nn = 0; nn < f.mNumIndices;++nn)
228 ftbl_orig[f.mIndices[nn]] = tt;
230 aiFace& f2 = inst->mFaces[tt];
231 for (unsigned int nn = 0; nn < f2.mNumIndices;++nn)
232 ftbl_inst[f2.mIndices[nn]] = tt;
233 }
234 if (0 != ::memcmp(ftbl_inst.get(),ftbl_orig.get(),orig->mNumVertices*sizeof(unsigned int)))
235 continue;
236 }
238 // We're still here. Or in other words: 'inst' is an instance of 'orig'.
239 // Place a marker in our list that we can easily update mesh indices.
240 remapping[i] = remapping[a];
242 // Delete the instanced mesh, we don't need it anymore
243 delete inst;
244 pScene->mMeshes[i] = NULL;
245 break;
246 }
247 }
249 // If we didn't find a match for the current mesh: keep it
250 if (pScene->mMeshes[i]) {
251 remapping[i] = numMeshesOut++;
252 }
253 }
254 ai_assert(0 != numMeshesOut);
255 if (numMeshesOut != pScene->mNumMeshes) {
257 // Collapse the meshes array by removing all NULL entries
258 for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) {
259 if (pScene->mMeshes[i])
260 pScene->mMeshes[real++] = pScene->mMeshes[i];
261 }
263 // And update the nodegraph with our nice lookup table
264 UpdateMeshIndices(pScene->mRootNode,remapping.get());
266 // write to log
267 if (!DefaultLogger::isNullLogger()) {
269 char buffer[512];
270 ::sprintf(buffer,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut);
271 DefaultLogger::get()->info(buffer);
272 }
273 pScene->mNumMeshes = numMeshesOut;
274 }
275 else DefaultLogger::get()->debug("FindInstancesProcess finished. No instanced meshes found");
276 }
277 }