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