rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file OptimizeMeshes.cpp
|
nuclear@0
|
43 * @brief Implementation of the aiProcess_OptimizeMeshes step
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
|
nuclear@0
|
48
|
nuclear@0
|
49 using namespace Assimp;
|
nuclear@0
|
50 #include "OptimizeMeshes.h"
|
nuclear@0
|
51 #include "ProcessHelper.h"
|
nuclear@0
|
52 #include "SceneCombiner.h"
|
nuclear@0
|
53
|
nuclear@0
|
54 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
55 // Constructor to be privately used by Importer
|
nuclear@0
|
56 OptimizeMeshesProcess::OptimizeMeshesProcess()
|
nuclear@0
|
57 : pts (false)
|
nuclear@0
|
58 , max_verts (0xffffffff)
|
nuclear@0
|
59 , max_faces (0xffffffff)
|
nuclear@0
|
60 {}
|
nuclear@0
|
61
|
nuclear@0
|
62 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
63 // Destructor, private as well
|
nuclear@0
|
64 OptimizeMeshesProcess::~OptimizeMeshesProcess()
|
nuclear@0
|
65 {}
|
nuclear@0
|
66
|
nuclear@0
|
67 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
68 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
69 bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
|
nuclear@0
|
70 {
|
nuclear@0
|
71 // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
|
nuclear@0
|
72 // steps are active. Thus we need to query their flags here and store the
|
nuclear@0
|
73 // information, although we're breaking const-correctness.
|
nuclear@0
|
74 // That's a serious design flaw, consider redesign.
|
nuclear@0
|
75 if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
|
nuclear@0
|
76 pts = (0 != (pFlags & aiProcess_SortByPType));
|
nuclear@0
|
77 max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0;
|
nuclear@0
|
78 return true;
|
nuclear@0
|
79 }
|
nuclear@0
|
80 return false;
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
84 // Setup properties for the postprocessing step
|
nuclear@0
|
85 void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
|
nuclear@0
|
86 {
|
nuclear@0
|
87 if (max_verts == 0xdeadbeef /* magic hack */) {
|
nuclear@0
|
88 max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
|
nuclear@0
|
89 max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
|
nuclear@0
|
90 }
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
94 // Execute step
|
nuclear@0
|
95 void OptimizeMeshesProcess::Execute( aiScene* pScene)
|
nuclear@0
|
96 {
|
nuclear@0
|
97 const unsigned int num_old = pScene->mNumMeshes;
|
nuclear@0
|
98 if (num_old <= 1) {
|
nuclear@0
|
99 DefaultLogger::get()->debug("Skipping OptimizeMeshesProcess");
|
nuclear@0
|
100 return;
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103 DefaultLogger::get()->debug("OptimizeMeshesProcess begin");
|
nuclear@0
|
104 mScene = pScene;
|
nuclear@0
|
105
|
nuclear@0
|
106 // need to clear persistent members from previous runs
|
nuclear@0
|
107 merge_list.clear();
|
nuclear@0
|
108 output.clear();
|
nuclear@0
|
109
|
nuclear@0
|
110 merge_list.reserve(pScene->mNumMeshes);
|
nuclear@0
|
111 output.reserve(pScene->mNumMeshes);
|
nuclear@0
|
112
|
nuclear@0
|
113 // Prepare lookup tables
|
nuclear@0
|
114 meshes.resize(pScene->mNumMeshes);
|
nuclear@0
|
115 FindInstancedMeshes(pScene->mRootNode);
|
nuclear@0
|
116 if (max_verts == 0xdeadbeef) /* undo the magic hack */
|
nuclear@0
|
117 max_verts = 0xffffffff;
|
nuclear@0
|
118
|
nuclear@0
|
119 // ... instanced meshes are immediately processed and added to the output list
|
nuclear@0
|
120 for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
|
nuclear@0
|
121 meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
|
nuclear@0
|
122
|
nuclear@0
|
123 if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
|
nuclear@0
|
124 meshes[i].output_id = n++;
|
nuclear@0
|
125 output.push_back(mScene->mMeshes[i]);
|
nuclear@0
|
126 }
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 // and process all nodes in the scenegraoh recursively
|
nuclear@0
|
130 ProcessNode(pScene->mRootNode);
|
nuclear@0
|
131 if (!output.size()) {
|
nuclear@0
|
132 throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 meshes.clear();
|
nuclear@0
|
136 ai_assert(output.size() <= num_old);
|
nuclear@0
|
137
|
nuclear@0
|
138 mScene->mNumMeshes = output.size();
|
nuclear@0
|
139 std::copy(output.begin(),output.end(),mScene->mMeshes);
|
nuclear@0
|
140
|
nuclear@0
|
141 if (output.size() != num_old) {
|
nuclear@0
|
142 char tmp[512];
|
nuclear@0
|
143 ::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
|
nuclear@0
|
144 DefaultLogger::get()->info(tmp);
|
nuclear@0
|
145 }
|
nuclear@0
|
146 else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
|
nuclear@0
|
147 }
|
nuclear@0
|
148
|
nuclear@0
|
149 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
150 // Process meshes for a single node
|
nuclear@0
|
151 void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
|
nuclear@0
|
152 {
|
nuclear@0
|
153 for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
|
nuclear@0
|
154 unsigned int& im = pNode->mMeshes[i];
|
nuclear@0
|
155
|
nuclear@0
|
156 if (meshes[im].instance_cnt > 1) {
|
nuclear@0
|
157 im = meshes[im].output_id;
|
nuclear@0
|
158 }
|
nuclear@0
|
159 else {
|
nuclear@0
|
160 merge_list.clear();
|
nuclear@0
|
161 unsigned int verts = 0, faces = 0;
|
nuclear@0
|
162
|
nuclear@0
|
163 // Find meshes to merge with us
|
nuclear@0
|
164 for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) {
|
nuclear@0
|
165 register unsigned int am = pNode->mMeshes[a];
|
nuclear@0
|
166 if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) {
|
nuclear@0
|
167
|
nuclear@0
|
168 merge_list.push_back(mScene->mMeshes[am]);
|
nuclear@0
|
169 verts += mScene->mMeshes[am]->mNumVertices;
|
nuclear@0
|
170 faces += mScene->mMeshes[am]->mNumFaces;
|
nuclear@0
|
171
|
nuclear@0
|
172 --pNode->mNumMeshes;
|
nuclear@0
|
173 for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
|
nuclear@0
|
174 pNode->mMeshes[n] = pNode->mMeshes[n+1];
|
nuclear@0
|
175
|
nuclear@0
|
176 --a;
|
nuclear@0
|
177 }
|
nuclear@0
|
178 }
|
nuclear@0
|
179
|
nuclear@0
|
180 // and merge all meshes which we found, replace the old ones
|
nuclear@0
|
181 if (!merge_list.empty()) {
|
nuclear@0
|
182 merge_list.push_back(mScene->mMeshes[im]);
|
nuclear@0
|
183
|
nuclear@0
|
184 aiMesh* out;
|
nuclear@0
|
185 SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
|
nuclear@0
|
186 output.push_back(out);
|
nuclear@0
|
187 }
|
nuclear@0
|
188 else {
|
nuclear@0
|
189 output.push_back(mScene->mMeshes[im]);
|
nuclear@0
|
190 }
|
nuclear@0
|
191 im = output.size()-1;
|
nuclear@0
|
192 }
|
nuclear@0
|
193 }
|
nuclear@0
|
194
|
nuclear@0
|
195
|
nuclear@0
|
196 for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
|
nuclear@0
|
197 ProcessNode(pNode->mChildren[i]);
|
nuclear@0
|
198 }
|
nuclear@0
|
199
|
nuclear@0
|
200 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
201 // Check whether two meshes can be joined
|
nuclear@0
|
202 bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces )
|
nuclear@0
|
203 {
|
nuclear@0
|
204 if (meshes[a].vertex_format != meshes[b].vertex_format)
|
nuclear@0
|
205 return false;
|
nuclear@0
|
206
|
nuclear@0
|
207 aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
|
nuclear@0
|
208
|
nuclear@0
|
209 if ((0xffffffff != max_verts && verts+mb->mNumVertices > max_verts) ||
|
nuclear@0
|
210 (0xffffffff != max_faces && faces+mb->mNumFaces > max_faces)) {
|
nuclear@0
|
211 return false;
|
nuclear@0
|
212 }
|
nuclear@0
|
213
|
nuclear@0
|
214 // Never merge unskinned meshes with skinned meshes
|
nuclear@0
|
215 if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones())
|
nuclear@0
|
216 return false;
|
nuclear@0
|
217
|
nuclear@0
|
218 // Never merge meshes with different kinds of primitives if SortByPType did already
|
nuclear@0
|
219 // do its work. We would destroy everything again ...
|
nuclear@0
|
220 if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes)
|
nuclear@0
|
221 return false;
|
nuclear@0
|
222
|
nuclear@0
|
223 // If both meshes are skinned, check whether we have many bones defined in both meshes.
|
nuclear@0
|
224 // If yes, we can savely join them.
|
nuclear@0
|
225 if (ma->HasBones()) {
|
nuclear@0
|
226 // TODO
|
nuclear@0
|
227 return false;
|
nuclear@0
|
228 }
|
nuclear@0
|
229 return true;
|
nuclear@0
|
230 }
|
nuclear@0
|
231
|
nuclear@0
|
232 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
233 // Buidl a LUT of all instanced meshes
|
nuclear@0
|
234 void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
|
nuclear@0
|
235 {
|
nuclear@0
|
236 for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
|
nuclear@0
|
237 ++meshes[pNode->mMeshes[i]].instance_cnt;
|
nuclear@0
|
238
|
nuclear@0
|
239 for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
|
nuclear@0
|
240 FindInstancedMeshes(pNode->mChildren[i]);
|
nuclear@0
|
241 }
|
nuclear@0
|
242
|
nuclear@0
|
243 #endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
|