2015-05-19 03:48:29 +00:00
|
|
|
/*
|
|
|
|
Open Asset Import Library (assimp)
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
|
2022-01-10 20:13:43 +00:00
|
|
|
Copyright (c) 2006-2022, assimp team
|
2018-01-28 18:42:05 +00:00
|
|
|
|
2017-05-09 17:57:36 +00:00
|
|
|
|
2015-05-19 03:48:29 +00:00
|
|
|
All rights reserved.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
Redistribution and use of this software in source and binary forms,
|
|
|
|
with or without modification, are permitted provided that the
|
2015-05-19 03:48:29 +00:00
|
|
|
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.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
2015-05-19 03:52:10 +00:00
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
2015-05-19 03:48:29 +00:00
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
2015-05-19 03:52:10 +00:00
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
2015-05-19 03:52:10 +00:00
|
|
|
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
|
2015-05-19 03:48:29 +00:00
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file MaterialSystem.cpp
|
|
|
|
* @brief Implementation of the material system of the library
|
|
|
|
*/
|
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
#include "MaterialSystem.h"
|
2018-01-06 00:18:33 +00:00
|
|
|
#include <assimp/Hash.h>
|
|
|
|
#include <assimp/ParsingUtils.h>
|
2020-06-23 19:05:42 +00:00
|
|
|
#include <assimp/fast_atof.h>
|
2016-06-06 20:04:29 +00:00
|
|
|
#include <assimp/material.h>
|
2020-06-23 19:05:42 +00:00
|
|
|
#include <assimp/types.h>
|
2016-06-06 20:04:29 +00:00
|
|
|
#include <assimp/DefaultLogger.hpp>
|
2023-06-02 15:08:50 +00:00
|
|
|
#include <memory>
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get a specific property from a material
|
2020-06-23 19:05:42 +00:00
|
|
|
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);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
/* 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. */
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *prop = pMat->mProperties[i];
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
if (prop /* just for safety ... */
|
2020-06-23 19:05:42 +00:00
|
|
|
&& 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)) {
|
2015-05-19 03:57:13 +00:00
|
|
|
*pPropOut = pMat->mProperties[i];
|
|
|
|
return AI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
*pPropOut = nullptr;
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get an array of floating-point values from the material.
|
2020-06-23 19:05:42 +00:00
|
|
|
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) {
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:49:28 +00:00
|
|
|
// data is given in floats, convert to ai_real
|
2015-05-19 03:57:13 +00:00
|
|
|
unsigned int iWrite = 0;
|
2020-06-23 19:05:42 +00:00
|
|
|
if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
|
2015-05-19 03:57:13 +00:00
|
|
|
iWrite = prop->mDataLength / sizeof(float);
|
|
|
|
if (pMax) {
|
2020-06-23 19:05:42 +00:00
|
|
|
iWrite = std::min(*pMax, iWrite);
|
|
|
|
;
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2019-06-12 20:12:38 +00:00
|
|
|
|
|
|
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
2020-06-23 19:05:42 +00:00
|
|
|
pOut[a] = static_cast<ai_real>(reinterpret_cast<float *>(prop->mData)[a]);
|
2016-07-16 23:49:28 +00:00
|
|
|
}
|
2019-06-12 20:12:38 +00:00
|
|
|
|
2016-07-16 23:49:28 +00:00
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// data is given in doubles, convert to float
|
2020-06-23 19:05:42 +00:00
|
|
|
else if (aiPTI_Double == prop->mType) {
|
2016-07-16 23:49:28 +00:00
|
|
|
iWrite = prop->mDataLength / sizeof(double);
|
|
|
|
if (pMax) {
|
2020-06-23 19:05:42 +00:00
|
|
|
iWrite = std::min(*pMax, iWrite);
|
|
|
|
;
|
2016-07-16 23:49:28 +00:00
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
|
|
|
pOut[a] = static_cast<ai_real>(reinterpret_cast<double *>(prop->mData)[a]);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// data is given in ints, convert to float
|
2020-06-23 19:05:42 +00:00
|
|
|
else if (aiPTI_Integer == prop->mType) {
|
2015-05-19 03:57:13 +00:00
|
|
|
iWrite = prop->mDataLength / sizeof(int32_t);
|
|
|
|
if (pMax) {
|
2020-06-23 19:05:42 +00:00
|
|
|
iWrite = std::min(*pMax, iWrite);
|
|
|
|
;
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
|
|
|
pOut[a] = static_cast<ai_real>(reinterpret_cast<int32_t *>(prop->mData)[a]);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
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
|
2016-11-03 22:29:03 +00:00
|
|
|
const char *cur = prop->mData + 4;
|
2020-06-23 19:05:42 +00:00
|
|
|
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) {
|
2015-05-19 03:57:13 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
if (!IsSpace(*cur)) {
|
2021-05-13 11:05:31 +00:00
|
|
|
ASSIMP_LOG_ERROR("Material property", pKey,
|
2020-06-23 19:05:42 +00:00
|
|
|
" is a string; failed to parse a float array out of it.");
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AI_SUCCESS;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get an array if integers from the material
|
2020-06-23 19:05:42 +00:00
|
|
|
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);
|
2015-05-19 03:57:13 +00:00
|
|
|
if (!prop) {
|
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// data is given in ints, simply copy it
|
|
|
|
unsigned int iWrite = 0;
|
2020-06-23 19:05:42 +00:00
|
|
|
if (aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
|
2018-10-21 00:00:27 +00:00
|
|
|
iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
|
2015-05-19 03:57:13 +00:00
|
|
|
if (pMax) {
|
2020-06-23 19:05:42 +00:00
|
|
|
iWrite = std::min(*pMax, iWrite);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2018-10-21 00:00:27 +00:00
|
|
|
if (1 == prop->mDataLength) {
|
|
|
|
// bool type, 1 byte
|
|
|
|
*pOut = static_cast<int>(*prop->mData);
|
2020-06-23 19:05:42 +00:00
|
|
|
} else {
|
|
|
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
|
|
|
pOut[a] = static_cast<int>(reinterpret_cast<int32_t *>(prop->mData)[a]);
|
2018-10-21 00:00:27 +00:00
|
|
|
}
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// data is given in floats convert to int
|
2020-06-23 19:05:42 +00:00
|
|
|
else if (aiPTI_Float == prop->mType) {
|
2015-05-19 03:57:13 +00:00
|
|
|
iWrite = prop->mDataLength / sizeof(float);
|
|
|
|
if (pMax) {
|
2020-06-23 19:05:42 +00:00
|
|
|
iWrite = std::min(*pMax, iWrite);
|
|
|
|
;
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int a = 0; a < iWrite; ++a) {
|
|
|
|
pOut[a] = static_cast<int>(reinterpret_cast<float *>(prop->mData)[a]);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// it is a string ... no way to read something out of this
|
2020-06-23 19:05:42 +00:00
|
|
|
else {
|
2015-05-19 03:57:13 +00:00
|
|
|
if (pMax) {
|
|
|
|
iWrite = *pMax;
|
|
|
|
}
|
|
|
|
// strings are zero-terminated with a 32 bit length prefix, so this is safe
|
2020-06-23 19:05:42 +00:00
|
|
|
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) {
|
2015-05-19 03:57:13 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-06-23 19:05:42 +00:00
|
|
|
if (!IsSpace(*cur)) {
|
2021-05-13 11:05:31 +00:00
|
|
|
ASSIMP_LOG_ERROR("Material property", pKey,
|
2020-06-23 19:05:42 +00:00
|
|
|
" is a string; failed to parse an integer array out of it.");
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pMax) {
|
|
|
|
*pMax = iWrite;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AI_SUCCESS;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get a color (3 or 4 floats) from the material
|
2020-06-23 19:05:42 +00:00
|
|
|
aiReturn aiGetMaterialColor(const aiMaterial *pMat,
|
|
|
|
const char *pKey,
|
|
|
|
unsigned int type,
|
|
|
|
unsigned int index,
|
|
|
|
aiColor4D *pOut) {
|
2015-05-19 03:57:13 +00:00
|
|
|
unsigned int iMax = 4;
|
2020-06-23 19:05:42 +00:00
|
|
|
const aiReturn eRet = aiGetMaterialFloatArray(pMat, pKey, type, index, (ai_real *)pOut, &iMax);
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// if no alpha channel is defined: set it to 1.0
|
|
|
|
if (3 == iMax) {
|
2016-07-16 23:49:28 +00:00
|
|
|
pOut->a = 1.0;
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
return eRet;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2019-11-26 07:17:35 +00:00
|
|
|
// Get a aiUVTransform (5 floats) from the material
|
2020-06-23 19:05:42 +00:00
|
|
|
aiReturn aiGetMaterialUVTransform(const aiMaterial *pMat,
|
|
|
|
const char *pKey,
|
|
|
|
unsigned int type,
|
|
|
|
unsigned int index,
|
|
|
|
aiUVTransform *pOut) {
|
2019-11-26 07:17:35 +00:00
|
|
|
unsigned int iMax = 5;
|
2020-06-23 19:05:42 +00:00
|
|
|
return aiGetMaterialFloatArray(pMat, pKey, type, index, (ai_real *)pOut, &iMax);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get a string from the material
|
2020-06-23 19:05:42 +00:00
|
|
|
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);
|
2015-05-19 03:57:13 +00:00
|
|
|
if (!prop) {
|
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (aiPTI_String == prop->mType) {
|
|
|
|
ai_assert(prop->mDataLength >= 5);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
|
2020-06-23 19:05:42 +00:00
|
|
|
pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t *>(prop->mData));
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
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 {
|
2015-05-19 03:57:13 +00:00
|
|
|
// TODO - implement lexical cast as well
|
2021-05-13 11:05:31 +00:00
|
|
|
ASSIMP_LOG_ERROR("Material property", pKey, " was found, but is no string");
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
|
|
|
return AI_SUCCESS;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get the number of textures on a particular texture stack
|
2020-06-23 19:05:42 +00:00
|
|
|
unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial *pMat, C_ENUM aiTextureType type) {
|
|
|
|
ai_assert(pMat != nullptr);
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2016-11-03 22:29:03 +00:00
|
|
|
// Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again)
|
2015-05-19 03:57:13 +00:00
|
|
|
unsigned int max = 0;
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *prop = pMat->mProperties[i];
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (prop /* just a sanity check ... */
|
|
|
|
&& 0 == strcmp(prop->mKey.data, _AI_MATKEY_TEXTURE_BASE) && static_cast<aiTextureType>(prop->mSemantic) == type) {
|
2015-05-19 03:52:10 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
max = std::max(max, prop->mIndex + 1);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return max;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
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);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// Get the path to the texture
|
2020-06-23 19:05:42 +00:00
|
|
|
if (AI_SUCCESS != aiGetMaterialString(mat, AI_MATKEY_TEXTURE(type, index), path)) {
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_FAILURE;
|
|
|
|
}
|
2018-07-25 13:11:24 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// Determine mapping type
|
2018-06-01 09:20:16 +00:00
|
|
|
int mapping_ = static_cast<int>(aiTextureMapping_UV);
|
2020-06-23 19:05:42 +00:00
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_MAPPING(type, index), &mapping_);
|
2018-06-01 09:20:16 +00:00
|
|
|
aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
|
2015-05-19 03:57:13 +00:00
|
|
|
if (_mapping)
|
|
|
|
*_mapping = mapping;
|
|
|
|
|
|
|
|
// Get UV index
|
2020-06-23 19:05:42 +00:00
|
|
|
if (aiTextureMapping_UV == mapping && uvindex) {
|
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_UVWSRC(type, index), (int *)uvindex);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
// Get blend factor
|
2020-06-23 19:05:42 +00:00
|
|
|
if (blend) {
|
|
|
|
aiGetMaterialFloat(mat, AI_MATKEY_TEXBLEND(type, index), blend);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
// Get texture operation
|
2020-06-23 19:05:42 +00:00
|
|
|
if (op) {
|
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_TEXOP(type, index), (int *)op);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
// Get texture mapping modes
|
2020-06-23 19:05:42 +00:00
|
|
|
if (mapmode) {
|
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(type, index), (int *)&mapmode[0]);
|
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(type, index), (int *)&mapmode[1]);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
// Get texture flags
|
2020-06-23 19:05:42 +00:00
|
|
|
if (flags) {
|
|
|
|
aiGetMaterialInteger(mat, AI_MATKEY_TEXFLAGS(type, index), (int *)flags);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2018-07-25 13:11:24 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_SUCCESS;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
2016-11-03 22:29:03 +00:00
|
|
|
static const unsigned int DefaultNumAllocated = 5;
|
|
|
|
|
2015-05-19 03:48:29 +00:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Construction. Actually the one and only way to get an aiMaterial instance
|
2020-06-23 19:05:42 +00:00
|
|
|
aiMaterial::aiMaterial() :
|
|
|
|
mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
|
2015-05-19 03:57:13 +00:00
|
|
|
// Allocate 5 entries by default
|
2020-06-23 19:05:42 +00:00
|
|
|
mProperties = new aiMaterialProperty *[DefaultNumAllocated];
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
aiMaterial::~aiMaterial() {
|
2015-05-19 03:57:13 +00:00
|
|
|
Clear();
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
delete[] mProperties;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 13:11:24 +00:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-11-10 11:50:17 +00:00
|
|
|
aiString aiMaterial::GetName() const {
|
2018-07-25 13:11:24 +00:00
|
|
|
aiString name;
|
|
|
|
Get(AI_MATKEY_NAME, name);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2015-05-19 03:48:29 +00:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
void aiMaterial::Clear() {
|
|
|
|
for (unsigned int i = 0; i < mNumProperties; ++i) {
|
2015-05-19 03:57:13 +00:00
|
|
|
// delete this entry
|
2020-06-23 19:05:42 +00:00
|
|
|
delete mProperties[i];
|
2015-05-19 03:57:13 +00:00
|
|
|
AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
|
|
|
|
}
|
|
|
|
mNumProperties = 0;
|
|
|
|
|
|
|
|
// The array remains allocated, we just invalidated its contents
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
aiReturn aiMaterial::RemoveProperty(const char *pKey, unsigned int type, unsigned int index) {
|
|
|
|
ai_assert(nullptr != pKey);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int i = 0; i < mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *prop = mProperties[i];
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (prop && !strcmp(prop->mKey.data, pKey) &&
|
|
|
|
prop->mSemantic == type && prop->mIndex == index) {
|
2015-05-19 03:57:13 +00:00
|
|
|
// Delete this entry
|
|
|
|
delete mProperties[i];
|
|
|
|
|
|
|
|
// collapse the array behind --.
|
|
|
|
--mNumProperties;
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int a = i; a < mNumProperties; ++a) {
|
|
|
|
mProperties[a] = mProperties[a + 1];
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
return AI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return AI_FAILURE;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
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;
|
2017-07-18 17:02:08 +00:00
|
|
|
}
|
2018-07-25 13:11:24 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// first search the list whether there is already an entry with this key
|
2020-06-23 19:05:42 +00:00
|
|
|
unsigned int iOutIndex(UINT_MAX);
|
|
|
|
for (unsigned int i = 0; i < mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *prop(mProperties[i]);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
|
|
|
|
prop->mSemantic == type && prop->mIndex == index) {
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
delete mProperties[i];
|
|
|
|
iOutIndex = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate a new material property
|
2023-06-02 14:36:19 +00:00
|
|
|
std::unique_ptr<aiMaterialProperty> pcNew(new aiMaterialProperty());
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// .. and fill it
|
|
|
|
pcNew->mType = pType;
|
|
|
|
pcNew->mSemantic = type;
|
|
|
|
pcNew->mIndex = index;
|
|
|
|
|
|
|
|
pcNew->mDataLength = pSizeInBytes;
|
|
|
|
pcNew->mData = new char[pSizeInBytes];
|
2020-06-23 19:05:42 +00:00
|
|
|
memcpy(pcNew->mData, pInput, pSizeInBytes);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));
|
|
|
|
ai_assert(MAXLEN > pcNew->mKey.length);
|
|
|
|
strcpy(pcNew->mKey.data, pKey);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (UINT_MAX != iOutIndex) {
|
2023-06-02 14:36:19 +00:00
|
|
|
mProperties[iOutIndex] = pcNew.release();
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resize the array ... double the storage allocated
|
2020-06-23 19:05:42 +00:00
|
|
|
if (mNumProperties == mNumAllocated) {
|
2015-05-19 03:57:13 +00:00
|
|
|
const unsigned int iOld = mNumAllocated;
|
|
|
|
mNumAllocated *= 2;
|
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
aiMaterialProperty **ppTemp;
|
2015-05-19 03:57:13 +00:00
|
|
|
try {
|
2020-06-23 19:05:42 +00:00
|
|
|
ppTemp = new aiMaterialProperty *[mNumAllocated];
|
|
|
|
} catch (std::bad_alloc &) {
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// just copy all items over; then replace the old array
|
2020-06-23 19:05:42 +00:00
|
|
|
memcpy(ppTemp, mProperties, iOld * sizeof(void *));
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
delete[] mProperties;
|
|
|
|
mProperties = ppTemp;
|
|
|
|
}
|
|
|
|
// push back ...
|
2023-06-02 14:36:19 +00:00
|
|
|
mProperties[mNumProperties++] = pcNew.release();
|
2018-07-25 13:11:24 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
return AI_SUCCESS;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
aiReturn aiMaterial::AddProperty(const aiString *pInput,
|
|
|
|
const char *pKey,
|
|
|
|
unsigned int type,
|
|
|
|
unsigned int index) {
|
|
|
|
ai_assert(sizeof(ai_uint32) == 4);
|
2015-05-19 03:57:13 +00:00
|
|
|
return AddBinaryProperty(pInput,
|
2020-06-23 19:05:42 +00:00
|
|
|
static_cast<unsigned int>(pInput->length + 1 + 4),
|
|
|
|
pKey,
|
|
|
|
type,
|
|
|
|
index,
|
|
|
|
aiPTI_String);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-06-23 19:05:42 +00:00
|
|
|
uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
|
2015-05-19 03:57:13 +00:00
|
|
|
uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *prop;
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// Exclude all properties whose first character is '?' from the hash
|
|
|
|
// See doc for aiMaterialProperty.
|
2020-06-23 19:05:42 +00:00
|
|
|
prop = mat->mProperties[i];
|
|
|
|
if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
|
|
|
|
hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// Combine the semantic and the index with the hash
|
2020-06-23 19:05:42 +00:00
|
|
|
hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
|
|
|
|
hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return hash;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-08-30 13:59:17 +00:00
|
|
|
void aiMaterial::CopyPropertyList(aiMaterial *const pcDest,
|
2020-06-23 19:05:42 +00:00
|
|
|
const aiMaterial *pcSrc) {
|
|
|
|
ai_assert(nullptr != pcDest);
|
|
|
|
ai_assert(nullptr != pcSrc);
|
2021-08-30 13:59:17 +00:00
|
|
|
ai_assert(pcDest->mNumProperties <= pcDest->mNumAllocated);
|
|
|
|
ai_assert(pcSrc->mNumProperties <= pcSrc->mNumAllocated);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2021-08-30 13:59:17 +00:00
|
|
|
const unsigned int iOldNum = pcDest->mNumProperties;
|
2015-05-19 03:57:13 +00:00
|
|
|
pcDest->mNumAllocated += pcSrc->mNumAllocated;
|
|
|
|
pcDest->mNumProperties += pcSrc->mNumProperties;
|
|
|
|
|
2021-08-30 13:59:17 +00:00
|
|
|
const unsigned int numAllocated = pcDest->mNumAllocated;
|
2020-06-23 19:05:42 +00:00
|
|
|
aiMaterialProperty **pcOld = pcDest->mProperties;
|
2021-08-30 13:59:17 +00:00
|
|
|
pcDest->mProperties = new aiMaterialProperty *[numAllocated];
|
|
|
|
|
|
|
|
ai_assert(!iOldNum || pcOld);
|
|
|
|
ai_assert(iOldNum < numAllocated);
|
2015-05-19 03:57:13 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (iOldNum && pcOld) {
|
|
|
|
for (unsigned int i = 0; i < iOldNum; ++i) {
|
2015-05-19 03:57:13 +00:00
|
|
|
pcDest->mProperties[i] = pcOld[i];
|
|
|
|
}
|
|
|
|
}
|
2016-01-16 21:51:18 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
if (pcOld) {
|
2016-11-03 22:29:03 +00:00
|
|
|
delete[] pcOld;
|
|
|
|
}
|
2016-01-16 21:51:18 +00:00
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
for (unsigned int i = iOldNum; i < pcDest->mNumProperties; ++i) {
|
|
|
|
aiMaterialProperty *propSrc = pcSrc->mProperties[i];
|
2015-05-19 03:57:13 +00:00
|
|
|
|
|
|
|
// search whether we have already a property with this name -> if yes, overwrite it
|
2020-06-23 19:05:42 +00:00
|
|
|
aiMaterialProperty *prop;
|
|
|
|
for (unsigned int q = 0; q < iOldNum; ++q) {
|
2015-05-19 03:57:13 +00:00
|
|
|
prop = pcDest->mProperties[q];
|
2020-06-23 19:05:42 +00:00
|
|
|
if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic && prop->mIndex == propSrc->mIndex) {
|
2015-05-19 03:57:13 +00:00
|
|
|
delete prop;
|
|
|
|
|
|
|
|
// collapse the whole array ...
|
2020-06-23 19:05:42 +00:00
|
|
|
memmove(&pcDest->mProperties[q], &pcDest->mProperties[q + 1], i - q);
|
2015-05-19 03:57:13 +00:00
|
|
|
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];
|
2020-06-23 19:05:42 +00:00
|
|
|
memcpy(prop->mData, propSrc->mData, prop->mDataLength);
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|