nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file MaterialSystem.cpp nuclear@0: * @brief Implementation of the material system of the library nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: nuclear@0: #include "Hash.h" nuclear@0: #include "fast_atof.h" nuclear@0: #include "ParsingUtils.h" nuclear@0: #include "MaterialSystem.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a specific property from a material nuclear@0: aiReturn aiGetMaterialProperty(const aiMaterial* pMat, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: const aiMaterialProperty** pPropOut) nuclear@0: { nuclear@0: ai_assert (pMat != NULL); nuclear@0: ai_assert (pKey != NULL); nuclear@0: ai_assert (pPropOut != NULL); nuclear@0: nuclear@0: /* Just search for a property with exactly this name .. nuclear@0: * could be improved by hashing, but it's possibly nuclear@0: * no worth the effort (we're bound to C structures, nuclear@0: * thus std::map or derivates are not applicable. */ nuclear@0: for (unsigned int i = 0; i < pMat->mNumProperties;++i) { nuclear@0: aiMaterialProperty* prop = pMat->mProperties[i]; nuclear@0: nuclear@0: if (prop /* just for safety ... */ nuclear@0: && 0 == strcmp( prop->mKey.data, pKey ) nuclear@0: && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wildcard, but this is undocumented :-) */ nuclear@0: && (UINT_MAX == index || prop->mIndex == index)) nuclear@0: { nuclear@0: *pPropOut = pMat->mProperties[i]; nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: } nuclear@0: *pPropOut = NULL; nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get an array of floating-point values from the material. nuclear@0: aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: float* pOut, nuclear@0: unsigned int* pMax) nuclear@0: { nuclear@0: ai_assert (pOut != NULL); nuclear@0: ai_assert (pMat != NULL); nuclear@0: nuclear@0: const aiMaterialProperty* prop; nuclear@0: aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop); nuclear@0: if (!prop) { nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // data is given in floats, simply copy it nuclear@0: unsigned int iWrite; nuclear@0: if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) { nuclear@0: iWrite = prop->mDataLength / sizeof(float); nuclear@0: if (pMax) { nuclear@0: iWrite = std::min(*pMax,iWrite); ; nuclear@0: } nuclear@0: for (unsigned int a = 0; a < iWrite;++a) { nuclear@0: pOut[a] = static_cast ( reinterpret_cast(prop->mData)[a] ); nuclear@0: } nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: // data is given in ints, convert to float nuclear@0: else if( aiPTI_Integer == prop->mType) { nuclear@0: iWrite = prop->mDataLength / sizeof(int32_t); nuclear@0: if (pMax) { nuclear@0: iWrite = std::min(*pMax,iWrite); ; nuclear@0: } nuclear@0: for (unsigned int a = 0; a < iWrite;++a) { nuclear@0: pOut[a] = static_cast ( reinterpret_cast(prop->mData)[a] ); nuclear@0: } nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: // a string ... read floats separated by spaces nuclear@0: else { nuclear@0: if (pMax) { nuclear@0: iWrite = *pMax; nuclear@0: } nuclear@0: // strings are zero-terminated with a 32 bit length prefix, so this is safe nuclear@0: const char* cur = prop->mData+4; nuclear@0: ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]); nuclear@0: for (unsigned int a = 0; ;++a) { nuclear@0: cur = fast_atoreal_move(cur,pOut[a]); nuclear@0: if(a==iWrite-1) { nuclear@0: break; nuclear@0: } nuclear@0: if(!IsSpace(*cur)) { nuclear@0: DefaultLogger::get()->error("Material property" + std::string(pKey) + nuclear@0: " is a string; failed to parse a float array out of it."); nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: return AI_SUCCESS; nuclear@0: nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get an array if integers from the material nuclear@0: aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: int* pOut, nuclear@0: unsigned int* pMax) nuclear@0: { nuclear@0: ai_assert (pOut != NULL); nuclear@0: ai_assert (pMat != NULL); nuclear@0: nuclear@0: const aiMaterialProperty* prop; nuclear@0: aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop); nuclear@0: if (!prop) { nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // data is given in ints, simply copy it nuclear@0: unsigned int iWrite; nuclear@0: if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) { nuclear@0: iWrite = prop->mDataLength / sizeof(int32_t); nuclear@0: if (pMax) { nuclear@0: iWrite = std::min(*pMax,iWrite); ; nuclear@0: } nuclear@0: for (unsigned int a = 0; a < iWrite;++a) { nuclear@0: pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); nuclear@0: } nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: // data is given in floats convert to int nuclear@0: else if( aiPTI_Float == prop->mType) { nuclear@0: iWrite = prop->mDataLength / sizeof(float); nuclear@0: if (pMax) { nuclear@0: iWrite = std::min(*pMax,iWrite); ; nuclear@0: } nuclear@0: for (unsigned int a = 0; a < iWrite;++a) { nuclear@0: pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); nuclear@0: } nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: // it is a string ... no way to read something out of this nuclear@0: else { nuclear@0: if (pMax) { nuclear@0: iWrite = *pMax; nuclear@0: } nuclear@0: // strings are zero-terminated with a 32 bit length prefix, so this is safe nuclear@0: const char* cur = prop->mData+4; nuclear@0: ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]); nuclear@0: for (unsigned int a = 0; ;++a) { nuclear@0: pOut[a] = strtol10(cur,&cur); nuclear@0: if(a==iWrite-1) { nuclear@0: break; nuclear@0: } nuclear@0: if(!IsSpace(*cur)) { nuclear@0: DefaultLogger::get()->error("Material property" + std::string(pKey) + nuclear@0: " is a string; failed to parse an integer array out of it."); nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (pMax) { nuclear@0: *pMax = iWrite; nuclear@0: } nuclear@0: } nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a color (3 or 4 floats) from the material nuclear@0: aiReturn aiGetMaterialColor(const aiMaterial* pMat, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: aiColor4D* pOut) nuclear@0: { nuclear@0: unsigned int iMax = 4; nuclear@0: const aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax); nuclear@0: nuclear@0: // if no alpha channel is defined: set it to 1.0 nuclear@0: if (3 == iMax) { nuclear@0: pOut->a = 1.0f; nuclear@0: } nuclear@0: nuclear@0: return eRet; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a string from the material nuclear@0: aiReturn aiGetMaterialString(const aiMaterial* pMat, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: aiString* pOut) nuclear@0: { nuclear@0: ai_assert (pOut != NULL); nuclear@0: nuclear@0: const aiMaterialProperty* prop; nuclear@0: aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop); nuclear@0: if (!prop) { nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: if( aiPTI_String == prop->mType) { nuclear@0: ai_assert(prop->mDataLength>=5); nuclear@0: nuclear@0: // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data nuclear@0: pOut->length = static_cast(*reinterpret_cast(prop->mData)); nuclear@0: nuclear@0: ai_assert(pOut->length+1+4==prop->mDataLength && !prop->mData[prop->mDataLength-1]); nuclear@0: memcpy(pOut->data,prop->mData+4,pOut->length+1); nuclear@0: } nuclear@0: else { nuclear@0: // TODO - implement lexical cast as well nuclear@0: DefaultLogger::get()->error("Material property" + std::string(pKey) + nuclear@0: " was found, but is no string" ); nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the number of textures on a particular texture stack nuclear@0: ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat, nuclear@0: C_ENUM aiTextureType type) nuclear@0: { nuclear@0: ai_assert (pMat != NULL); nuclear@0: nuclear@0: /* Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again) */ nuclear@0: unsigned int max = 0; nuclear@0: for (unsigned int i = 0; i < pMat->mNumProperties;++i) { nuclear@0: aiMaterialProperty* prop = pMat->mProperties[i]; nuclear@0: nuclear@0: if (prop /* just a sanity check ... */ nuclear@0: && 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE ) nuclear@0: && prop->mSemantic == type) { nuclear@0: nuclear@0: max = std::max(max,prop->mIndex+1); nuclear@0: } nuclear@0: } nuclear@0: return max; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, nuclear@0: aiTextureType type, nuclear@0: unsigned int index, nuclear@0: C_STRUCT aiString* path, nuclear@0: aiTextureMapping* _mapping /*= NULL*/, nuclear@0: unsigned int* uvindex /*= NULL*/, nuclear@0: float* blend /*= NULL*/, nuclear@0: aiTextureOp* op /*= NULL*/, nuclear@0: aiTextureMapMode* mapmode /*= NULL*/, nuclear@0: unsigned int* flags /*= NULL*/ nuclear@0: ) nuclear@0: { nuclear@0: ai_assert(NULL != mat && NULL != path); nuclear@0: nuclear@0: // Get the path to the texture nuclear@0: if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path)) { nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: // Determine mapping type nuclear@0: aiTextureMapping mapping = aiTextureMapping_UV; nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping); nuclear@0: if (_mapping) nuclear@0: *_mapping = mapping; nuclear@0: nuclear@0: // Get UV index nuclear@0: if (aiTextureMapping_UV == mapping && uvindex) { nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex); nuclear@0: } nuclear@0: // Get blend factor nuclear@0: if (blend) { nuclear@0: aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend); nuclear@0: } nuclear@0: // Get texture operation nuclear@0: if (op){ nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op); nuclear@0: } nuclear@0: // Get texture mapping modes nuclear@0: if (mapmode) { nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]); nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]); nuclear@0: } nuclear@0: // Get texture flags nuclear@0: if (flags){ nuclear@0: aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags); nuclear@0: } nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Construction. Actually the one and only way to get an aiMaterial instance nuclear@0: aiMaterial::aiMaterial() nuclear@0: { nuclear@0: // Allocate 5 entries by default nuclear@0: mNumProperties = 0; nuclear@0: mNumAllocated = 5; nuclear@0: mProperties = new aiMaterialProperty*[5]; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiMaterial::~aiMaterial() nuclear@0: { nuclear@0: Clear(); nuclear@0: nuclear@0: delete[] mProperties; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void aiMaterial::Clear() nuclear@0: { nuclear@0: for (unsigned int i = 0; i < mNumProperties;++i) { nuclear@0: // delete this entry nuclear@0: delete mProperties[i]; nuclear@0: AI_DEBUG_INVALIDATE_PTR(mProperties[i]); nuclear@0: } nuclear@0: mNumProperties = 0; nuclear@0: nuclear@0: // The array remains allocated, we just invalidated its contents nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiReturn aiMaterial::RemoveProperty (const char* pKey,unsigned int type, nuclear@0: unsigned int index nuclear@0: ) nuclear@0: { nuclear@0: ai_assert(NULL != pKey); nuclear@0: nuclear@0: for (unsigned int i = 0; i < mNumProperties;++i) { nuclear@0: aiMaterialProperty* prop = mProperties[i]; nuclear@0: nuclear@0: if (prop && !strcmp( prop->mKey.data, pKey ) && nuclear@0: prop->mSemantic == type && prop->mIndex == index) nuclear@0: { nuclear@0: // Delete this entry nuclear@0: delete mProperties[i]; nuclear@0: nuclear@0: // collapse the array behind --. nuclear@0: --mNumProperties; nuclear@0: for (unsigned int a = i; a < mNumProperties;++a) { nuclear@0: mProperties[a] = mProperties[a+1]; nuclear@0: } nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiReturn aiMaterial::AddBinaryProperty (const void* pInput, nuclear@0: unsigned int pSizeInBytes, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index, nuclear@0: aiPropertyTypeInfo pType nuclear@0: ) nuclear@0: { nuclear@0: ai_assert (pInput != NULL); nuclear@0: ai_assert (pKey != NULL); nuclear@0: ai_assert (0 != pSizeInBytes); nuclear@0: nuclear@0: // first search the list whether there is already an entry with this key nuclear@0: unsigned int iOutIndex = UINT_MAX; nuclear@0: for (unsigned int i = 0; i < mNumProperties;++i) { nuclear@0: aiMaterialProperty* prop = mProperties[i]; nuclear@0: nuclear@0: if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) && nuclear@0: prop->mSemantic == type && prop->mIndex == index){ nuclear@0: nuclear@0: delete mProperties[i]; nuclear@0: iOutIndex = i; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Allocate a new material property nuclear@0: aiMaterialProperty* pcNew = new aiMaterialProperty(); nuclear@0: nuclear@0: // .. and fill it nuclear@0: pcNew->mType = pType; nuclear@0: pcNew->mSemantic = type; nuclear@0: pcNew->mIndex = index; nuclear@0: nuclear@0: pcNew->mDataLength = pSizeInBytes; nuclear@0: pcNew->mData = new char[pSizeInBytes]; nuclear@0: memcpy (pcNew->mData,pInput,pSizeInBytes); nuclear@0: nuclear@0: pcNew->mKey.length = ::strlen(pKey); nuclear@0: ai_assert ( MAXLEN > pcNew->mKey.length); nuclear@0: strcpy( pcNew->mKey.data, pKey ); nuclear@0: nuclear@0: if (UINT_MAX != iOutIndex) { nuclear@0: mProperties[iOutIndex] = pcNew; nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // resize the array ... double the storage allocated nuclear@0: if (mNumProperties == mNumAllocated) { nuclear@0: const unsigned int iOld = mNumAllocated; nuclear@0: mNumAllocated *= 2; nuclear@0: nuclear@0: aiMaterialProperty** ppTemp; nuclear@0: try { nuclear@0: ppTemp = new aiMaterialProperty*[mNumAllocated]; nuclear@0: } catch (std::bad_alloc&) { nuclear@0: return AI_OUTOFMEMORY; nuclear@0: } nuclear@0: nuclear@0: // just copy all items over; then replace the old array nuclear@0: memcpy (ppTemp,mProperties,iOld * sizeof(void*)); nuclear@0: nuclear@0: delete[] mProperties; nuclear@0: mProperties = ppTemp; nuclear@0: } nuclear@0: // push back ... nuclear@0: mProperties[mNumProperties++] = pcNew; nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiReturn aiMaterial::AddProperty (const aiString* pInput, nuclear@0: const char* pKey, nuclear@0: unsigned int type, nuclear@0: unsigned int index) nuclear@0: { nuclear@0: // We don't want to add the whole buffer .. write a 32 bit length nuclear@0: // prefix followed by the zero-terminated UTF8 string. nuclear@0: // (HACK) I don't want to break the ABI now, but we definitely nuclear@0: // ought to change aiString::mLength to uint32_t one day. nuclear@0: if (sizeof(size_t) == 8) { nuclear@0: aiString copy = *pInput; nuclear@0: uint32_t* s = reinterpret_cast(©.length); nuclear@0: s[1] = static_cast(pInput->length); nuclear@0: nuclear@0: return AddBinaryProperty(s+1, nuclear@0: pInput->length+1+4, nuclear@0: pKey, nuclear@0: type, nuclear@0: index, nuclear@0: aiPTI_String); nuclear@0: } nuclear@0: ai_assert(sizeof(size_t)==4); nuclear@0: return AddBinaryProperty(pInput, nuclear@0: pInput->length+1+4, nuclear@0: pKey, nuclear@0: type, nuclear@0: index, nuclear@0: aiPTI_String); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: uint32_t Assimp :: ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/) nuclear@0: { nuclear@0: uint32_t hash = 1503; // magic start value, chosen to be my birthday :-) nuclear@0: for (unsigned int i = 0; i < mat->mNumProperties;++i) { nuclear@0: aiMaterialProperty* prop; nuclear@0: nuclear@0: // Exclude all properties whose first character is '?' from the hash nuclear@0: // See doc for aiMaterialProperty. nuclear@0: if ((prop = mat->mProperties[i]) && (includeMatName || prop->mKey.data[0] != '?')) { nuclear@0: nuclear@0: hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash); nuclear@0: hash = SuperFastHash(prop->mData,prop->mDataLength,hash); nuclear@0: nuclear@0: // Combine the semantic and the index with the hash nuclear@0: hash = SuperFastHash((const char*)&prop->mSemantic,sizeof(unsigned int),hash); nuclear@0: hash = SuperFastHash((const char*)&prop->mIndex,sizeof(unsigned int),hash); nuclear@0: } nuclear@0: } nuclear@0: return hash; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void aiMaterial::CopyPropertyList(aiMaterial* pcDest, nuclear@0: const aiMaterial* pcSrc nuclear@0: ) nuclear@0: { nuclear@0: ai_assert(NULL != pcDest); nuclear@0: ai_assert(NULL != pcSrc); nuclear@0: nuclear@0: unsigned int iOldNum = pcDest->mNumProperties; nuclear@0: pcDest->mNumAllocated += pcSrc->mNumAllocated; nuclear@0: pcDest->mNumProperties += pcSrc->mNumProperties; nuclear@0: nuclear@0: aiMaterialProperty** pcOld = pcDest->mProperties; nuclear@0: pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated]; nuclear@0: nuclear@0: if (iOldNum && pcOld) { nuclear@0: for (unsigned int i = 0; i < iOldNum;++i) { nuclear@0: pcDest->mProperties[i] = pcOld[i]; nuclear@0: } nuclear@0: nuclear@0: delete[] pcOld; nuclear@0: } nuclear@0: for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) { nuclear@0: aiMaterialProperty* propSrc = pcSrc->mProperties[i]; nuclear@0: nuclear@0: // search whether we have already a property with this name -> if yes, overwrite it nuclear@0: aiMaterialProperty* prop; nuclear@0: for (unsigned int q = 0; q < iOldNum;++q) { nuclear@0: prop = pcDest->mProperties[q]; nuclear@0: if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic nuclear@0: && prop->mIndex == propSrc->mIndex) { nuclear@0: delete prop; nuclear@0: nuclear@0: // collapse the whole array ... nuclear@0: memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q); nuclear@0: i--; nuclear@0: pcDest->mNumProperties--; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Allocate the output property and copy the source property nuclear@0: prop = pcDest->mProperties[i] = new aiMaterialProperty(); nuclear@0: prop->mKey = propSrc->mKey; nuclear@0: prop->mDataLength = propSrc->mDataLength; nuclear@0: prop->mType = propSrc->mType; nuclear@0: prop->mSemantic = propSrc->mSemantic; nuclear@0: prop->mIndex = propSrc->mIndex; nuclear@0: nuclear@0: prop->mData = new char[propSrc->mDataLength]; nuclear@0: memcpy(prop->mData,propSrc->mData,prop->mDataLength); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: