vrshoot

annotate 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
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