MD5
- added some extra validations to prevent unwanted crashes - fixed stand-alone loading of MD5ANIM files - MD5CAMERA working very well now ... JoinIdenticalVertices - an exception case where multiple vertices with the same position are assigned to different bones is handled now -> no crash anymore SkeletonMeshBuilder - proper material naming - two-sided flag is set for material - enforcing 'rahd' per-face normal vectors for better visual appearance ValidateDataStructure - code cleanup MaterialSystem - code cleanup LimitBoneWeights - code cleanup git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@364 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
ddbb8ab856
commit
de50bb915b
|
@ -145,19 +145,17 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
float posEpsilonSqr;
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
if (shared)
|
||||
{
|
||||
if (shared) {
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf) {
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilonSqr = blubb.second;
|
||||
vertexFinder = &blubb.first;posEpsilonSqr = blubb.second;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder) {
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilonSqr = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
|
||||
|
@ -360,7 +358,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
|
||||
// adjust bone vertex weights.
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
||||
for( int a = 0; a < (int)pMesh->mNumBones; a++)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
std::vector<aiVertexWeight> newWeights;
|
||||
|
@ -379,14 +377,38 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
}
|
||||
|
||||
// there should be some. At least I think there should be some
|
||||
ai_assert( newWeights.size() > 0);
|
||||
if (newWeights.size() > 0) {
|
||||
// kill the old and replace them with the translated weights
|
||||
delete [] bone->mWeights;
|
||||
bone->mNumWeights = (unsigned int)newWeights.size();
|
||||
|
||||
// kill the old and replace them with the translated weights
|
||||
delete [] bone->mWeights;
|
||||
bone->mNumWeights = (unsigned int)newWeights.size();
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
|
||||
}
|
||||
else {
|
||||
|
||||
/* NOTE:
|
||||
*
|
||||
* In the algorithm above we're assuming that there are no vertices
|
||||
* with a different bone weight setup at the same position. That wouldn't
|
||||
* make sense, but it is not absolutely impossible. SkeletonMeshBuilder
|
||||
* for example generates such input data if two skeleton points
|
||||
* share the same position. Again this doesn't make sense but is
|
||||
* reality for some model formats (MD5 for example uses these special
|
||||
* nodes as attachment tags for its weapons).
|
||||
*
|
||||
* Then it is possible that a bone has no weights anymore .... as a quick
|
||||
* workaround, we're just removing these bones. If they're animated,
|
||||
* model geometry might be modified but at least there's no risk of a crash.
|
||||
*/
|
||||
delete bone;
|
||||
--pMesh->mNumBones;
|
||||
for (unsigned int n = a; n < pMesh->mNumBones; ++n)
|
||||
pMesh->mBones[n] = pMesh->mBones[n+1];
|
||||
|
||||
--a;
|
||||
DefaultLogger::get()->warn("Removing bone -> no weights remaining");
|
||||
}
|
||||
}
|
||||
return pMesh->mNumVertices;
|
||||
}
|
||||
|
|
|
@ -181,12 +181,9 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
|||
::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
||||
}
|
||||
|
||||
if (bChanged)
|
||||
{
|
||||
// the number of new bones is smaller than before, so we can
|
||||
// reuse the old array, too.
|
||||
aiBone** ppcCur = pMesh->mBones;
|
||||
aiBone** ppcSrc = ppcCur;
|
||||
if (bChanged) {
|
||||
// the number of new bones is smaller than before, so we can reuse the old array
|
||||
aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur;
|
||||
|
||||
for (std::vector<bool>::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) {
|
||||
if (*iter) {
|
||||
|
|
|
@ -198,12 +198,12 @@ void MD5Importer::MakeDataUnique (MD5::MeshDesc& meshSrc)
|
|||
const unsigned int guess = (unsigned int)(fWeightsPerVert*iNewNum);
|
||||
meshSrc.mWeights.reserve(guess + (guess >> 3)); // + 12.5% as buffer
|
||||
|
||||
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(),iterEnd = meshSrc.mFaces.end();
|
||||
iter != iterEnd;++iter)
|
||||
{
|
||||
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(),iterEnd = meshSrc.mFaces.end();iter != iterEnd;++iter){
|
||||
const aiFace& face = *iter;
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < 3;++i) {
|
||||
if (face.mIndices[0] >= meshSrc.mVertices.size())
|
||||
throw new ImportErrorException("MD5MESH: Invalid vertex index");
|
||||
|
||||
if (abHad[face.mIndices[i]]) {
|
||||
// generate a new vertex
|
||||
meshSrc.mVertices[iNewIndex] = meshSrc.mVertices[face.mIndices[i]];
|
||||
|
@ -445,6 +445,9 @@ void MD5Importer::LoadMD5MeshFile ()
|
|||
// process bone weights
|
||||
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w)
|
||||
{
|
||||
if (w >= meshSrc.mWeights.size())
|
||||
throw new ImportErrorException("MD5MESH: Invalid weight index");
|
||||
|
||||
MD5::WeightDesc& desc = meshSrc.mWeights[w];
|
||||
if ( desc.mWeight < AI_MD5_WEIGHT_EPSILON && desc.mWeight >= -AI_MD5_WEIGHT_EPSILON)
|
||||
continue;
|
||||
|
@ -532,7 +535,6 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
DefaultLogger::get()->warn("Failed to read MD5ANIM file: " + pFile);
|
||||
return;
|
||||
}
|
||||
bHadMD5Anim = true;
|
||||
LoadFileIntoMemory(file.get());
|
||||
|
||||
// parse the basic file structure
|
||||
|
@ -542,7 +544,14 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
MD5::MD5AnimParser animParser(parser.mSections);
|
||||
|
||||
// generate and fill the output animation
|
||||
if (!animParser.mAnimatedBones.empty()) {
|
||||
if (animParser.mAnimatedBones.empty() || animParser.mFrames.empty() ||
|
||||
animParser.mBaseFrames.size() != animParser.mAnimatedBones.size()) {
|
||||
|
||||
DefaultLogger::get()->error("MD5ANIM: No frames or animated bones loaded");
|
||||
}
|
||||
else {
|
||||
bHadMD5Anim = true;
|
||||
|
||||
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations = 1];
|
||||
aiAnimation* anim = pScene->mAnimations[0] = new aiAnimation();
|
||||
anim->mNumChannels = (unsigned int)animParser.mAnimatedBones.size();
|
||||
|
@ -552,9 +561,8 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
node->mNodeName = aiString( animParser.mAnimatedBones[i].mName );
|
||||
|
||||
// allocate storage for the keyframes
|
||||
node->mNumPositionKeys = node->mNumRotationKeys = (unsigned int)animParser.mFrames.size();
|
||||
node->mPositionKeys = new aiVectorKey[node->mNumPositionKeys];
|
||||
node->mRotationKeys = new aiQuatKey[node->mNumPositionKeys];
|
||||
node->mPositionKeys = new aiVectorKey[animParser.mFrames.size()];
|
||||
node->mRotationKeys = new aiQuatKey[animParser.mFrames.size()];
|
||||
}
|
||||
|
||||
// 1 tick == 1 frame
|
||||
|
@ -562,23 +570,27 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
|
||||
for (FrameList::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end();iter != iterEnd;++iter){
|
||||
double dTime = (double)(*iter).iIndex;
|
||||
if (!(*iter).mValues.empty())
|
||||
aiNodeAnim** pcAnimNode = anim->mChannels;
|
||||
if (!(*iter).mValues.empty() || iter == animParser.mFrames.begin()) /* be sure we have at least one frame */
|
||||
{
|
||||
// now process all values in there ... read all joints
|
||||
aiNodeAnim** pcAnimNode = anim->mChannels;
|
||||
MD5::BaseFrameDesc* pcBaseFrame = &animParser.mBaseFrames[0];
|
||||
for (AnimBoneList::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end();++iter2,
|
||||
++pcAnimNode,++pcBaseFrame)
|
||||
{
|
||||
const float* fpCur;
|
||||
if((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {
|
||||
DefaultLogger::get()->error("MD5: Keyframe index is out of range");
|
||||
continue;
|
||||
}
|
||||
const float* fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
|
||||
|
||||
// Allow for empty frames
|
||||
if ((*iter2).iFlags != 0) {
|
||||
throw new ImportErrorException("MD5: Keyframe index is out of range");
|
||||
}
|
||||
}
|
||||
else fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
|
||||
aiNodeAnim* pcCurAnimBone = *pcAnimNode;
|
||||
aiVectorKey* vKey = pcCurAnimBone->mPositionKeys++;
|
||||
aiQuatKey* qKey = pcCurAnimBone->mRotationKeys++;
|
||||
|
||||
aiVectorKey* vKey = &pcCurAnimBone->mPositionKeys[pcCurAnimBone->mNumPositionKeys++];
|
||||
aiQuatKey* qKey = &pcCurAnimBone->mRotationKeys [pcCurAnimBone->mNumRotationKeys++];
|
||||
aiVector3D vTemp;
|
||||
|
||||
// translational component
|
||||
|
@ -587,7 +599,7 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
vKey->mValue[i] = *fpCur++;
|
||||
else vKey->mValue[i] = pcBaseFrame->vPositionXYZ[i];
|
||||
}
|
||||
|
||||
|
||||
// orientation component
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
if ((*iter2).iFlags & (8u << i))
|
||||
|
@ -596,26 +608,14 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
}
|
||||
|
||||
MD5::ConvertQuaternion(vTemp, qKey->mValue);
|
||||
|
||||
aiMatrix4x4 m;
|
||||
aiMatrix4x4::Translation(vKey->mValue,m);
|
||||
m = m*aiMatrix4x4( qKey->mValue.GetMatrix() );
|
||||
m.DecomposeNoScaling(qKey->mValue,vKey->mValue);
|
||||
|
||||
qKey->mTime = vKey->mTime = dTime;
|
||||
}
|
||||
}
|
||||
|
||||
// compute the duration of the animation
|
||||
anim->mDuration = std::max(dTime,anim->mDuration);
|
||||
}
|
||||
|
||||
// undo our offset computations
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
aiNodeAnim* node = anim->mChannels[i];
|
||||
node->mPositionKeys -= node->mNumPositionKeys;
|
||||
node->mRotationKeys -= node->mNumPositionKeys;
|
||||
}
|
||||
|
||||
// If we didn't build the hierarchy yet (== we didn't load a MD5MESH),
|
||||
// construct it now from the data given in the MD5ANIM.
|
||||
if (!pScene->mRootNode) {
|
||||
|
@ -629,7 +629,6 @@ void MD5Importer::LoadMD5AnimFile ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete the file again
|
||||
UnloadFileFromMemory();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ 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 "AssimpPCH.h"
|
||||
#include "Hash.h"
|
||||
|
||||
|
@ -55,12 +59,17 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
|
|||
ai_assert (pKey != NULL);
|
||||
ai_assert (pPropOut != NULL);
|
||||
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i)
|
||||
{
|
||||
/* Just search for a property with exactly this name ..
|
||||
* could be improved by hashing, but it's possibly
|
||||
* no worth the effort.
|
||||
*/
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
|
||||
if (prop && !::strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index)
|
||||
if (prop /* just for safety ... */
|
||||
&& 0 == ::strcmp( prop->mKey.data, pKey )
|
||||
&& (0xffffffff == type || prop->mSemantic == type) /* 0xffffffff is a wildcard */
|
||||
&& (0xffffffff == index || prop->mIndex == index))
|
||||
{
|
||||
*pPropOut = pMat->mProperties[i];
|
||||
return AI_SUCCESS;
|
||||
|
@ -79,50 +88,40 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
|
|||
float* pOut,
|
||||
unsigned int* pMax)
|
||||
{
|
||||
ai_assert (pMat != NULL);
|
||||
ai_assert (pKey != NULL);
|
||||
ai_assert (pOut != NULL);
|
||||
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop);
|
||||
if (!prop)
|
||||
return AI_FAILURE;
|
||||
|
||||
if (prop && !::strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index)
|
||||
{
|
||||
// data is given in floats, simply copy it
|
||||
if( aiPTI_Float == pMat->mProperties[i]->mType ||
|
||||
aiPTI_Buffer == pMat->mProperties[i]->mType)
|
||||
{
|
||||
unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
|
||||
// data is given in floats, simply copy it
|
||||
if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
|
||||
unsigned int iWrite = prop->mDataLength / sizeof(float);
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (float));
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
::memcpy (pOut, prop->mData, iWrite * sizeof (float));
|
||||
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// data is given in ints, convert to float
|
||||
else if( aiPTI_Integer == pMat->mProperties[i]->mType)
|
||||
{
|
||||
unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(int);
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
for (unsigned int a = 0; a < iWrite;++a)
|
||||
{
|
||||
pOut[a] = (float) ((int*)pMat->mProperties[i]->mData)[a];
|
||||
}
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// it is a string ... no way to read something out of this
|
||||
else
|
||||
{
|
||||
if (pMax)*pMax = 0;
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
return AI_FAILURE;
|
||||
// data is given in ints, convert to float
|
||||
else if( aiPTI_Integer == prop->mType) {
|
||||
unsigned int iWrite = prop->mDataLength / sizeof(int);
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = (float) ((int*)prop->mData)[a];
|
||||
}
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// it is a string ... no way to read something out of this
|
||||
else {
|
||||
DefaultLogger::get()->error("Material property" + std::string(pKey) + " was found, but is not an float array");
|
||||
if (pMax)*pMax = 0;
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -134,49 +133,39 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
|
|||
int* pOut,
|
||||
unsigned int* pMax)
|
||||
{
|
||||
ai_assert (pMat != NULL);
|
||||
ai_assert (pKey != NULL);
|
||||
ai_assert (pOut != NULL);
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
|
||||
if (prop && !::strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index)
|
||||
{
|
||||
// data is given in ints, simply copy it
|
||||
if( aiPTI_Integer == pMat->mProperties[i]->mType ||
|
||||
aiPTI_Buffer == pMat->mProperties[i]->mType)
|
||||
{
|
||||
unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(int);
|
||||
aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop);
|
||||
if (!prop)
|
||||
return AI_FAILURE;
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (int));
|
||||
// data is given in ints, simply copy it
|
||||
if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
|
||||
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// data is given in floats convert to int (lossy!)
|
||||
else if( aiPTI_Float == pMat->mProperties[i]->mType)
|
||||
{
|
||||
unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
|
||||
unsigned int iWrite = prop->mDataLength / sizeof(int);
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
for (unsigned int a = 0; a < iWrite;++a)
|
||||
{
|
||||
pOut[a] = (int) ((float*)pMat->mProperties[i]->mData)[a];
|
||||
}
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// it is a string ... no way to read something out of this
|
||||
else
|
||||
{
|
||||
if (pMax)*pMax = 0;
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
::memcpy (pOut, prop->mData, iWrite * sizeof (int));
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
return AI_FAILURE;
|
||||
// data is given in floats convert to int (lossy!)
|
||||
else if( aiPTI_Float == prop->mType) {
|
||||
unsigned int iWrite = prop->mDataLength / sizeof(float);
|
||||
|
||||
if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
for (unsigned int a = 0; a < iWrite;++a) {
|
||||
pOut[a] = (int) ((float*)prop->mData)[a];
|
||||
}
|
||||
if (pMax)*pMax = iWrite;
|
||||
}
|
||||
// it is a string ... no way to read something out of this
|
||||
else {
|
||||
DefaultLogger::get()->error("Material property" + std::string(pKey) + " was found, but is not an integer array");
|
||||
if (pMax)*pMax = 0;
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -184,14 +173,15 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
|
|||
aiReturn aiGetMaterialColor(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
unsigned int index,
|
||||
aiColor4D* pOut)
|
||||
{
|
||||
unsigned int iMax = 4;
|
||||
aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax);
|
||||
|
||||
// if no alpha channel is provided set it to 1.0 by default
|
||||
if (3 == iMax)pOut->a = 1.0f;
|
||||
// if no alpha channel is defined: set it to 1.0
|
||||
if (3 == iMax)
|
||||
pOut->a = 1.0f;
|
||||
return eRet;
|
||||
}
|
||||
|
||||
|
@ -200,31 +190,28 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
|
|||
aiReturn aiGetMaterialString(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
unsigned int index,
|
||||
aiString* pOut)
|
||||
{
|
||||
ai_assert (pMat != NULL);
|
||||
ai_assert (pKey != NULL);
|
||||
ai_assert (pOut != NULL);
|
||||
|
||||
for (unsigned int i = 0; i < pMat->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = pMat->mProperties[i];
|
||||
aiMaterialProperty* prop;
|
||||
aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop);
|
||||
if (!prop)
|
||||
return AI_FAILURE;
|
||||
|
||||
if (prop && !::strcmp( prop->mKey.data, pKey ) &&
|
||||
prop->mSemantic == type && prop->mIndex == index)
|
||||
{
|
||||
if( aiPTI_String == pMat->mProperties[i]->mType)
|
||||
{
|
||||
const aiString* pcSrc = (const aiString*)pMat->mProperties[i]->mData;
|
||||
::memcpy (pOut->data, pcSrc->data, (pOut->length = pcSrc->length)+1);
|
||||
}
|
||||
// Wrong type
|
||||
else return AI_FAILURE;
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
if( aiPTI_String == prop->mType) {
|
||||
|
||||
// WARN: There's not the whole string stored ..
|
||||
const aiString* pcSrc = (const aiString*)prop->mData;
|
||||
::memcpy (pOut->data, pcSrc->data, (pOut->length = pcSrc->length)+1);
|
||||
}
|
||||
return AI_FAILURE;
|
||||
// Wrong type
|
||||
else {
|
||||
DefaultLogger::get()->error("Material property" + std::string(pKey) + " was found, but is no string" );
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -246,8 +233,10 @@ MaterialHelper::~MaterialHelper()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
aiMaterial::~aiMaterial()
|
||||
{
|
||||
// This is safe: aiMaterial has a private constructor,
|
||||
// so instances must be created indirectly via MaterialHelper.
|
||||
// HACK (Aramis): This is safe: aiMaterial has a private constructor,
|
||||
// so instances must be created indirectly via MaterialHelper. We can't
|
||||
// use a virtual d'tor because we need to preserve binary compatibility
|
||||
// with good old C ...
|
||||
((MaterialHelper*)this)->_InternDestruct();
|
||||
}
|
||||
|
||||
|
@ -305,12 +294,12 @@ uint32_t MaterialHelper::ComputeHash(bool includeMatName /*= false*/)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn MaterialHelper::RemoveProperty (const char* pKey,unsigned int type,
|
||||
unsigned int index)
|
||||
unsigned int index
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != pKey);
|
||||
|
||||
for (unsigned int i = 0; i < mNumProperties;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mNumProperties;++i) {
|
||||
aiMaterialProperty* prop = mProperties[i];
|
||||
|
||||
if (prop && !::strcmp( prop->mKey.data, pKey ) &&
|
||||
|
@ -321,8 +310,7 @@ aiReturn MaterialHelper::RemoveProperty (const char* pKey,unsigned int type,
|
|||
|
||||
// collapse the array behind --.
|
||||
--mNumProperties;
|
||||
for (unsigned int a = i; a < mNumProperties;++a)
|
||||
{
|
||||
for (unsigned int a = i; a < mNumProperties;++a) {
|
||||
mProperties[a] = mProperties[a+1];
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
|
@ -338,24 +326,25 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiPropertyTypeInfo pType)
|
||||
aiPropertyTypeInfo pType
|
||||
)
|
||||
{
|
||||
ai_assert (pInput != NULL);
|
||||
ai_assert (pKey != NULL);
|
||||
ai_assert (0 != pSizeInBytes);
|
||||
|
||||
// first search the list whether there is already an entry
|
||||
// with this name.
|
||||
unsigned int iOutIndex = 0xFFFFFFFF;
|
||||
for (unsigned int i = 0; i < mNumProperties;++i)
|
||||
{
|
||||
// first search the list whether there is already an entry with this key
|
||||
unsigned int iOutIndex = 0xffffffff;
|
||||
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)
|
||||
if (prop /* just for safety */
|
||||
&& !::strcmp( prop->mKey.data, pKey )
|
||||
&& prop->mSemantic == type
|
||||
&& prop->mIndex == index)
|
||||
{
|
||||
// delete this entry
|
||||
delete this->mProperties[i];
|
||||
delete mProperties[i];
|
||||
iOutIndex = i;
|
||||
}
|
||||
}
|
||||
|
@ -376,21 +365,24 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
ai_assert ( MAXLEN > pcNew->mKey.length);
|
||||
::strcpy( pcNew->mKey.data, pKey );
|
||||
|
||||
if (0xFFFFFFFF != iOutIndex)
|
||||
{
|
||||
if (0xffffffff != iOutIndex) {
|
||||
mProperties[iOutIndex] = pcNew;
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// resize the array ... double the storage
|
||||
if (mNumProperties == mNumAllocated)
|
||||
{
|
||||
unsigned int iOld = mNumAllocated;
|
||||
// resize the array ... double the storage allocated
|
||||
if (mNumProperties == mNumAllocated) {
|
||||
const unsigned int iOld = mNumAllocated;
|
||||
mNumAllocated *= 2;
|
||||
|
||||
aiMaterialProperty** ppTemp = new aiMaterialProperty*[mNumAllocated];
|
||||
if (NULL == ppTemp)return AI_OUTOFMEMORY;
|
||||
aiMaterialProperty** ppTemp;
|
||||
try {
|
||||
ppTemp = new aiMaterialProperty*[mNumAllocated];
|
||||
} catch (std::bad_alloc&) {
|
||||
return AI_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
// just copy all items over; then replace the old array
|
||||
::memcpy (ppTemp,mProperties,iOld * sizeof(void*));
|
||||
|
||||
delete[] mProperties;
|
||||
|
@ -407,15 +399,20 @@ aiReturn MaterialHelper::AddProperty (const aiString* pInput,
|
|||
unsigned int type,
|
||||
unsigned int index)
|
||||
{
|
||||
// Fix ... don't keep the whole string buffer
|
||||
return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
|
||||
// We don't want to add the whole buffer ..
|
||||
return AddBinaryProperty(pInput,
|
||||
(unsigned int)pInput->length+1+
|
||||
(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
|
||||
pKey,type,index, aiPTI_String);
|
||||
pKey,
|
||||
type,
|
||||
index,
|
||||
aiPTI_String);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
|
||||
const MaterialHelper* pcSrc)
|
||||
const MaterialHelper* pcSrc
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != pcDest);
|
||||
ai_assert(NULL != pcSrc);
|
||||
|
@ -427,32 +424,28 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
|
|||
aiMaterialProperty** pcOld = pcDest->mProperties;
|
||||
pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated];
|
||||
|
||||
if (iOldNum && pcOld)
|
||||
{
|
||||
if (iOldNum && pcOld) {
|
||||
for (unsigned int i = 0; i < iOldNum;++i)
|
||||
pcDest->mProperties[i] = pcOld[i];
|
||||
|
||||
delete[] pcOld;
|
||||
}
|
||||
for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i)
|
||||
{
|
||||
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 we overwrite the old one)
|
||||
// search whether we have already a property with this name -> if yes, overwrite it
|
||||
aiMaterialProperty* prop;
|
||||
for (unsigned int q = 0; q < iOldNum;++q)
|
||||
{
|
||||
for (unsigned int q = 0; q < iOldNum;++q) {
|
||||
prop = pcDest->mProperties[q];
|
||||
if (prop && prop->mKey == propSrc->mKey &&
|
||||
prop->mSemantic == propSrc->mSemantic && prop->mIndex == propSrc->mIndex)
|
||||
{
|
||||
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--;
|
||||
i--;pcDest->mNumProperties--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,7 +509,6 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
|
|||
if (flags){
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags);
|
||||
}
|
||||
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,9 +65,9 @@ SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root)
|
|||
pScene->mMeshes = new aiMesh*[1];
|
||||
pScene->mMeshes[0] = CreateMesh();
|
||||
// and install it at the root node
|
||||
pScene->mRootNode->mNumMeshes = 1;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
pScene->mRootNode->mMeshes[0] = 0;
|
||||
root->mNumMeshes = 1;
|
||||
root->mMeshes = new unsigned int[1];
|
||||
root->mMeshes[0] = 0;
|
||||
|
||||
// create a dummy material for the mesh
|
||||
pScene->mNumMaterials = 1;
|
||||
|
@ -207,6 +207,8 @@ aiMesh* SkeletonMeshBuilder::CreateMesh()
|
|||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
|
||||
|
||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
// add faces
|
||||
mesh->mNumFaces = mFaces.size();
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
|
@ -219,6 +221,19 @@ aiMesh* SkeletonMeshBuilder::CreateMesh()
|
|||
outface.mIndices[0] = inface.mIndices[0];
|
||||
outface.mIndices[1] = inface.mIndices[1];
|
||||
outface.mIndices[2] = inface.mIndices[2];
|
||||
|
||||
// Compute per-face normals ... we don't want the bones to be
|
||||
// smoothed ... they're built to visualize the skeleton,
|
||||
// so it's good if there's a visual difference to the rest
|
||||
// of the geometry
|
||||
aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
|
||||
(mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
|
||||
|
||||
if (nor.Length() < 1e-5f) /* ensure that FindInvalidData won't remove us ...*/
|
||||
nor = aiVector3D(1.f,0.f,0.f);
|
||||
|
||||
for (unsigned int n = 0; n < 3; ++n)
|
||||
mesh->mNormals[inface.mIndices[n]] = nor;
|
||||
}
|
||||
|
||||
// add the bones
|
||||
|
@ -239,8 +254,12 @@ aiMaterial* SkeletonMeshBuilder::CreateMaterial()
|
|||
Assimp::MaterialHelper* matHelper = new Assimp::MaterialHelper;
|
||||
|
||||
// Name
|
||||
aiString matName( std::string( "Material"));
|
||||
aiString matName( std::string( "SkeletonMaterial"));
|
||||
matHelper->AddProperty( &matName, AI_MATKEY_NAME);
|
||||
|
||||
// Prevent backface culling
|
||||
const int no_cull = 1;
|
||||
matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED);
|
||||
|
||||
return matHelper;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ValidateDataStructure.h"
|
||||
#include "BaseImporter.h"
|
||||
#include "fast_atof.h"
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
// CRT headers
|
||||
#include <stdarg.h>
|
||||
|
@ -59,16 +60,12 @@ using namespace Assimp;
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ValidateDSProcess::ValidateDSProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
ValidateDSProcess::~ValidateDSProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
|
@ -550,43 +547,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
|
|||
void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
|
||||
aiTextureType type)
|
||||
{
|
||||
const char* szType = NULL;
|
||||
switch (type)
|
||||
{
|
||||
case aiTextureType_DIFFUSE:
|
||||
szType = "Diffuse";
|
||||
break;
|
||||
|
||||
case aiTextureType_SPECULAR:
|
||||
szType = "Specular";
|
||||
break;
|
||||
|
||||
case aiTextureType_AMBIENT:
|
||||
szType = "Ambient";
|
||||
break;
|
||||
|
||||
case aiTextureType_EMISSIVE:
|
||||
szType = "Emissive";
|
||||
break;
|
||||
|
||||
case aiTextureType_OPACITY:
|
||||
szType = "Opacity";
|
||||
break;
|
||||
|
||||
case aiTextureType_SHININESS:
|
||||
szType = "Shininess";
|
||||
break;
|
||||
|
||||
case aiTextureType_NORMALS:
|
||||
szType = "Normals";
|
||||
break;
|
||||
|
||||
case aiTextureType_HEIGHT:
|
||||
szType = "Height";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
const char* szType = TextureTypeToString(type);
|
||||
|
||||
// ****************************************************************************
|
||||
// Search all keys of the material ...
|
||||
|
@ -835,7 +796,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
|
|||
for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys;++i)
|
||||
{
|
||||
// ScenePreprocessor will compute the duration if still teh default value
|
||||
if (-1. != pAnimation->mDuration && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration)
|
||||
if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration)
|
||||
{
|
||||
ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger "
|
||||
"than aiAnimation::mDuration (which is %.5f)",i,
|
||||
|
@ -863,7 +824,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
|
|||
double dLast = -10e10;
|
||||
for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys;++i)
|
||||
{
|
||||
if (-1. != pAnimation->mDuration && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration)
|
||||
if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration)
|
||||
{
|
||||
ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger "
|
||||
"than aiAnimation::mDuration (which is %.5f)",i,
|
||||
|
@ -890,7 +851,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
|
|||
double dLast = -10e10;
|
||||
for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys;++i)
|
||||
{
|
||||
if (-1. != pAnimation->mDuration && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration)
|
||||
if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration)
|
||||
{
|
||||
ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger "
|
||||
"than aiAnimation::mDuration (which is %.5f)",i,
|
||||
|
|
Loading…
Reference in New Issue