vrshoot

view libs/assimp/RemoveRedundantMaterials.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 */
41 /** @file RemoveRedundantMaterials.cpp
42 * @brief Implementation of the "RemoveRedundantMaterials" post processing step
43 */
45 // internal headers
46 #include "AssimpPCH.h"
47 #include "RemoveRedundantMaterials.h"
48 #include "ParsingUtils.h"
49 #include "ProcessHelper.h"
50 #include "MaterialSystem.h"
52 using namespace Assimp;
54 // ------------------------------------------------------------------------------------------------
55 // Constructor to be privately used by Importer
56 RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
57 {
58 // nothing to do here
59 }
61 // ------------------------------------------------------------------------------------------------
62 // Destructor, private as well
63 RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess()
64 {
65 // nothing to do here
66 }
68 // ------------------------------------------------------------------------------------------------
69 // Returns whether the processing step is present in the given flag field.
70 bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const
71 {
72 return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
73 }
75 // ------------------------------------------------------------------------------------------------
76 // Setup import properties
77 void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp)
78 {
79 // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
80 configFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
81 }
83 // ------------------------------------------------------------------------------------------------
84 // Executes the post processing step on the given imported data.
85 void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
86 {
87 DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
89 unsigned int iCnt = 0, unreferenced = 0;
90 if (pScene->mNumMaterials)
91 {
92 // Find out which materials are referenced by meshes
93 std::vector<bool> abReferenced(pScene->mNumMaterials,false);
94 for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
95 abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
97 // If a list of materials to be excluded was given, match the list with
98 // our imported materials and 'salt' all positive matches to ensure that
99 // we get unique hashes later.
100 if (configFixedMaterials.length()) {
102 std::list<std::string> strings;
103 ConvertListToStrings(configFixedMaterials,strings);
105 for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
106 aiMaterial* mat = pScene->mMaterials[i];
108 aiString name;
109 mat->Get(AI_MATKEY_NAME,name);
111 if (name.length) {
112 std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
113 if (it != strings.end()) {
115 // Our brilliant 'salt': A single material property with ~ as first
116 // character to mark it as internal and temporary.
117 const int dummy = 1;
118 ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
120 // Keep this material even if no mesh references it
121 abReferenced[i] = true;
122 DefaultLogger::get()->debug(std::string("Found positive match in exclusion list: \'") + name.data + "\'");
123 }
124 }
125 }
126 }
129 // TODO: reimplement this algorithm to work in-place
131 unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials];
132 unsigned int iNewNum = 0;
134 // Iterate through all materials and calculate a hash for them
135 // store all hashes in a list and so a quick search whether
136 // we do already have a specific hash. This allows us to
137 // determine which materials are identical.
138 uint32_t* aiHashes;
139 aiHashes = new uint32_t[pScene->mNumMaterials];
140 for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
141 {
142 // if the material is not referenced ... remove it
143 if (!abReferenced[i]) {
144 ++unreferenced;
145 continue;
146 }
148 uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
149 for (unsigned int a = 0; a < i;++a)
150 {
151 if (abReferenced[a] && me == aiHashes[a]) {
152 ++iCnt;
153 me = 0;
154 aiMappingTable[i] = aiMappingTable[a];
155 delete pScene->mMaterials[i];
156 break;
157 }
158 }
159 if (me) {
160 aiMappingTable[i] = iNewNum++;
161 }
162 }
163 if (iCnt) {
164 // build an output material list
165 aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
166 ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
167 for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
168 {
169 // if the material is not referenced ... remove it
170 if (!abReferenced[p])
171 continue;
173 // generate new names for all modified materials
174 const unsigned int idx = aiMappingTable[p];
175 if (ppcMaterials[idx])
176 {
177 aiString sz;
178 sz.length = ::sprintf(sz.data,"JoinedMaterial_#%i",p);
179 ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
180 }
181 else ppcMaterials[idx] = pScene->mMaterials[p];
182 }
183 // update all material indices
184 for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
185 aiMesh* mesh = pScene->mMeshes[p];
186 mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
187 }
188 // delete the old material list
189 delete[] pScene->mMaterials;
190 pScene->mMaterials = ppcMaterials;
191 pScene->mNumMaterials = iNewNum;
192 }
193 // delete temporary storage
194 delete[] aiHashes;
195 delete[] aiMappingTable;
196 }
197 if (!iCnt)DefaultLogger::get()->debug("RemoveRedundantMatsProcess finished ");
198 else
199 {
200 char szBuffer[128]; // should be sufficiently large
201 ::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. %i redundant and %i unused materials",
202 iCnt,unreferenced);
203 DefaultLogger::get()->info(szBuffer);
204 }
205 }