vrshoot

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