vrshoot

view libs/assimp/OptimizeMeshes.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 OptimizeMeshes.cpp
43 * @brief Implementation of the aiProcess_OptimizeMeshes step
44 */
46 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
49 using namespace Assimp;
50 #include "OptimizeMeshes.h"
51 #include "ProcessHelper.h"
52 #include "SceneCombiner.h"
54 // ------------------------------------------------------------------------------------------------
55 // Constructor to be privately used by Importer
56 OptimizeMeshesProcess::OptimizeMeshesProcess()
57 : pts (false)
58 , max_verts (0xffffffff)
59 , max_faces (0xffffffff)
60 {}
62 // ------------------------------------------------------------------------------------------------
63 // Destructor, private as well
64 OptimizeMeshesProcess::~OptimizeMeshesProcess()
65 {}
67 // ------------------------------------------------------------------------------------------------
68 // Returns whether the processing step is present in the given flag field.
69 bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
70 {
71 // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
72 // steps are active. Thus we need to query their flags here and store the
73 // information, although we're breaking const-correctness.
74 // That's a serious design flaw, consider redesign.
75 if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
76 pts = (0 != (pFlags & aiProcess_SortByPType));
77 max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0;
78 return true;
79 }
80 return false;
81 }
83 // ------------------------------------------------------------------------------------------------
84 // Setup properties for the postprocessing step
85 void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
86 {
87 if (max_verts == 0xdeadbeef /* magic hack */) {
88 max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
89 max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
90 }
91 }
93 // ------------------------------------------------------------------------------------------------
94 // Execute step
95 void OptimizeMeshesProcess::Execute( aiScene* pScene)
96 {
97 const unsigned int num_old = pScene->mNumMeshes;
98 if (num_old <= 1) {
99 DefaultLogger::get()->debug("Skipping OptimizeMeshesProcess");
100 return;
101 }
103 DefaultLogger::get()->debug("OptimizeMeshesProcess begin");
104 mScene = pScene;
106 // need to clear persistent members from previous runs
107 merge_list.clear();
108 output.clear();
110 merge_list.reserve(pScene->mNumMeshes);
111 output.reserve(pScene->mNumMeshes);
113 // Prepare lookup tables
114 meshes.resize(pScene->mNumMeshes);
115 FindInstancedMeshes(pScene->mRootNode);
116 if (max_verts == 0xdeadbeef) /* undo the magic hack */
117 max_verts = 0xffffffff;
119 // ... instanced meshes are immediately processed and added to the output list
120 for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
121 meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
123 if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
124 meshes[i].output_id = n++;
125 output.push_back(mScene->mMeshes[i]);
126 }
127 }
129 // and process all nodes in the scenegraoh recursively
130 ProcessNode(pScene->mRootNode);
131 if (!output.size()) {
132 throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
133 }
135 meshes.clear();
136 ai_assert(output.size() <= num_old);
138 mScene->mNumMeshes = output.size();
139 std::copy(output.begin(),output.end(),mScene->mMeshes);
141 if (output.size() != num_old) {
142 char tmp[512];
143 ::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
144 DefaultLogger::get()->info(tmp);
145 }
146 else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
147 }
149 // ------------------------------------------------------------------------------------------------
150 // Process meshes for a single node
151 void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
152 {
153 for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
154 unsigned int& im = pNode->mMeshes[i];
156 if (meshes[im].instance_cnt > 1) {
157 im = meshes[im].output_id;
158 }
159 else {
160 merge_list.clear();
161 unsigned int verts = 0, faces = 0;
163 // Find meshes to merge with us
164 for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) {
165 register unsigned int am = pNode->mMeshes[a];
166 if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) {
168 merge_list.push_back(mScene->mMeshes[am]);
169 verts += mScene->mMeshes[am]->mNumVertices;
170 faces += mScene->mMeshes[am]->mNumFaces;
172 --pNode->mNumMeshes;
173 for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
174 pNode->mMeshes[n] = pNode->mMeshes[n+1];
176 --a;
177 }
178 }
180 // and merge all meshes which we found, replace the old ones
181 if (!merge_list.empty()) {
182 merge_list.push_back(mScene->mMeshes[im]);
184 aiMesh* out;
185 SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
186 output.push_back(out);
187 }
188 else {
189 output.push_back(mScene->mMeshes[im]);
190 }
191 im = output.size()-1;
192 }
193 }
196 for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
197 ProcessNode(pNode->mChildren[i]);
198 }
200 // ------------------------------------------------------------------------------------------------
201 // Check whether two meshes can be joined
202 bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces )
203 {
204 if (meshes[a].vertex_format != meshes[b].vertex_format)
205 return false;
207 aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
209 if ((0xffffffff != max_verts && verts+mb->mNumVertices > max_verts) ||
210 (0xffffffff != max_faces && faces+mb->mNumFaces > max_faces)) {
211 return false;
212 }
214 // Never merge unskinned meshes with skinned meshes
215 if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones())
216 return false;
218 // Never merge meshes with different kinds of primitives if SortByPType did already
219 // do its work. We would destroy everything again ...
220 if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes)
221 return false;
223 // If both meshes are skinned, check whether we have many bones defined in both meshes.
224 // If yes, we can savely join them.
225 if (ma->HasBones()) {
226 // TODO
227 return false;
228 }
229 return true;
230 }
232 // ------------------------------------------------------------------------------------------------
233 // Buidl a LUT of all instanced meshes
234 void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
235 {
236 for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
237 ++meshes[pNode->mMeshes[i]].instance_cnt;
239 for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
240 FindInstancedMeshes(pNode->mChildren[i]);
241 }
243 #endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS