From 32342857d8b8e2e9705916b1bb06bfdf085eaf8d Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sun, 16 Nov 2008 21:56:45 +0000 Subject: [PATCH] ASE and 3DS cleanup - face ordering improved. Further work on target camera animation support in both loaders. Some general animation problems in both formats remaining, too. Added GenUVCoords and TransformUV-steps (see ML). The latter has been fully implemented, test file are there. GenUVCoords is a dummy for the moment. Boost workaround for shared_array. Further work on the documentation. Updated material system (see ML). Bug fixing in the AC loader, lights are now supported, too. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@243 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/3DSConverter.cpp | 445 +++---- code/3DSHelper.h | 43 +- code/3DSLoader.cpp | 61 +- code/3DSLoader.h | 4 - code/ACLoader.cpp | 51 +- code/ACLoader.h | 3 + code/ASELoader.cpp | 365 +++--- code/ASEParser.cpp | 61 +- code/ASEParser.h | 7 +- code/AssimpPCH.h | 2 + code/BaseImporter.cpp | 2 +- code/ComputeUVMappingProcess.cpp | 175 +++ code/ComputeUVMappingProcess.h | 125 ++ code/ConvertToLHProcess.cpp | 23 + code/ConvertToLHProcess.h | 7 + code/FindDegenerates.cpp | 1 + code/FindInvalidDataProcess.cpp | 30 +- code/Hash.h | 1 + code/IRRMeshLoader.cpp | 60 +- code/Importer.cpp | 39 +- code/LWOBLoader.cpp | 5 +- code/LWOFileData.h | 37 +- code/LWOLoader.cpp | 149 ++- code/LWOLoader.h | 8 +- code/LWOMaterial.cpp | 166 ++- code/MDLFileData.h | 2 +- code/MaterialSystem.cpp | 492 ++++---- code/MaterialSystem.h | 56 +- code/ProcessHelper.h | 48 + code/RemoveRedundantMaterials.cpp | 23 +- code/TargetAnimation.cpp | 24 +- code/TargetAnimation.h | 24 +- code/TextureTransform.cpp | 1031 ++++++++-------- code/TextureTransform.h | 206 ++-- code/ValidateDataStructure.cpp | 212 ++-- code/ValidateDataStructure.h | 5 +- code/XFileImporter.cpp | 23 +- code/makefile | 5 +- code/makefile.mingw | 6 +- include/BoostWorkaround/boost/scoped_array.h | 85 ++ include/BoostWorkaround/boost/scoped_ptr.hpp | 19 +- include/aiCamera.h | 6 + include/aiConfig.h | 26 +- include/aiDefines.h | 2 + include/aiLight.h | 6 + include/aiMaterial.h | 1165 ++++++++++-------- include/aiMaterial.inl | 281 +++-- include/aiMatrix3x3.h | 18 +- include/aiMatrix3x3.inl | 21 + include/aiMesh.h | 17 + include/aiPostProcess.h | 27 +- include/aiTypes.h | 81 +- tools/assimp_view/Display.cpp | 126 +- tools/assimp_view/Material.cpp | 33 +- tools/assimp_view/Shaders.cpp | 18 + tools/assimp_view/assimp_view.cpp | 3 +- workspaces/vc8/assimp.vcproj | 36 +- 57 files changed, 3522 insertions(+), 2475 deletions(-) create mode 100644 code/ComputeUVMappingProcess.cpp create mode 100644 code/ComputeUVMappingProcess.h create mode 100644 include/BoostWorkaround/boost/scoped_array.h diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 8eabd9dd4..f2333de7a 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -46,7 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "3DSLoader.h" -#include "TextureTransform.h" #include "TargetAnimation.h" using namespace Assimp; @@ -159,41 +158,60 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) // Generate out unique verbose format representation void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) { - unsigned int iBase = 0; - // Allocate output storage std::vector vNew (sMesh.mFaces.size() * 3); - std::vector vNew2; - if (sMesh.mTexCoords.size())vNew2.resize(sMesh.mFaces.size() * 3); + std::vector vNew2; + if (sMesh.mTexCoords.size()) + vNew2.resize(sMesh.mFaces.size() * 3); - for (unsigned int i = 0; i < sMesh.mFaces.size();++i) + for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) { - uint32_t iTemp1,iTemp2; + D3DS::Face& face = sMesh.mFaces[i]; - // positions - vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[2]]; - iTemp1 = iBase++; - vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[1]]; - iTemp2 = iBase++; - vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[0]]; - - // texture coordinates - if (sMesh.mTexCoords.size()) + // Positions + for (unsigned int a = 0; a < 3;++a,++base) { - vNew2[iTemp1] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[2]]; - vNew2[iTemp2] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[1]]; - vNew2[iBase] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[0]]; - } + vNew[base] = sMesh.mPositions[face.mIndices[a]]; + if (sMesh.mTexCoords.size()) + vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; - sMesh.mFaces[i].mIndices[2] = iBase++; - sMesh.mFaces[i].mIndices[0] = iTemp1; - sMesh.mFaces[i].mIndices[1] = iTemp2; + face.mIndices[a] = base; + } } sMesh.mPositions = vNew; sMesh.mTexCoords = vNew2; return; } +// ------------------------------------------------------------------------------------------------ +void CopyTexture(MaterialHelper& mat, D3DS::Texture& texture, aiTextureType type) +{ + // Setup the texture name + aiString tex; + tex.Set( texture.mMapName); + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + + // Setup the texture blend factor + if (is_not_qnan(texture.mTextureBlend)) + mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + + // Setup the texture mapping mode + mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); + mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); + + // Mirroring - double the scaling values + if (texture.mMapMode == aiTextureMapMode_Mirror) + { + texture.mScaleU *= 2.f; + texture.mScaleV *= 2.f; + texture.mOffsetU /= 2.f; + texture.mOffsetV /= 2.f; + } + + // Setup texture UV transformations + mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); +} + // ------------------------------------------------------------------------------------------------ // Convert a 3DS material to an aiMaterial void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, @@ -207,12 +225,11 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, tex.Set( mBackgroundImage); mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); - // be sure this is only done for the first material + // Be sure this is only done for the first material mBackgroundImage = std::string(""); } - // At first add the base ambient color of the - // scene to the material + // At first add the base ambient color of the scene to the material oldMat.mAmbient.r += mClrAmbient.r; oldMat.mAmbient.g += mClrAmbient.g; oldMat.mAmbient.b += mClrAmbient.b; @@ -221,13 +238,13 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, name.Set( oldMat.mName); mat.AddProperty( &name, AI_MATKEY_NAME); - // material colors + // Material colors mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - // phong shininess and shininess strength + // Phong shininess and shininess strength if (D3DS::Discreet3DS::Phong == oldMat.mShading || D3DS::Discreet3DS::Metal == oldMat.mShading) { @@ -242,20 +259,20 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, } } - // opacity + // Opacity mat.AddProperty( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); - // bump height scaling + // Bump height scaling mat.AddProperty( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); - // two sided rendering? + // Two sided rendering? if (oldMat.mTwoSided) { int i = 1; mat.AddProperty(&i,1,AI_MATKEY_TWOSIDED); } - // shading mode + // Shading mode aiShadingMode eShading = aiShadingMode_NoShading; switch (oldMat.mShading) { @@ -263,8 +280,14 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, eShading = aiShadingMode_Flat; break; // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse (L dot N) shading + // assume it is simple lambertian diffuse shading case D3DS::Discreet3DS::Wire: + { + // Set the wireframe flag + unsigned int iWire = 1; + mat.AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); + } + case D3DS::Discreet3DS::Gouraud: eShading = aiShadingMode_Gouraud; break; @@ -283,112 +306,29 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, } mat.AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); - if (D3DS::Discreet3DS::Wire == oldMat.mShading) - { - // set the wireframe flag - unsigned int iWire = 1; - mat.AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - - // texture, if there is one // DIFFUSE texture if( oldMat.sTexDiffuse.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexDiffuse.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0)); + CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); - if (is_not_qnan(oldMat.sTexDiffuse.mTextureBlend)) - mat.AddProperty( &oldMat.sTexDiffuse.mTextureBlend, 1, AI_MATKEY_TEXBLEND_DIFFUSE(0)); - - if (aiTextureMapMode_Clamp != oldMat.sTexDiffuse.mMapMode) - { - int i = (int)oldMat.sTexSpecular.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0)); - } - } // SPECULAR texture if( oldMat.sTexSpecular.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexSpecular.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(0)); + CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); - if (is_not_qnan(oldMat.sTexSpecular.mTextureBlend)) - mat.AddProperty( &oldMat.sTexSpecular.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SPECULAR(0)); - - if (aiTextureMapMode_Clamp != oldMat.sTexSpecular.mMapMode) - { - int i = (int)oldMat.sTexSpecular.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_SPECULAR(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_SPECULAR(0)); - } - } // OPACITY texture if( oldMat.sTexOpacity.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexOpacity.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY(0)); + CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); - if (is_not_qnan(oldMat.sTexOpacity.mTextureBlend)) - mat.AddProperty( &oldMat.sTexOpacity.mTextureBlend, 1,AI_MATKEY_TEXBLEND_OPACITY(0)); - if (aiTextureMapMode_Clamp != oldMat.sTexOpacity.mMapMode) - { - int i = (int)oldMat.sTexOpacity.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_OPACITY(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_OPACITY(0)); - } - } // EMISSIVE texture if( oldMat.sTexEmissive.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexEmissive.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(0)); + CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); - if (is_not_qnan(oldMat.sTexEmissive.mTextureBlend)) - mat.AddProperty( &oldMat.sTexEmissive.mTextureBlend, 1, AI_MATKEY_TEXBLEND_EMISSIVE(0)); - if (aiTextureMapMode_Clamp != oldMat.sTexEmissive.mMapMode) - { - int i = (int)oldMat.sTexEmissive.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_EMISSIVE(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_EMISSIVE(0)); - } - } - // BUMP texturee + // BUMP texture if( oldMat.sTexBump.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexBump.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(0)); + CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); - if (is_not_qnan(oldMat.sTexBump.mTextureBlend)) - mat.AddProperty( &oldMat.sTexBump.mTextureBlend, 1, AI_MATKEY_TEXBLEND_HEIGHT(0)); - if (aiTextureMapMode_Clamp != oldMat.sTexBump.mMapMode) - { - int i = (int)oldMat.sTexBump.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_HEIGHT(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_HEIGHT(0)); - } - } // SHININESS texture if( oldMat.sTexShininess.mMapName.length() > 0) - { - aiString tex; - tex.Set( oldMat.sTexShininess.mMapName); - mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SHININESS(0)); - - if (is_not_qnan(oldMat.sTexShininess.mTextureBlend)) - mat.AddProperty( &oldMat.sTexShininess.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SHININESS(0)); - if (aiTextureMapMode_Clamp != oldMat.sTexShininess.mMapMode) - { - int i = (int)oldMat.sTexShininess.mMapMode; - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_U_SHININESS(0)); - mat.AddProperty(&i,1,AI_MATKEY_MAPPINGMODE_V_SHININESS(0)); - } - } + CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); // Store the name of the material itself, too if( oldMat.mName.length()) @@ -425,74 +365,51 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) // now generate submeshes for (unsigned int p = 0; p < mScene->mMaterials.size();++p) { - if (aiSplit[p].size() != 0) + if (aiSplit[p].size()) { - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + aiMesh* meshOut = new aiMesh(); + meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // be sure to setup the correct material index - p_pcOut->mMaterialIndex = p; + meshOut->mMaterialIndex = p; // use the color data as temporary storage - p_pcOut->mColors[0] = (aiColor4D*)(&*i); - avOutMeshes.push_back(p_pcOut); + meshOut->mColors[0] = (aiColor4D*)(&*i); + avOutMeshes.push_back(meshOut); // convert vertices - p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); - p_pcOut->mNumVertices = p_pcOut->mNumFaces*3; + meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); + meshOut->mNumVertices = meshOut->mNumFaces*3; // allocate enough storage for faces - p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; - iFaceCnt += p_pcOut->mNumFaces; - - if (p_pcOut->mNumVertices) - { - p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; - p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; - unsigned int iBase = 0; - - for (unsigned int q = 0; q < aiSplit[p].size();++q) - { - unsigned int iIndex = aiSplit[p][q]; - - p_pcOut->mFaces[q].mIndices = new unsigned int[3]; - p_pcOut->mFaces[q].mNumIndices = 3; - - p_pcOut->mFaces[q].mIndices[2] = iBase; - p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].mIndices[0]]; - p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[0]]; - - p_pcOut->mFaces[q].mIndices[1] = iBase; - p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].mIndices[1]]; - p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[1]]; - - p_pcOut->mFaces[q].mIndices[0] = iBase; - p_pcOut->mVertices[iBase] = (*i).mPositions[(*i).mFaces[iIndex].mIndices[2]]; - p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[2]]; - } - } - // convert texture coordinates + meshOut->mFaces = new aiFace[meshOut->mNumFaces]; + iFaceCnt += meshOut->mNumFaces; + + meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; + meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; if ((*i).mTexCoords.size()) { - p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices]; + meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; + } + for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) + { + register unsigned int index = aiSplit[p][q]; + aiFace& face = meshOut->mFaces[q]; - unsigned int iBase = 0; - for (unsigned int q = 0; q < aiSplit[p].size();++q) + face.mIndices = new unsigned int[3]; + face.mNumIndices = 3; + + for (unsigned int a = 0; a < 3;++a,++base) { - unsigned int iIndex2 = aiSplit[p][q]; + unsigned int idx = (*i).mFaces[index].mIndices[a]; + meshOut->mVertices[base] = (*i).mPositions[idx]; + meshOut->mNormals [base] = (*i).mNormals[idx]; - aiVector2D* pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[0]]; - p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f); + if ((*i).mTexCoords.size()) + meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; - pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[1]]; - p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f); - - pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[2]]; - p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f); + face.mIndices[a] = base; } - // apply texture coordinate scalings - TextureTransform::BakeScaleNOffset ( p_pcOut, &mScene->mMaterials[ - p_pcOut->mMaterialIndex] ); } } } @@ -508,20 +425,12 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) // We should have at least one face here if (!iFaceCnt) throw new ImportErrorException("No faces loaded. The mesh is empty"); - - // for each material in the scene we need to setup the UV source - // set for each texture - for (unsigned int a = 0; a < pcOut->mNumMaterials;++a) - { - TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &mScene->mMaterials[a] ); - } - return; } // ------------------------------------------------------------------------------------------------ // Add a node to the scenegraph and setup its final transformation -void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn, - aiMatrix4x4& absTrafo) +void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, + D3DS::Node* pcIn, aiMatrix4x4& absTrafo) { std::vector iArray; iArray.reserve(3); @@ -529,11 +438,12 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod aiMatrix4x4 abs; if (pcIn->mName == "$$$DUMMY") { - // Append the "real" name of the dummy to the string - pcIn->mName.append(pcIn->mDummyName); + // FIX: Append the "real" name of the dummy to the string + pcIn->mName = "Dummy." + pcIn->mDummyName; } else // if (pcIn->mName != "$$$DUMMY") { + // Find all meshes with the same name as the node for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) { const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; @@ -544,13 +454,10 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod } if (!iArray.empty()) { - // The matrix should be identical for all meshes with the same name. - // It HAS to be identical for all meshes ........ - aiMatrix4x4& mTrafo = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; - aiMatrix4x4 mInv = mTrafo; - if (!configSkipPivot) - mInv.Inverse(); - + // The matrix should be identical for all meshes with the + // same name. It HAS to be identical for all meshes ..... + aiMatrix4x4 mInv = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; + mInv.Inverse(); const aiVector3D& pivot = pcIn->vPivot; pcOut->mNumMeshes = (unsigned int)iArray.size(); @@ -560,31 +467,24 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod const unsigned int iIndex = iArray[i]; aiMesh* const mesh = pcSOut->mMeshes[iIndex]; - // Pivot point adjustment. + // Pivot point adjustment // See: http://www.zfx.info/DisplayThread.php?MID=235690#235690 const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; aiVector3D* pvCurrent = mesh->mVertices; - if(pivot.x || pivot.y || pivot.z && !configSkipPivot) + if(pivot.x || pivot.y || pivot.z) { - while (pvCurrent != pvEnd) + for (;pvCurrent != pvEnd;++pvCurrent) { *pvCurrent = mInv * (*pvCurrent); - pvCurrent->x -= pivot.x; - pvCurrent->y -= pivot.y; - pvCurrent->z -= pivot.z; - ++pvCurrent; + *pvCurrent -= pivot; } } else { - while (pvCurrent != pvEnd) - { + for (;pvCurrent != pvEnd;++pvCurrent) *pvCurrent = mInv * (*pvCurrent); - ++pvCurrent; - } } - // Setup the mesh index pcOut->mMeshes[i] = iIndex; } @@ -648,73 +548,82 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod } } - if (pcIn->aTargetPositionKeys.size() > 1) + //if (pcIn->aTargetPositionKeys.size() > 1) + //{ + // DefaultLogger::get()->debug("3DS: Converting target track ..."); + + // // Camera or spot light - need to convert the separate + // // target position channel to our representation + // TargetAnimationHelper helper; + + // if (pcIn->aPositionKeys.empty()) + // { + // // We can just pass zero here ... + // helper.SetFixedMainAnimationChannel(aiVector3D()); + // } + // else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); + // helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); + + // // Do the conversion + // std::vector distanceTrack; + // helper.Process(&distanceTrack); + + // // Now add a new node as child, name it .Target + // // and assign the distance track to it. This is that the + // // information where the target is and how it moves is + // // not lost + // D3DS::Node* nd = new D3DS::Node(); + // pcIn->push_back(nd); + + // nd->mName = pcIn->mName + ".Target"; + + // aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + // nda->mNodeName.Set(nd->mName); + + // nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); + // nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + // ::memcpy(nda->mPositionKeys,&distanceTrack[0], + // sizeof(aiVectorKey)*nda->mNumPositionKeys); + //} + + // Allocate a new nda, increment the nda index + aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); + nda->mNodeName.Set(pcIn->mName); + + // POSITION keys + if (pcIn->aPositionKeys.size() > 0) { - //DefaultLogger::get()->debug("3DS: Converting target track ..."); - - //// Camera or spot light - need to convert the separate - //// target position channel to our representation - //TargetAnimationHelper helper; - - //helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); - //helper.SetMainAnimationChannel(&pcIn->aPositionKeys); - - //// Do the conversion - //std::vector distanceTrack; - //helper.Process(&distanceTrack); - - //// Now add a new node as child, name it .Target - //// and assign the distance track to it. This is that the - //// information where the target is and how it moves is - //// not lost - //D3DS::Node* nd = new D3DS::Node(); - //pcIn->push_back(nd); - - //nd->mName = pcIn->mName + ".Target"; - - //aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - //nda->mNodeName.Set(nd->mName); - - //nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); - //nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - //::memcpy(nda->mPositionKeys,&distanceTrack[0], - // sizeof(aiVectorKey)*nda->mNumPositionKeys); + nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); + nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; + ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], + sizeof(aiVectorKey)*nda->mNumPositionKeys); } - // Just for safety ... we *should* have at least one track here - if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || - pcIn->aScalingKeys.size() > 1) + // ROTATION keys + if (pcIn->aRotationKeys.size() > 0) { - // Allocate a new nda, increment the nda index - aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); - nda->mNodeName.Set(pcIn->mName); + nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); + nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; - // POSITION keys - if (pcIn->aPositionKeys.size() > 0) + // Rotations are quaternion offsets + aiQuaternion abs; + for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) { - nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); - nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; - ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], - sizeof(aiVectorKey)*nda->mNumPositionKeys); - } + const aiQuatKey& q = pcIn->aRotationKeys[n]; - // ROTATION keys - if (pcIn->aRotationKeys.size() > 0) - { - nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); - nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; - ::memcpy(nda->mRotationKeys,&pcIn->aRotationKeys[0], - sizeof(aiQuatKey)*nda->mNumRotationKeys); + abs = (n ? abs * q.mValue : q.mValue); + nda->mRotationKeys[n].mTime = q.mTime; + nda->mRotationKeys[n].mValue = abs.Normalize(); } + } - // SCALING keys - if (pcIn->aScalingKeys.size() > 0) - { - nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); - nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; - ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], - sizeof(aiVectorKey)*nda->mNumScalingKeys); - } + // SCALING keys + if (pcIn->aScalingKeys.size() > 0) + { + nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); + nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; + ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], + sizeof(aiVectorKey)*nda->mNumScalingKeys); } } @@ -864,14 +773,6 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) pcOld->mChildren[0] = NULL; delete pcOld; } - -#if 0 - // modify the transformation of the root node to change - // the coordinate system of the whole scene from Max' to OpenGL - pcOut->mRootNode->mTransformation.a3 *= -1.f; - pcOut->mRootNode->mTransformation.b3 *= -1.f; - pcOut->mRootNode->mTransformation.c3 *= -1.f; -#endif } // ------------------------------------------------------------------------------------------------ diff --git a/code/3DSHelper.h b/code/3DSHelper.h index c9fcd14a4..2c0b9965f 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -38,21 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines helper data structures for the import of 3DS files. -http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */ +/** @file Defines helper data structures for the import of 3DS files */ #ifndef AI_3DSFILEHELPER_H_INC #define AI_3DSFILEHELPER_H_INC -#include -#include -#include - -#include "../include/aiTypes.h" -#include "../include/aiQuaternion.h" -#include "../include/aiMesh.h" -#include "../include/aiAnim.h" -#include "../include/aiMaterial.h" #include "SpatialSort.h" #include "SmoothingGroups.h" @@ -66,12 +56,13 @@ namespace D3DS { /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks * and data structures. */ -// --------------------------------------------------------------------------- class Discreet3DS { -public: +private: inline Discreet3DS() {} +public: + //! data structure for a single chunk in a .3ds file struct Chunk { @@ -79,10 +70,6 @@ public: uint32_t Size; } PACK_STRUCT; - //! source for this used own structures, - //! replaced it with out standard math helpers - typedef aiMatrix3x3 MatTransform; - typedef aiVector3D MatTranslate; //! Used for shading field in material3ds structure //! From AutoDesk 3ds SDK @@ -301,26 +288,22 @@ public: }; }; -#include "./../include/Compiler/poppack1.h" - // --------------------------------------------------------------------------- /** Helper structure representing a 3ds mesh face */ struct Face : public FaceWithSmoothingGroup { - //! Specifies that the face normal must be flipped. - //! todo: do we really need this? - bool bFlipped; }; + // --------------------------------------------------------------------------- /** Helper structure representing a texture */ struct Texture { //! Default constructor Texture() - : mScaleU (1.0f) - , mScaleV (1.0f) - , mOffsetU (0.0f) + : mOffsetU (0.0f) , mOffsetV (0.0f) + , mScaleU (1.0f) + , mScaleV (1.0f) , mRotation (0.0f) , mMapMode (aiTextureMapMode_Wrap) , iUVSrc (0) @@ -335,10 +318,10 @@ struct Texture std::string mMapName; //! Specifies texture coordinate offsets/scaling/rotations - float mScaleU; - float mScaleV; float mOffsetU; float mOffsetV; + float mScaleU; + float mScaleV; float mRotation; //! Specifies the mapping mode to be used for the texture @@ -348,6 +331,9 @@ struct Texture bool bPrivate; int iUVSrc; }; + +#include "./../include/Compiler/poppack1.h" + // --------------------------------------------------------------------------- /** Helper structure representing a 3ds material */ struct Material @@ -414,6 +400,7 @@ struct Material unsigned int iBakeUVTransform; Texture* pcSingleTexture; }; + // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file mesh */ struct Mesh : public MeshWithSmoothingGroups @@ -433,7 +420,7 @@ struct Mesh : public MeshWithSmoothingGroups std::string mName; //! Texture coordinates - std::vector mTexCoords; + std::vector mTexCoords; //! Face materials std::vector mFaceMaterials; diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index 3c320196b..7b899e0b5 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -104,7 +104,7 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle // Setup configuration properties void Discreet3DSImporter::SetupProperties(const Importer* pImp) { - configSkipPivot = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false; + // nothing to be done for the moment } // ------------------------------------------------------------------------------------------------ @@ -141,7 +141,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, // internal verbose representation. Finally compute normal // vectors from the smoothing groups we read from the // file. - for (std::vector::iterator i = mScene->mMeshes.begin(), + for (std::vector::iterator i = mScene->mMeshes.begin(), end = mScene->mMeshes.end(); i != end;++i) { CheckIndices(*i); @@ -149,9 +149,6 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, ComputeNormalsWithSmoothingsGroups(*i); } - // Apply scaling and offsets to all texture coordinates - TextureTransform::ApplyScaleNOffset(mScene->mMaterials); - // Replace all occurences of the default material with a // valid material. Generate it if no material containing // DEFAULT in its name has been found in the file @@ -678,6 +675,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) } else l = & mCurrentNode->aPositionKeys; + l->reserve(numFrames); for (unsigned int i = 0; i < numFrames;++i) { unsigned int fidx = stream->GetI2(); @@ -724,6 +722,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) stream->IncPtr(10); unsigned int numFrames = stream->GetI2(); + l->reserve(numFrames); stream->IncPtr(2); for (unsigned int i = 0; i < numFrames;++i) @@ -776,6 +775,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) bool sortKeys = false; std::vector* l = &mCurrentNode->aRotationKeys; + l->reserve(numFrames); for (unsigned int i = 0; i < numFrames;++i) { @@ -825,6 +825,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) bool sortKeys = false; std::vector* l = &mCurrentNode->aScalingKeys; + l->reserve(numFrames); for (unsigned int i = 0; i < numFrames;++i) { @@ -924,7 +925,7 @@ void Discreet3DSImporter::ParseFaceChunk() } // Now continue and read all material indices - cnt = stream->GetI2(); + cnt = (uint16_t)stream->GetI2(); for (unsigned int i = 0; i < cnt;++i) { unsigned int fidx = (uint16_t)stream->GetI2(); @@ -957,7 +958,8 @@ void Discreet3DSImporter::ParseMeshChunk() case Discreet3DS::CHUNK_VERTLIST: { // This is the list of all vertices in the current mesh - int num = stream->GetI2(); + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mPositions.reserve(num); while (num-- > 0) { aiVector3D v; @@ -985,8 +987,8 @@ void Discreet3DSImporter::ParseMeshChunk() mMesh.mMat.c4 = stream->GetF4(); // Now check whether the matrix has got a negative determinant - // If yes, we need to flip all vertices' x axis .... - // From lib3ds, mesh.c + // If yes, we need to flip all vertices' Z axis .... + // This code has been taken from lib3ds if (mMesh.mMat.Determinant() < 0.0f) { // Compute the inverse of the matrix @@ -994,10 +996,10 @@ void Discreet3DSImporter::ParseMeshChunk() mInv.Inverse(); aiMatrix4x4 mMe = mMesh.mMat; - mMe.a1 *= -1.0f; - mMe.b1 *= -1.0f; mMe.c1 *= -1.0f; - mMe.d1 *= -1.0f; + mMe.c2 *= -1.0f; + mMe.c3 *= -1.0f; + mMe.c4 *= -1.0f; mInv = mInv * mMe; // Now transform all vertices @@ -1010,16 +1012,19 @@ void Discreet3DSImporter::ParseMeshChunk() c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2]; mMesh.mPositions[i] = c; } + + DefaultLogger::get()->info("3DS: Flipping mesh Z-Axis"); }} break; case Discreet3DS::CHUNK_MAPLIST: { // This is the list of all UV coords in the current mesh - int num = stream->GetI2(); + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mTexCoords.reserve(num); while (num-- > 0) { - aiVector2D v; + aiVector3D v; v.x = stream->GetF4(); v.y = stream->GetF4(); mMesh.mTexCoords.push_back(v); @@ -1029,7 +1034,8 @@ void Discreet3DSImporter::ParseMeshChunk() case Discreet3DS::CHUNK_FACELIST: { // This is the list of all faces in the current mesh - int num = stream->GetI2(); + int num = (int)(uint16_t)stream->GetI2(); + mMesh.mFaces.reserve(num); while (num-- > 0) { // 3DS faces are ALWAYS triangles @@ -1226,6 +1232,7 @@ void Discreet3DSImporter::ParseMaterialChunk() // recursively continue processing this hierarchy level return ParseMaterialChunk(); } + // ------------------------------------------------------------------------------------------------ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) { @@ -1262,7 +1269,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) if (0.0f == pcOut->mScaleU) { DefaultLogger::get()->warn("Texture coordinate scaling in the " - "x direction is zero. Assuming this should be 1.0 ... "); + "x direction is zero. Assuming 1"); pcOut->mScaleU = 1.0f; } break; @@ -1272,14 +1279,14 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) if (0.0f == pcOut->mScaleV) { DefaultLogger::get()->warn("Texture coordinate scaling in the " - "y direction is zero. Assuming this should be 1.0 ... "); + "y direction is zero. Assuming 1"); pcOut->mScaleV = 1.0f; } break; case Discreet3DS::CHUNK_MAT_MAP_UOFFSET: // Texture coordinate offset in the U direction - pcOut->mOffsetU = stream->GetF4(); + pcOut->mOffsetU = -stream->GetF4(); break; case Discreet3DS::CHUNK_MAT_MAP_VOFFSET: @@ -1288,24 +1295,24 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) break; case Discreet3DS::CHUNK_MAT_MAP_ANG: - // Texture coordinate rotation, CCW in radians - pcOut->mRotation = stream->GetF4(); + // Texture coordinate rotation, CCW in DEGREES + pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() ); break; case Discreet3DS::CHUNK_MAT_MAP_TILING: { uint16_t iFlags = stream->GetI2(); - // check whether the mirror flag is set + // Get the mapping mode (for both axes) if (iFlags & 0x2u) - { pcOut->mMapMode = aiTextureMapMode_Mirror; + + else if (iFlags & 0x10u) + pcOut->mMapMode = aiTextureMapMode_Decal; + + // wrapping in all remaining cases + else pcOut->mMapMode = aiTextureMapMode_Wrap; } - // assume that "decal" means clamping ... - else if (iFlags & 0x10u && iFlags & 0x1u) - { - pcOut->mMapMode = aiTextureMapMode_Clamp; - }} break; }; diff --git a/code/3DSLoader.h b/code/3DSLoader.h index 28fbde92e..85f595424 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -238,12 +238,8 @@ protected: */ void CheckIndices(D3DS::Mesh& sMesh); - protected: - /** Configuration option: skip pivot chunks */ - bool configSkipPivot; - /** Stream to read from */ StreamReaderLE* stream; diff --git a/code/ACLoader.cpp b/code/ACLoader.cpp index d77d18e9e..c1cb3928b 100644 --- a/code/ACLoader.cpp +++ b/code/ACLoader.cpp @@ -151,11 +151,30 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) if (!TokenMatch(buffer,"OBJECT",6)) return; + SkipSpaces(&buffer); + ++mNumMeshes; objects.push_back(Object()); Object& obj = objects.back(); + aiLight* light = NULL; + if (!ASSIMP_stricmp(buffer,"light")) + { + // This is a light source. Add it to the list + mLights->push_back(light = new aiLight()); + + // Return a point light with no attenuation + light->mType = aiLightSource_POINT; + light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); + light->mAttenuationConstant = 1.f; + + // Generate a default name for both the light source and the node + light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",mLights->size()-1); + obj.name = std::string( light->mName.data ); + + } + while (GetNextLine()) { if (TokenMatch(buffer,"kids",4)) @@ -176,6 +195,13 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) { SkipSpaces(&buffer); AI_AC_GET_STRING(obj.name); + + // If this is a light source, we'll also need to store + // the name of the node in it. + if (light) + { + light->mName.Set(obj.name); + } } else if (TokenMatch(buffer,"texture",7)) { @@ -219,8 +245,6 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) obj.vertices.push_back(aiVector3D()); aiVector3D& v = obj.vertices.back(); AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); - //std::swap(v.z,v.y); - v.z *= -1.f; } } else if (TokenMatch(buffer,"numsurf",7)) @@ -597,7 +621,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, node->mTransformation = aiMatrix4x4 ( object.rotation ); node->mTransformation.a4 = object.translation.x; - node->mTransformation.b4 = object.translation.y; + node->mTransformation.b4 = -object.translation.y; node->mTransformation.c4 = object.translation.z; return node; @@ -644,6 +668,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile, std::vector rootObjects; rootObjects.reserve(5); + std::vector lights; + mLights = & lights; + while (GetNextLine()) { if (TokenMatch(buffer,"MATERIAL",8)) @@ -662,9 +689,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile, } AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.rgb); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); + AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); } @@ -701,6 +728,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile, pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); if (1 != rootObjects.size())delete root; + if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) + pScene->mRootNode->mName.Set(""); + // build output arrays if (meshes.empty()) { @@ -710,10 +740,17 @@ void AC3DImporter::InternReadFile( const std::string& pFile, pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); - // build output arrays + pScene->mNumMaterials = (unsigned int)omaterials.size(); pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); + + pScene->mNumLights = (unsigned int)lights.size(); + if (lights.size()) + { + pScene->mLights = new aiLight*[lights.size()]; + ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); + } } #endif //!defined AI_BUILD_NO_AC_IMPORTER diff --git a/code/ACLoader.h b/code/ACLoader.h index a3ce9e94f..64ad999f1 100644 --- a/code/ACLoader.h +++ b/code/ACLoader.h @@ -236,6 +236,9 @@ private: // basing on this information we can find a // good estimate how many meshes we'll have in the final scene. unsigned int mNumMeshes; + + // current list of light sources + std::vector* mLights; }; } // end of namespace Assimp diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 6d5357405..f6a1940af 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ASELoader.h" #include "MaterialSystem.h" #include "StringComparison.h" -#include "TextureTransform.h" #include "SkeletonMeshBuilder.h" +#include "TargetAnimation.h" // utilities #include "fast_atof.h" -#include "qnan.h" using namespace Assimp; using namespace Assimp::ASE; @@ -156,15 +155,15 @@ void ASEImporter::InternReadFile( const std::string& pFile, std::vector avOutMeshes; avOutMeshes.reserve(mParser->m_vMeshes.size()*2); for (std::vector::iterator - i = mParser->m_vMeshes.begin(); - i != mParser->m_vMeshes.end();++i) + i = mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) { if ((*i).bSkip)continue; - // Now we need to create proper meshes from the import we - // need to split them by materials, build valid vertex/ - // face lists ... - BuildUniqueRepresentation(*i); + // First of all - we need to build an unique mesh representation + // that we can recompute the normal vectors easily. This is + // also a prerequisite for the second code path in ConvertMeshes() + // so it's difficult to optimize it away. TODO! + BuildUniqueRepresentation(*i); // Need to generate proper vertex normals if necessary if(GenerateNormals(*i)) @@ -305,8 +304,12 @@ void ASEImporter::BuildAnimations() // that represent the node transformation. if ((*i)->mAnim.akeyPositions.size() > 1 || (*i)->mAnim.akeyRotations.size() > 1 || - (*i)->mAnim.akeyScaling.size() > 1 || - (*i)->mTargetAnim.akeyPositions.size() > 1 + (*i)->mAnim.akeyScaling.size() > 1) + { + ++iNum; + } + + if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) { ++iNum; @@ -337,6 +340,21 @@ void ASEImporter::BuildAnimations() aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); nd->mNodeName.Set(me->mName + ".Target"); + // If there is no input position channel we will need + // to supply the default position from the node's + // local transformation matrix. + /*TargetAnimationHelper helper; + if (me->mAnim.akeyPositions.empty()) + { + aiMatrix4x4& mat = (*i)->mTransform; + helper.SetFixedMainAnimationChannel(aiVector3D( + mat.a4, mat.b4, mat.c4)); + } + else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions); + helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions); + + helper.Process(&me->mTargetAnim.akeyPositions);*/ + // Allocate the key array and fill it nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size(); nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; @@ -345,7 +363,8 @@ void ASEImporter::BuildAnimations() nd->mNumPositionKeys * sizeof(aiVectorKey)); } - if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1) + if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || + me->mAnim.akeyScaling.size() > 1) { // Begin a new node animation channel for this node aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim(); @@ -424,8 +443,6 @@ void ASEImporter::BuildCameras() out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); out->mHorizontalFOV = in.mFOV; - // TODO: Implement proper camera target - out->mName.Set(in.mName); } } @@ -480,7 +497,7 @@ void ASEImporter::AddNodes(std::vector& nodes, aiNode* pcParent,const char* szName) { aiMatrix4x4 m; - this->AddNodes(nodes,pcParent,szName,m); + AddNodes(nodes,pcParent,szName,m); } // ------------------------------------------------------------------------------------------------ @@ -580,6 +597,12 @@ void ASEImporter::AddNodes (std::vector& nodes, mParentAdjust.Inverse(); node->mTransformation = mParentAdjust*snode->mTransform; + // Add sub nodes - prevent stack overflow + if (node->mName != node->mParent->mName) + { + AddNodes(nodes,node,node->mName.data,snode->mTransform); + } + // Further processing depends on the type of the node if (snode->mType == ASE::BaseNode::Mesh) { @@ -597,39 +620,43 @@ void ASEImporter::AddNodes (std::vector& nodes, // target (the direction information is contained in *this* // node's animation track but the exact target position // would be lost otherwise) - apcNodes.push_back(new aiNode()); - aiNode* node = apcNodes.back(); + if (!node->mNumChildren) + { + node->mChildren = new aiNode*[1]; + } - node->mName.Set ( snode->mName + ".Target" ); - node->mTransformation.a4 = snode->mTargetPosition.x; - node->mTransformation.b4 = snode->mTargetPosition.y; - node->mTransformation.c4 = snode->mTargetPosition.z; + aiNode* nd = new aiNode(); - node->mParent = pcParent; - } + nd->mName.Set ( snode->mName + ".Target" ); + nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4; + nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4; + nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4; - // add sub nodes - // aiMatrix4x4 mNewAbs = mat * node->mTransformation; + nd->mParent = node; - // prevent stack overflow - if (node->mName != node->mParent->mName) - { - AddNodes(nodes,node,node->mName.data,snode->mTransform); + // The .Target node is always the first child node + for (unsigned int m = 0; m < node->mNumChildren;++m) + node->mChildren[m+1] = node->mChildren[m]; + + node->mChildren[0] = nd; + node->mNumChildren++; + + // What we did is so great, it is at least worth a debug message + DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")"); } } - // allocate enough space for the child nodes + // Allocate enough space for the child nodes + // We allocate one slot more in case this is a target camera/light pcParent->mNumChildren = (unsigned int)apcNodes.size(); if (pcParent->mNumChildren) { - pcParent->mChildren = new aiNode*[apcNodes.size()]; + pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */]; // now build all nodes for our nice new children for (unsigned int p = 0; p < apcNodes.size();++p) - { pcParent->mChildren[p] = apcNodes[p]; - } } return; } @@ -643,7 +670,7 @@ void ASEImporter::BuildNodes() pcScene->mRootNode = new aiNode(); pcScene->mRootNode->mNumMeshes = 0; pcScene->mRootNode->mMeshes = 0; - pcScene->mRootNode->mName.Set(""); + pcScene->mRootNode->mName.Set(""); // Setup the coordinate system transformation //pcScene->mRootNode->mTransformation.c3 *= -1.f; @@ -708,7 +735,7 @@ void ASEImporter::BuildNodes() { const ASE::BaseNode* src = *i; - // the parent is not known, so we can assume that we must add + // The parent is not known, so we can assume that we must add // this node to the root node of the whole scene aiNode* pcNode = new aiNode(); pcNode->mParent = pcScene->mRootNode; @@ -731,16 +758,18 @@ void ASEImporter::BuildNodes() for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) pcScene->mMeshes[i]->mColors[2] = NULL; - // if there is only one subnode, set it as root node + // If there is only one subnode, set it as root node // FIX: The sub node may not have animations assigned if (1 == pcScene->mRootNode->mNumChildren && !pcScene->mNumAnimations) { aiNode* cc = pcScene->mRootNode->mChildren[0]; aiNode* pc = pcScene->mRootNode; + if (!cc->mName.length) + cc->mName = pc->mName; + pcScene->mRootNode = cc; - pcScene->mRootNode->mParent = NULL; - cc->mTransformation = pc->mTransformation * cc->mTransformation; + cc->mParent = NULL; // make sure the destructor won't delete us ... delete[] pc->mChildren; @@ -803,17 +832,12 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) for (unsigned int n = 0; n < 3;++n,++iCurrent) { mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]]; - //std::swap((float&)mPositions[iCurrent].z,(float&)mPositions[iCurrent].y); // DX-to-OGL - //mPositions[iCurrent].y *= -1.f; // add texture coordinates for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (!mesh.amTexCoords[c].empty()) - { - amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; - // amTexCoords[c][iCurrent].y = 1.f- amTexCoords[c][iCurrent].y; // DX-to-OGL - } + if (mesh.amTexCoords[c].empty())break; + amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]]; } // add vertex colors if (!mesh.mVertexColors.empty()) @@ -825,9 +849,6 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) { mNormals[iCurrent] = mesh.mNormals[fi*3+n]; mNormals[iCurrent].Normalize(); - - //std::swap((float&)mNormals[iCurrent].z,(float&)mNormals[iCurrent].y); // DX-to-OGL - //mNormals[iCurrent].y *= -1.0f; } // handle bone vertices @@ -838,11 +859,9 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) // will fix that again ...) mBoneVertices[iCurrent] = mesh.mBoneVertices[(*i).mIndices[n]]; } + + (*i).mIndices[n] = iCurrent; } - // we need to flip the order of the indices - (*i).mIndices[0] = iCurrent-1; - (*i).mIndices[1] = iCurrent-2; - (*i).mIndices[2] = iCurrent-3; } // replace the old arrays @@ -852,20 +871,37 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) mesh.amTexCoords[c] = amTexCoords[c]; - return; +} + +// ------------------------------------------------------------------------------------------------ +void CopyASETexture(MaterialHelper& mat, ASE::Texture& texture, aiTextureType type) +{ + // Setup the texture name + aiString tex; + tex.Set( texture.mMapName); + mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); + + // Setup the texture blend factor + if (is_not_qnan(texture.mTextureBlend)) + mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); + + // Setup texture UV transformations + mat.AddProperty(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); } // ------------------------------------------------------------------------------------------------ void ASEImporter::ConvertMaterial(ASE::Material& mat) { - // allocate the output material + // LARGE TODO: Much code her is copied from 3DS ... join them maybe? + + // Allocate the output material mat.pcInstance = new MaterialHelper(); // At first add the base ambient color of the // scene to the material - mat.mAmbient.r += this->mParser->m_clrAmbient.r; - mat.mAmbient.g += this->mParser->m_clrAmbient.g; - mat.mAmbient.b += this->mParser->m_clrAmbient.b; + mat.mAmbient.r += mParser->m_clrAmbient.r; + mat.mAmbient.g += mParser->m_clrAmbient.g; + mat.mAmbient.b += mParser->m_clrAmbient.b; aiString name; name.Set( mat.mName); @@ -883,7 +919,7 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS); mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); } - // if there is no shininess, we can disable phong lighting + // If there is no shininess, we can disable phong lighting else if (D3DS::Discreet3DS::Metal == mat.mShading || D3DS::Discreet3DS::Phong == mat.mShading || D3DS::Discreet3DS::Blinn == mat.mShading) @@ -894,6 +930,12 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) // opacity mat.pcInstance->AddProperty( &mat.mTransparency,1,AI_MATKEY_OPACITY); + // Two sided rendering? + if (mat.mTwoSided) + { + int i = 1; + mat.pcInstance->AddProperty(&i,1,AI_MATKEY_TWOSIDED); + } // shading mode aiShadingMode eShading = aiShadingMode_NoShading; @@ -906,9 +948,14 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) case D3DS::Discreet3DS::Blinn : eShading = aiShadingMode_Blinn; break; - // I don't know what "Wire" shading should be, - // assume it is simple lambertian diffuse (L dot N) shading + // I don't know what "Wire" shading should be, + // assume it is simple lambertian diffuse (L dot N) shading case D3DS::Discreet3DS::Wire: + { + // set the wireframe flag + unsigned int iWire = 1; + mat.pcInstance->AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); + } case D3DS::Discreet3DS::Gouraud: eShading = aiShadingMode_Gouraud; break; case D3DS::Discreet3DS::Metal : @@ -916,84 +963,33 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat) } mat.pcInstance->AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); - if (D3DS::Discreet3DS::Wire == mat.mShading) - { - // set the wireframe flag - unsigned int iWire = 1; - mat.pcInstance->AddProperty( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); - } - - // texture, if there is one + // DIFFUSE texture if( mat.sTexDiffuse.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexDiffuse.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0)); + CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE); - if (is_not_qnan(mat.sTexDiffuse.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexDiffuse.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_DIFFUSE(0)); - } + // SPECULAR texture if( mat.sTexSpecular.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexSpecular.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(0)); + CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR); - if (is_not_qnan(mat.sTexSpecular.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexSpecular.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_SPECULAR(0)); - } - if( mat.sTexOpacity.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexOpacity.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY(0)); - - if (is_not_qnan(mat.sTexOpacity.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexOpacity.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_OPACITY(0)); - } - if( mat.sTexEmissive.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexEmissive.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(0)); - - if (is_not_qnan(mat.sTexEmissive.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexEmissive.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_EMISSIVE(0)); - } + // AMBIENT texture if( mat.sTexAmbient.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexAmbient.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(0)); + CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT); - if (is_not_qnan(mat.sTexAmbient.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexAmbient.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_AMBIENT(0)); - } + // OPACITY texture + if( mat.sTexOpacity.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY); + + // EMISSIVE texture + if( mat.sTexEmissive.mMapName.length() > 0) + CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE); + + // BUMP texture if( mat.sTexBump.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexBump.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(0)); + CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT); - if (is_not_qnan(mat.sTexBump.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexBump.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_HEIGHT(0)); - } + // SHININESS texture if( mat.sTexShininess.mMapName.length() > 0) - { - aiString tex; - tex.Set( mat.sTexShininess.mMapName); - mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_SHININESS(0)); - - if (is_not_qnan(mat.sTexShininess.mTextureBlend)) - mat.pcInstance->AddProperty( &mat.sTexBump.mTextureBlend, 1, - AI_MATKEY_TEXBLEND_SHININESS(0)); - } + CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS); // store the name of the material itself, too if( mat.mName.length() > 0) @@ -1081,12 +1077,12 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; for (unsigned int q = 0; q < aiSplit[p].size();++q) { - iIndex = aiSplit[p][q]; + iIndex = aiSplit[p][q]; p_pcOut->mFaces[q].mIndices = new unsigned int[3]; p_pcOut->mFaces[q].mNumIndices = 3; - for (unsigned int t = 0; t < 3;++t) + for (unsigned int t = 0; t < 3;++t, ++iBase) { const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; @@ -1110,13 +1106,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } } } - ++iBase; + p_pcOut->mFaces[q].mIndices[t] = iBase; } - - // Flip the face order - p_pcOut->mFaces[q].mIndices[0] = iBase-3; - p_pcOut->mFaces[q].mIndices[1] = iBase-2; - p_pcOut->mFaces[q].mIndices[2] = iBase-1; } } // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported) @@ -1134,12 +1125,12 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; } } - // setup the number of valid vertex components + // Setup the number of valid vertex components p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c]; } } - // convert vertex colors (only one set supported) + // Convert vertex colors (only one set supported) if (!mesh.mVertexColors.empty()) { p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; @@ -1153,6 +1144,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh } } } + // Copy bones if (!mesh.mBones.empty()) { p_pcOut->mNumBones = 0; @@ -1211,7 +1203,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mColors[2] = (aiColor4D*) &mesh; avOutMeshes.push_back(p_pcOut); - // if the mesh hasn't faces or vertices, there are two cases + // If the mesh hasn't faces or vertices, there are two cases // possible: 1. the model is invalid. 2. This is a dummy // helper object which we are going to remove later ... if (mesh.mFaces.empty() || mesh.mPositions.empty()) @@ -1264,10 +1256,10 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector& avOutMesh p_pcOut->mFaces[iFace].mNumIndices = 3; p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; - // copy indices (flip the face order, too) - p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[2]; + // copy indices + p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0]; p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1]; - p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[0]; + p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2]; } // copy vertex bones @@ -1328,23 +1320,20 @@ void ASEImporter::BuildMaterialIndices() // iterate through all materials and check whether we need them for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { - if (mParser->m_vMaterials[iMat].bNeed) + ASE::Material& mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) { - // convert it to the aiMaterial layout - ASE::Material& mat = mParser->m_vMaterials[iMat]; + // Convert it to the aiMaterial layout ConvertMaterial(mat); - TextureTransform::ApplyScaleNOffset(mat); ++pcScene->mNumMaterials; } - for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[ - iMat].avSubMaterials.size();++iSubMat) + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { - if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed) + ASE::Material& submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { - // convert it to the aiMaterial layout - ASE::Material& mat = mParser->m_vMaterials[iMat].avSubMaterials[iSubMat]; - ConvertMaterial(mat); - TextureTransform::ApplyScaleNOffset(mat); + // Convert it to the aiMaterial layout + ConvertMaterial(submat); ++pcScene->mNumMaterials; } } @@ -1357,77 +1346,60 @@ void ASEImporter::BuildMaterialIndices() unsigned int iNum = 0; for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) { - if (mParser->m_vMaterials[iMat].bNeed) + ASE::Material& mat = mParser->m_vMaterials[iMat]; + if (mat.bNeed) { - ai_assert(NULL != mParser->m_vMaterials[iMat].pcInstance); - pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat].pcInstance; + ai_assert(NULL != mat.pcInstance); + pcScene->mMaterials[iNum] = mat.pcInstance; - // store the internal material, too - pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat]; + // Store the internal material, too + pcIntMaterials[iNum] = &mat; - // iterate through all meshes and search for one which is using + // Iterate through all meshes and search for one which is using // this top-level material index for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { - if (ASE::Face::DEFAULT_MATINDEX == pcScene->mMeshes[iMesh]->mMaterialIndex && - iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3]) + aiMesh* mesh = pcScene->mMeshes[iMesh]; + if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex && + iMat == (uintptr_t)mesh->mColors[3]) { - pcScene->mMeshes[iMesh]->mMaterialIndex = iNum; - pcScene->mMeshes[iMesh]->mColors[3] = NULL; + mesh->mMaterialIndex = iNum; + mesh->mColors[3] = NULL; } } iNum++; } - for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[iMat].avSubMaterials.size();++iSubMat) + for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat) { - if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed) + ASE::Material& submat = mat.avSubMaterials[iSubMat]; + if (submat.bNeed) { - ai_assert(NULL != mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].pcInstance); - pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat]. - avSubMaterials[iSubMat].pcInstance; + ai_assert(NULL != submat.pcInstance); + pcScene->mMaterials[iNum] = submat.pcInstance; - // store the internal material, too - pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat].avSubMaterials[iSubMat]; + // Store the internal material, too + pcIntMaterials[iNum] = &submat; - // iterate through all meshes and search for one which is using + // Iterate through all meshes and search for one which is using // this sub-level material index for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh) { - if (iSubMat == pcScene->mMeshes[iMesh]->mMaterialIndex && - iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3]) + aiMesh* mesh = pcScene->mMeshes[iMesh]; + if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) { - pcScene->mMeshes[iMesh]->mMaterialIndex = iNum; - pcScene->mMeshes[iMesh]->mColors[3] = NULL; + mesh->mMaterialIndex = iNum; + mesh->mColors[3] = NULL; } } iNum++; } } } - // prepare for the next step - for (unsigned int hans = 0; hans < mParser->m_vMaterials.size();++hans) - TextureTransform::ApplyScaleNOffset(mParser->m_vMaterials[hans]); - // now we need to iterate through all meshes, - // generating correct texture coordinates and material uv indices - for (unsigned int curie = 0; curie < pcScene->mNumMeshes;++curie) - { - aiMesh* pcMesh = pcScene->mMeshes[curie]; - - // apply texture coordinate transformations - TextureTransform::BakeScaleNOffset(pcMesh,pcIntMaterials[pcMesh->mMaterialIndex]); - } - for (unsigned int hans = 0; hans < pcScene->mNumMaterials;++hans) - { - // setup the correct UV indices for each material - TextureTransform::SetupMatUVSrc(pcScene->mMaterials[hans], - pcIntMaterials[hans]); - } + // Dekete our temporary array delete[] pcIntMaterials; - - // finished! - return; } + // ------------------------------------------------------------------------------------------------ // Generate normal vectors basing on smoothing groups bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) @@ -1446,6 +1418,7 @@ bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) } } } + // The array will be reused ComputeNormalsWithSmoothingsGroups(mesh); return false; diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index 44aafa23b..5af9c9e84 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -634,6 +634,12 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat) mat.mSpecularExponent *= 15; continue; } + // two-sided material + if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) ) + { + mat.mTwoSided = true; + continue; + } // material shininess strength if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22)) { @@ -1387,7 +1393,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh) continue; } // Number of vertex colors in the mesh - if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,14)) + if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15)) { ParseLV4MeshLong(iNumCVertices); continue; @@ -1877,44 +1883,38 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) { AI_ASE_PARSER_INIT(); - // allocate enough storage for the normals + // Allocate enough storage for the normals sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); - unsigned int iIndex = 0, faceIdx = 0xffffffff; + unsigned int index, faceIdx = 0xffffffff; - // ******************************************************************** - // just smooth both vertex and face normals together, so it will still - // work if one one of the two is missing. If one of the two is invalid - // the result will be partly corrected by this trick. - // ******************************************************************** + // Smooth the vertex and face normals together. The result + // will be edgy then, but otherwise everything would be soft ... while (true) { if ('*' == *filePtr) { ++filePtr; - if (0xffffffff != faceIdx && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) + if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { aiVector3D vNormal; - ParseLV4MeshFloatTriple(&vNormal.x,iIndex); + ParseLV4MeshFloatTriple(&vNormal.x,index); - if (iIndex == sMesh.mFaces[faceIdx].mIndices[0]) - { - iIndex = 0; - } - else if (iIndex == sMesh.mFaces[faceIdx].mIndices[1]) - { - iIndex = 1; - } - else if (iIndex == sMesh.mFaces[faceIdx].mIndices[2]) - { - iIndex = 2; - } + // Make sure we assign it to the correct face + const ASE::Face& face = sMesh.mFaces[faceIdx]; + if (index == face.mIndices[0]) + index = 0; + else if (index == face.mIndices[1]) + index = 1; + else if (index == face.mIndices[2]) + index = 2; else { - LogWarning("Normal index doesn't fit to face index"); + DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); continue; } + // We'll renormalize later - sMesh.mNormals[faceIdx*3 + iIndex] += vNormal; + sMesh.mNormals[faceIdx*3+index] += vNormal; continue; } if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) @@ -1922,15 +1922,14 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) aiVector3D vNormal; ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); - if (iIndex >= sMesh.mFaces.size()) + if (faceIdx >= sMesh.mFaces.size()) { - LogWarning("Face normal index is too large"); - faceIdx = 0xffffffff; + DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); continue; } - sMesh.mNormals[faceIdx*3] += vNormal; - sMesh.mNormals[faceIdx*3 +1] += vNormal; - sMesh.mNormals[faceIdx*3 +2] += vNormal; + + // We'll renormalize later + sMesh.mNormals[faceIdx*3] += vNormal; continue; } } @@ -2037,7 +2036,7 @@ void Parser::ParseLV4MeshFace(ASE::Face& out) return; } - // parse smoothing groups until we don_t anymore see commas + // Parse smoothing groups until we don't anymore see commas // FIX: There needn't always be a value, sad but true while (true) { diff --git a/code/ASEParser.h b/code/ASEParser.h index b1ba0d06b..be7254d1e 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -82,6 +82,7 @@ struct Material : public D3DS::Material //! Can we remove this material? bool bNeed; }; + // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file face */ struct Face : public FaceWithSmoothingGroup @@ -175,12 +176,6 @@ struct Animation , mPositionType (TRACK) {} - /** ONLY ONE OF THESE SETS IS USED - * - * Bezier and TCB channels are converted to a normal - * trac later. - */ - //! List of track rotation keyframes std::vector< aiQuatKey > akeyRotations; diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index 2f9d1a71f..f0739ec6d 100644 --- a/code/AssimpPCH.h +++ b/code/AssimpPCH.h @@ -107,12 +107,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef ASSIMP_BUILD_BOOST_WORKAROUND # include "../include/BoostWorkaround/boost/scoped_ptr.hpp" +# include "../include/BoostWorkaround/boost/scoped_array.hpp" # include "../include/BoostWorkaround/boost/format.hpp" # include "../include/BoostWorkaround/boost/common_factor_rt.hpp" #else # include +# include # include # include diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index df056bd0d..157c38fa3 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -110,7 +110,7 @@ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, if (pStream.get() ) { // read 200 characters from the file - boost::scoped_ptr _buffer (new char[searchBytes]); + boost::scoped_array _buffer (new char[searchBytes+1 /* for the '\0' */]); char* buffer = _buffer.get(); unsigned int read = (unsigned int)pStream->Read(buffer,1,searchBytes); diff --git a/code/ComputeUVMappingProcess.cpp b/code/ComputeUVMappingProcess.cpp new file mode 100644 index 000000000..3ccc6ea5f --- /dev/null +++ b/code/ComputeUVMappingProcess.cpp @@ -0,0 +1,175 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 GenUVCoords step */ + + +#include "AssimpPCH.h" +#include "ComputeUVMappingProcess.h" +#include "ProcessHelper.h" + +using namespace Assimp; + + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +ComputeUVMappingProcess::ComputeUVMappingProcess() +{ + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +ComputeUVMappingProcess::~ComputeUVMappingProcess() +{ + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the processing step is present in the given flag field. +bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const +{ + return (pFlags & aiProcess_GenUVCoords) != 0; +} + +// ------------------------------------------------------------------------------------------------ +unsigned int ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,aiAxis axis) +{ + DefaultLogger::get()->error("Mapping type currently not implemented"); + return 0; +} + +// ------------------------------------------------------------------------------------------------ +unsigned int ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,aiAxis axis) +{ + DefaultLogger::get()->error("Mapping type currently not implemented"); + return 0; +} + +// ------------------------------------------------------------------------------------------------ +unsigned int ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,aiAxis axis) +{ + DefaultLogger::get()->error("Mapping type currently not implemented"); + return 0; +} + +// ------------------------------------------------------------------------------------------------ +unsigned int ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* mesh) +{ + DefaultLogger::get()->error("Mapping type currently not implemented"); + return 0; +} + +// ------------------------------------------------------------------------------------------------ +void ComputeUVMappingProcess::Execute( aiScene* pScene) +{ + DefaultLogger::get()->debug("GenUVCoordsProcess begin"); + char buffer[1024]; + + /* Iterate through all materials and search for non-UV mapped textures + */ + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) + { + aiMaterial* mat = pScene->mMaterials[i]; + for (unsigned int a = 0; a < mat->mNumProperties;++a) + { + aiMaterialProperty* prop = mat->mProperties[a]; + if (!::strcmp( prop->mKey.data, "$tex.mapping")) + { + aiTextureMapping mapping = *((aiTextureMapping*)prop->mData); + if (aiTextureMapping_UV != mapping) + { + if (!DefaultLogger::isNullLogger()) + { + sprintf(buffer, "Found non-UV mapped texture (%s,%i). Mapping type: %s", + TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, + MappingTypeToString(mapping)); + + DefaultLogger::get()->info(buffer); + } + + aiAxis axis; + + // Get further properties - currently only the major axis + for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) + { + aiMaterialProperty* prop2 = mat->mProperties[a2]; + if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) + continue; + + if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) + { + axis = *((aiAxis*)prop2->mData); + break; + } + } + + /* We have found a non-UV mapped texture. Now + * we need to find all meshes using this material + * that we can compute UV channels for them. + */ + for (unsigned int m = 0; m < pScene->mNumMeshes;++m) + { + aiMesh* mesh = pScene->mMeshes[m]; + if (mesh->mMaterialIndex != i) continue; + + switch (mapping) + { + case aiTextureMapping_SPHERE: + ComputeSphereMapping(mesh,axis); + break; + case aiTextureMapping_CYLINDER: + ComputeCylinderMapping(mesh,axis); + break; + case aiTextureMapping_PLANE: + ComputePlaneMapping(mesh,axis); + break; + case aiTextureMapping_BOX: + ComputeBoxMapping(mesh); + break; + } + } + } + } + } + } + + DefaultLogger::get()->debug("GenUVCoordsProcess finished"); +} diff --git a/code/ComputeUVMappingProcess.h b/code/ComputeUVMappingProcess.h new file mode 100644 index 000000000..8290fad8f --- /dev/null +++ b/code/ComputeUVMappingProcess.h @@ -0,0 +1,125 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 Defines a post processing step to compute UV coordinates + from abstract mappings, such as box or spherical*/ +#ifndef AI_COMPUTEUVMAPPING_H_INC +#define AI_COMPUTEUVMAPPING_H_INC + +#include "BaseProcess.h" +#include "../include/aiMesh.h" + +class ComputeUVMappingTest; +namespace Assimp + { + +// --------------------------------------------------------------------------- +/** ComputeUVMappingProcess - converts special mappings, such as spherical, + * cylindrical or boxed to proper UV coordinates for rendering. +*/ +class ASSIMP_API ComputeUVMappingProcess : public BaseProcess +{ + friend class Importer; + friend class ::ComputeUVMappingTest; // grant the unit test full access to us + +protected: + /** Constructor to be privately used by Importer */ + ComputeUVMappingProcess(); + + /** Destructor, private as well */ + ~ComputeUVMappingProcess(); + +public: + // ------------------------------------------------------------------- + /** Returns whether the processing step is present in the given flag field. + * @param pFlags The processing flags the importer was called with. A bitwise + * combination of #aiPostProcessSteps. + * @return true if the process is present in this flag fields, false if not. + */ + bool IsActive( unsigned int pFlags) const; + + // ------------------------------------------------------------------- + /** Executes the post processing step on the given imported data. + * At the moment a process is not supposed to fail. + * @param pScene The imported data to work at. + */ + void Execute( aiScene* pScene); + +protected: + + // ------------------------------------------------------------------- + /** Computes spherical UV coordinates for a mesh + * + * @param mesh Mesh to be processed + * @param axis Main axis + * @return Index of the newly generated UV channel + */ + unsigned int ComputeSphereMapping(aiMesh* mesh,aiAxis axis); + + // ------------------------------------------------------------------- + /** Computes cylindrical UV coordinates for a mesh + * + * @param mesh Mesh to be processed + * @param axis Main axis + * @return Index of the newly generated UV channel + */ + unsigned int ComputeCylinderMapping(aiMesh* mesh,aiAxis axis); + + // ------------------------------------------------------------------- + /** Computes planar UV coordinates for a mesh + * + * @param mesh Mesh to be processed + * @param axis Main axis + * @return Index of the newly generated UV channel + */ + unsigned int ComputePlaneMapping(aiMesh* mesh,aiAxis axis); + + // ------------------------------------------------------------------- + /** Computes cubic UV coordinates for a mesh + * + * @param mesh Mesh to be processed + * @return Index of the newly generated UV channel + */ + unsigned int ComputeBoxMapping(aiMesh* mesh); +}; + +} // end of namespace Assimp + +#endif // AI_COMPUTEUVMAPPING_H_INC diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index 1ea025c55..969b702f1 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -141,6 +141,10 @@ void ConvertToLHProcess::Execute( aiScene* pScene) for( unsigned int a = 0; a < pScene->mNumMeshes; a++) ProcessMesh( pScene->mMeshes[a]); + // process all materials - we need to adjust UV transformations + for( unsigned int a = 0; a < pScene->mNumMaterials; a++) + ProcessMaterial( pScene->mMaterials[a]); + // transform all animation channels affecting the root node as well for( unsigned int a = 0; a < pScene->mNumAnimations; a++) { @@ -155,6 +159,25 @@ void ConvertToLHProcess::Execute( aiScene* pScene) DefaultLogger::get()->debug("ConvertToLHProcess finished"); } +// ------------------------------------------------------------------------------------------------ +// Converts a single material to left handed coordinates. +void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat) +{ + for (unsigned int a = 0; a < mat->mNumProperties;++a) + { + aiMaterialProperty* prop = mat->mProperties[a]; + if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) + { + ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); + aiUVTransform* uv = (aiUVTransform*)prop->mData; + + // just flip it, that's everything + uv->mTranslation.y *= -1.f; + uv->mRotation *= -1.f; + } + } +} + // ------------------------------------------------------------------------------------------------ // Converts a single mesh to left handed coordinates. void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh) diff --git a/code/ConvertToLHProcess.h b/code/ConvertToLHProcess.h index 696d430a5..1f8fca2bd 100644 --- a/code/ConvertToLHProcess.h +++ b/code/ConvertToLHProcess.h @@ -108,6 +108,13 @@ protected: */ void ProcessMesh( aiMesh* pMesh); + // ------------------------------------------------------------------- + /** Converts a single material to left handed coordinates. + * This simply means all UV offsets are inverted. + * @param mat The material to convert. + */ + void ProcessMaterial (aiMaterial* mat); + // ------------------------------------------------------------------- /** Converts the given animation to LH coordinates. * The rotation and translation keys are transformed, the scale keys diff --git a/code/FindDegenerates.cpp b/code/FindDegenerates.cpp index dbe42c5b5..3a9cf8bb6 100644 --- a/code/FindDegenerates.cpp +++ b/code/FindDegenerates.cpp @@ -108,6 +108,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) // application attemps to access this data. face.mIndices[face.mNumIndices] = 0xdeadbeef; + if(first) { ++deg; diff --git a/code/FindInvalidDataProcess.cpp b/code/FindInvalidDataProcess.cpp index 824d88afa..ebb4e79f0 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/FindInvalidDataProcess.cpp @@ -284,7 +284,16 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) { bool ret = false; - std::vector dirtyMask; + std::vector dirtyMask(pMesh->mNumVertices,true); + + // Ignore elements that are not referenced by vertices. + // (they are, for example, caused by the FindDegenerates step) + for (unsigned int m = 0; m < pMesh->mNumFaces;++m) + { + const aiFace& f = pMesh->mFaces[m]; + for (unsigned int i = 0; i < f.mNumIndices;++i) + dirtyMask[f.mIndices[i]] = false; + } // process vertex positions if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask)) @@ -311,9 +320,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) // -- we don't validate vertex colors, it's difficult to say whether // they are invalid or not. - // normals and tangents are undefined for point and line faces. - // we generate a small lookup table in which we mark all - // indices into the normals/tangents array that MAY be invalid + // Normals and tangents are undefined for point and line faces. if (pMesh->mNormals || pMesh->mTangents) { if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes || @@ -322,8 +329,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes || aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) { - // we need the lookup table - dirtyMask.resize(pMesh->mNumVertices,false); + // We need to update the lookup-table for (unsigned int m = 0; m < pMesh->mNumFaces;++m) { const aiFace& f = pMesh->mFaces[m]; @@ -334,27 +340,29 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) else if (1 == f.mNumIndices)dirtyMask[f.mIndices[0]] = true; } } + // Normals, tangents and bitangents are undefined for + // the whole mesh (and should not even be there) else return ret; } - // process mesh normals + // Process mesh normals if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices, "normals",dirtyMask,true,false)) ret = true; - // process mesh tangents + // Process mesh tangents if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices, "tangents",dirtyMask)) { - delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; + delete[] pMesh->mTangents; pMesh->mTangents = NULL; ret = true; } - // process mesh bitangents + // Process mesh bitangents if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices, "bitangents",dirtyMask)) { - delete[] pMesh->mTangents; pMesh->mTangents = NULL; + delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; ret = true; } } diff --git a/code/Hash.h b/code/Hash.h index a17a0e177..f52134688 100644 --- a/code/Hash.h +++ b/code/Hash.h @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // http://www.azillionmonkeys.com/qed/hash.html // (incremental version of the hashing function) // (stdint.h should have been been included here) +// ------------------------------------------------------------------------------------------------ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) diff --git a/code/IRRMeshLoader.cpp b/code/IRRMeshLoader.cpp index 044ebcbc5..ca7833522 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/IRRMeshLoader.cpp @@ -429,20 +429,6 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) // lightmap settings to the last texture. if (cnt && matFlags & AI_IRRMESH_MAT_lightmap) { - static const char* PropArray[4] = - { - AI_MATKEY_TEXBLEND_DIFFUSE(0), - AI_MATKEY_TEXBLEND_DIFFUSE(1), - AI_MATKEY_TEXBLEND_DIFFUSE(2), - AI_MATKEY_TEXBLEND_DIFFUSE(3) - }; - static const char* PropArray2[4] = - { - AI_MATKEY_TEXOP_DIFFUSE(0), - AI_MATKEY_TEXOP_DIFFUSE(1), - AI_MATKEY_TEXOP_DIFFUSE(2), - AI_MATKEY_TEXOP_DIFFUSE(3) - }; float f = 1.f; // Additive lightmap? @@ -460,8 +446,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) { f = 4.f; } - mat->AddProperty( &f, 1, PropArray [cnt-1]); - mat->AddProperty( &op,1, PropArray2 [cnt-1]); + mat->AddProperty( &f, 1, AI_MATKEY_TEXBLEND_DIFFUSE(cnt-1)); + mat->AddProperty( &op,1, AI_MATKEY_TEXOP_DIFFUSE(cnt-1)); } return mat; @@ -600,13 +586,28 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, if (curMat) { DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please"); - delete curMat; + delete curMat;curMat = NULL; } curMat = ParseMaterial(curMatFlags); } /* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices")) { int num = reader->getAttributeValueAsInt("vertexCount"); + + if (!num) + { + // This is possible ... remove the mesh from the list + // and skip further reading + + DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices"); + + delete curMat;curMat = NULL; + + curMesh = NULL; + textMeaning = 0; + continue; + } + curVertices.reserve (num); curNormals.reserve (num); curColors.reserve (num); @@ -648,6 +649,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, } else if (ASSIMP_stricmp("standard", t)) { + delete curMat; DefaultLogger::get()->warn("IRRMESH: Unknown vertex format"); } else vertexFormat = 0; @@ -655,8 +657,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, } else if (!ASSIMP_stricmp(reader->getNodeName(),"indices")) { - if (curVertices.empty()) + if (curVertices.empty() && curMat) + { + delete curMat; throw new ImportErrorException("IRRMESH: indices must come after vertices"); + } textMeaning = 2; @@ -665,6 +670,23 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, // allocate storage for all faces curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount"); + if (!curMesh->mNumVertices) + { + // This is possible ... remove the mesh from the list + // and skip further reading + + DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices"); + + // mesh - away + delete curMesh; curMesh = NULL; + + // material - away + delete curMat;curMat = NULL; + + textMeaning = 0; + continue; + } + if (curMesh->mNumVertices % 3) { DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3"); @@ -888,7 +910,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile, }; } - // end of the last buffer. A material and a mesh should be there + // End of the last buffer. A material and a mesh should be there if (curMat || curMesh) { if ( !curMat || !curMesh) diff --git a/code/Importer.cpp b/code/Importer.cpp index cdfe25d6c..21cb2a441 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -189,6 +189,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BUILD_NO_SORTBYPTYPE_PROCESS # include "SortByPTypeProcess.h" #endif +#ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS +# include "ComputeUVMappingProcess.h" +#endif +#ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS +# include "TextureTransform.h" +#endif + using namespace Assimp; @@ -290,7 +297,7 @@ Importer::Importer() : mImporter.push_back( new ColladaLoader()); #endif - // add an instance of each post processing step here in the order + // Add an instance of each post processing step here in the order // of sequence it is executed. steps that are added here are not validated - // as RegisterPPStep() does - all dependencies must be there. mPostProcessingSteps.reserve(25); @@ -310,6 +317,17 @@ Importer::Importer() : #endif + +#ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS + mPostProcessingSteps.push_back( new ComputeUVMappingProcess()); +#endif +#ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS + mPostProcessingSteps.push_back( new TextureTransformStep()); +#endif + + + + #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess()); #endif @@ -371,6 +389,9 @@ Importer::Importer() : mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess()); #endif + + + // allocate a SharedPostProcessInfo object and store pointers to it // in all post-process steps in the list. mPPShared = new SharedPostProcessInfo(); @@ -412,7 +433,9 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) { ai_assert(NULL != pImp); - // check whether we would have two loaders for the same file extension now + // Check whether we would have two loaders for the same file extension now + // This is absolutely OK, but we should warn the developer of the new + // loader that his code will propably never be called. std::string st; pImp->GetExtensionList(st); @@ -423,15 +446,14 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) { if (IsExtensionSupported(std::string(sz))) { - DefaultLogger::get()->error(std::string( "The file extension " ) + sz + " is already in use"); - return AI_FAILURE; + DefaultLogger::get()->warn(std::string( "The file extension " ) + sz + " is already in use"); } sz = ::strtok(NULL,";"); } #endif // add the loader - this->mImporter.push_back(pImp); + mImporter.push_back(pImp); DefaultLogger::get()->info("Registering custom importer: " + st); return AI_SUCCESS; } @@ -729,7 +751,7 @@ const std::string& Importer::GetPropertyString(const char* szName, } // ------------------------------------------------------------------------------------------------ -void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) +inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) { iScene += sizeof(aiNode); iScene += sizeof(unsigned int) * pcNode->mNumMeshes; @@ -816,6 +838,10 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const } in.total += in.animations; + // add all cameras and all lights + in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras; + in.total += in.lights = sizeof(aiLight) * mScene->mNumLights; + // add all nodes AddNodeWeight(in.nodes,mScene->mRootNode); in.total += in.nodes; @@ -832,6 +858,5 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const } } in.total += in.materials; - return; } diff --git a/code/LWOBLoader.cpp b/code/LWOBLoader.cpp index 51ef056ba..f30107494 100644 --- a/code/LWOBLoader.cpp +++ b/code/LWOBLoader.cpp @@ -45,11 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" -// internal headers +// Internal headers #include "LWOLoader.h" -#include "MaterialSystem.h" -#include "ByteSwap.h" - using namespace Assimp; diff --git a/code/LWOFileData.h b/code/LWOFileData.h index 130fb083d..408fc74ac 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -62,6 +62,7 @@ namespace LWO { #define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L','W','O','B') #define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L','W','O','2') +#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L','X','O','B') // chunks specific to the LWOB format #define AI_LWO_SRFS AI_IFF_FOURCC('S','R','F','S') @@ -178,6 +179,7 @@ namespace LWO { #define AI_LWO_AVAL AI_IFF_FOURCC('A','V','A','L') #define AI_LWO_GVAL AI_IFF_FOURCC('G','V','A','L') #define AI_LWO_BLOK AI_IFF_FOURCC('B','L','O','K') +#define AI_LWO_VCOL AI_IFF_FOURCC('V','C','O','L') /* texture layer */ #define AI_LWO_TYPE AI_IFF_FOURCC('T','Y','P','E') @@ -236,10 +238,13 @@ namespace LWO { /* VMAP types */ #define AI_LWO_TXUV AI_IFF_FOURCC('T','X','U','V') -#define AI_LWO_RGB AI_IFF_FOURCC(' ','R','G','B') +#define AI_LWO_RGB AI_IFF_FOURCC('R','G','B',' ') #define AI_LWO_RGBA AI_IFF_FOURCC('R','G','B','A') #define AI_LWO_WGHT AI_IFF_FOURCC('W','G','H','T') +// MODO extension - per-vertex normal vectors +#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M') + // --------------------------------------------------------------------------- /** \brief Data structure for a face in a LWO file @@ -318,15 +323,11 @@ struct VColorChannel : public VMapEntry register unsigned int m = num*dims; rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs - rawData.resize(m,0.f); + rawData.resize(m); + + for (aiColor4D* p = (aiColor4D*)&rawData[0]; p < (aiColor4D*)&rawData[m-1]; ++p) + *p = aiColor4D(); - for (std::vector::iterator it = rawData.begin(), end = rawData.end(); - it != end;++it ) - { - for (unsigned int i = 0; i< 3;++i,++it) - *it = 0.f; - *it = 1.f; - } abAssigned.resize(num,false); } }; @@ -351,6 +352,15 @@ struct WeightChannel : public VMapEntry {} }; +// --------------------------------------------------------------------------- +/** \brief Represents a vertex-normals channel (MODO extension) + */ +struct NormalChannel : public VMapEntry +{ + NormalChannel() + : VMapEntry(3) + {} +}; // --------------------------------------------------------------------------- /** \brief Data structure for a LWO file texture @@ -515,8 +525,10 @@ struct Surface , mColorHighlights (0.f) , mMaximumSmoothAngle (0.f) // 0 == not specified, no smoothing , mVCMap ("") + , mVCMapType (AI_LWO_RGBA) , mIOR (1.f) // vakuum , mBumpIntensity (1.f) + , mWireframe (false) {} //! Name of the surface @@ -537,6 +549,7 @@ struct Surface //! Vertex color map to be used to color the surface std::string mVCMap; + uint32_t mVCMapType; //! Names of the special shaders to be applied to the surface ShaderList mShaders; @@ -554,6 +567,9 @@ struct Surface //! Bump intensity scaling float mBumpIntensity; + + //! Wireframe flag + bool mWireframe; }; // --------------------------------------------------------------------------- @@ -606,6 +622,9 @@ struct Layer /** UV channel list from the file */ UVChannelList mUVChannels; + /** Normal vector channel from the file */ + NormalChannel mNormals; + /** Temporary face list from the file*/ FaceList mFaces; diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index 811f326ae..8d2248efa 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -79,11 +79,10 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const if (extension.length() < 4)return false; if (extension[0] != '.')return false; - if (extension[1] != 'l' && extension[1] != 'L')return false; - if (extension[2] != 'w' && extension[2] != 'W')return false; - if (extension[3] != 'o' && extension[3] != 'O')return false; - - return true; + return ! (extension[1] != 'l' && extension[1] != 'L' || + extension[2] != 'w' && extension[2] != 'W' && + extension[2] != 'x' && extension[2] != 'X' || + extension[3] != 'o' && extension[3] != 'O'); } // ------------------------------------------------------------------------------------------------ @@ -151,11 +150,29 @@ void LWOImporter::InternReadFile( const std::string& pFile, LoadLWOBFile(); } - // new lightwave format + // New lightwave format else if (AI_LWO_FOURCC_LWO2 == fileType) { DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)"); + } + // MODO file format + else if (AI_LWO_FOURCC_LXOB == fileType) + { + DefaultLogger::get()->info("LWO file format: LXOB (Modo)"); + } + // we don't know this format + else + { + char szBuff[5]; + szBuff[0] = (char)(fileType >> 24u); + szBuff[1] = (char)(fileType >> 16u); + szBuff[2] = (char)(fileType >> 8u); + szBuff[3] = (char)(fileType); + throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff); + } + if (AI_LWO_FOURCC_LWOB != fileType) + { mIsLWO2 = true; LoadLWO2File(); @@ -172,17 +189,6 @@ void LWOImporter::InternReadFile( const std::string& pFile, } } - // we don't know this format - else - { - char szBuff[5]; - szBuff[0] = (char)(fileType >> 24u); - szBuff[1] = (char)(fileType >> 16u); - szBuff[2] = (char)(fileType >> 8u); - szBuff[3] = (char)(fileType); - throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff); - } - // now, as we have loaded all data, we can resolve cross-referenced tags and clips ResolveTags(); ResolveClips(); @@ -249,7 +255,7 @@ void LWOImporter::InternReadFile( const std::string& pFile, mesh->mNumVertices += layer.mFaces[*it].mNumIndices; } - aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiVector3D *nrm = NULL, * pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mMaterialIndex = i; @@ -276,8 +282,12 @@ void LWOImporter::InternReadFile( const std::string& pFile, pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices]; // LightWave doesn't support more than 2 UV components + // so we can directly setup this value mesh->mNumUVComponents[0] = 2; } + + if (layer.mNormals.name.length()) + nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices]; aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS]; for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui) @@ -320,11 +330,24 @@ void LWOImporter::InternReadFile( const std::string& pFile, pp++; } + // process normals (MODO extension) + if (nrm) + { + *nrm++ = ((aiVector3D*)&layer.mNormals.rawData[0])[idx]; + } + // process vertex colors for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) { if (0xffffffff == vVColorIndices[w])break; - *(pvVC[w])++ = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx]; + *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx]; + + // If a RGB color map is explicitly requested delete the + // alpha channel - it could theoretically be != 1. + if(_mSurfaces[i].mVCMapType == AI_LWO_RGB) + pvVC[w]->a = 1.f; + + pvVC[w]++; } #if 0 @@ -343,16 +366,19 @@ void LWOImporter::InternReadFile( const std::string& pFile, pf++; } - // compute normal vectors for the mesh - we can't use our GenSmoothNormal- - // Step here since it wouldn't handle smoothing groups correctly for LWO. - // So we use a separate implementation. - ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]); - + if (!mesh->mNormals) + { + // Compute normal vectors for the mesh - we can't use our GenSmoothNormal- + // Step here since it wouldn't handle smoothing groups correctly for LWO. + // So we use a separate implementation. + ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]); + } + else DefaultLogger::get()->debug("LWO2: No need to compute normals, they're already there"); ++p; } } - // generate nodes to render the mesh. Store the parent index + // Generate nodes to render the mesh. Store the parent index // in the mParent member of the nodes aiNode* pcNode = new aiNode(); apcNodes.push_back(pcNode); @@ -367,7 +393,7 @@ void LWOImporter::InternReadFile( const std::string& pFile, if (apcNodes.empty() || apcMeshes.empty()) throw new ImportErrorException("LWO: No meshes loaded"); - // the RemoveRedundantMaterials step will clean this up later + // The RemoveRedundantMaterials step will clean this up later pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()]; for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat) { @@ -510,7 +536,6 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector& // ------------------------------------------------------------------------------------------------ void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector& apcNodes) { - parent -= 1; for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i) { if (i == parent)continue; @@ -706,10 +731,15 @@ void LWOImporter::LoadLWO2Polygons(unsigned int length) LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); uint32_t type = GetU4(); - if (type != AI_LWO_FACE) + // Determine the type of the polygons + switch (type) { - DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunks are supported."); - return; + case AI_LWO_PTCH: + case AI_LWO_FACE: + + break; + default: + DefaultLogger::get()->warn("LWO2: Unsupported polygon type (PTCH and FACE are supported)"); } // first find out how many faces and vertices we'll finally need @@ -829,19 +859,26 @@ VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPol // ------------------------------------------------------------------------------------------------ template -void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx) +inline void CreateNewEntry(T& chan, unsigned int srcIdx) +{ + if (!chan.name.length())return; + + chan.abAssigned[srcIdx] = true; + chan.abAssigned.resize(chan.abAssigned.size()+1,false); + + for (unsigned int a = 0; a < chan.dims;++a) + chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]); +} + +// ------------------------------------------------------------------------------------------------ +template +inline void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx) { for (typename std::vector< T >::iterator it = list.begin(), end = list.end(); it != end;++it) { - T& chan = *it; - - chan.abAssigned[srcIdx] = true; - chan.abAssigned.resize(chan.abAssigned.size()+1,false); - - for (unsigned int a = 0; a < chan.dims;++a) - chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]); + CreateNewEntry( *it, srcIdx ); } } @@ -911,7 +948,24 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) } base = FindEntry(mCurLayer->mVColorChannels,name,perPoly); break; - default: return; + + case AI_LWO_MODO_NORM: + + /* This is a non-standard extension chunk used by Luxology's MODO. + * It stores per-vertex normals. This VMAP exists just once, has + * 3 dimensions and is btw extremely beautiful. + */ + if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length()) + return; + + DefaultLogger::get()->info("Non-standard extension: MODO VMAP.NORM.vert_normals"); + + mCurLayer->mNormals.name = name; + base = & mCurLayer->mNormals; + break; + + default: + return; }; base->Allocate((unsigned int)mCurLayer->mTempPoints.size()); @@ -946,20 +1000,22 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) if (polyIdx >= numFaces) { DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range"); - mFileBuffer += base->dims*4;continue; + mFileBuffer += base->dims*4; + continue; } LWO::Face& src = list[polyIdx]; - refList.resize(refList.size()+src.mNumIndices, 0xffffffff); - // generate new vertex positions + // generate a new unique vertex for the corresponding index - but only + // if we can find the index in the face for (unsigned int i = 0; i < src.mNumIndices;++i) { register unsigned int srcIdx = src.mIndices[i]; - if (idx == srcIdx) - { - idx = (unsigned int)pointList.size(); - } + if (idx != srcIdx)continue; + + refList.resize(refList.size()+1, 0xffffffff); + + idx = (unsigned int)pointList.size(); src.mIndices[i] = (unsigned int)pointList.size(); // store the index of the new vertex in the old vertex @@ -971,6 +1027,7 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) CreateNewEntry(mCurLayer->mVColorChannels, srcIdx ); CreateNewEntry(mCurLayer->mUVChannels, srcIdx ); CreateNewEntry(mCurLayer->mWeightChannels, srcIdx ); + CreateNewEntry(mCurLayer->mNormals, srcIdx ); } } } diff --git a/code/LWOLoader.h b/code/LWOLoader.h index 7bb318cb4..03a1d2e4c 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -100,7 +100,7 @@ protected: */ void GetExtensionList(std::string& append) { - append.append("*.lwo"); + append.append("*.lwo;*.lxo"); } // ------------------------------------------------------------------- @@ -257,12 +257,10 @@ private: * * @param pcMat Output material * @param in Input texture list - * @param type Type identifier of the texture list. This is the string - * that appears in the middle of all material keys - e.g. "diffuse", - * "shininess", "glossiness" or "specular". + * @param type Type identifier of the texture list */ bool HandleTextures(MaterialHelper* pcMat, const TextureList& in, - const char* type); + aiTextureType type); // ------------------------------------------------------------------- /** Adjust a texture path diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index 93a1897ea..d255b3976 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -59,16 +59,20 @@ T lerp(const T& one, const T& two, float val) } // ------------------------------------------------------------------------------------------------ +// Convert a lightwave mapping mode to our's inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) { switch (in) { case LWO::Texture::REPEAT: return aiTextureMapMode_Wrap; + case LWO::Texture::MIRROR: return aiTextureMapMode_Mirror; + case LWO::Texture::RESET: DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET"); + // fall though here case LWO::Texture::EDGE: return aiTextureMapMode_Clamp; @@ -77,23 +81,67 @@ inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) } // ------------------------------------------------------------------------------------------------ -bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, const char* type) +bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, aiTextureType type) { - ai_assert(NULL != pcMat && NULL != type); + ai_assert(NULL != pcMat); unsigned int cur = 0, temp = 0; - char buffer[512]; aiString s; bool ret = false; for (TextureList::const_iterator it = in.begin(), end = in.end(); it != end;++it) { - if (!(*it).enabled || !(*it).bCanUse || 0xffffffff == (*it).mRealUVIndex)continue; + if (!(*it).enabled || !(*it).bCanUse)continue; ret = true; - // add the path to the texture - sprintf(buffer,"$tex.file.%s[%i]",type,cur); + // Convert lightwave's mapping modes to ours. We let them + // as they are, the GenUVcoords step will compute UV + // channels if they're not there. + + aiTextureMapping mapping; + switch ((*it).mapMode) + { + case LWO::Texture::Planar: + mapping = aiTextureMapping_PLANE; + break; + case LWO::Texture::Cylindrical: + mapping = aiTextureMapping_CYLINDER; + break; + case LWO::Texture::Spherical: + mapping = aiTextureMapping_SPHERE; + break; + case LWO::Texture::Cubic: + mapping = aiTextureMapping_BOX; + break; + case LWO::Texture::FrontProjection: + DefaultLogger::get()->error("LWO2: Unsupported texture mapping: FrontProjection"); + mapping = aiTextureMapping_OTHER; + break; + case LWO::Texture::UV: + { + if( 0xffffffff == (*it).mRealUVIndex ) + { + // We have no UV index for this texture, so we can't display it + continue; + } + + // add the UV source index + temp = (*it).mRealUVIndex; + pcMat->AddProperty((int*)&temp,1,AI_MATKEY_UVWSRC(type,cur)); + + mapping = aiTextureMapping_UV; + } + break; + }; + + if (mapping != aiTextureMapping_UV) + { + // Setup the main axis (the enum values map one to one) + pcMat->AddProperty((int*)&(*it).majorAxis,1,AI_MATKEY_TEXMAP_AXIS(type,cur)); + DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping"); + } + // The older LWOB format does not use indirect references to clips. // The file name of a texture is directly specified in the tex chunk. @@ -133,14 +181,12 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, c AdjustTexturePath(ss); s.Set(ss); } - pcMat->AddProperty(&s,buffer); + pcMat->AddProperty(&s,AI_MATKEY_TEXTURE(type,cur)); // add the blend factor - sprintf(buffer,"$tex.blend.%s[%i]",type,cur); - pcMat->AddProperty(&(*it).mStrength,1,buffer); + pcMat->AddProperty(&(*it).mStrength,1,AI_MATKEY_TEXBLEND(type,cur)); // add the blend operation - sprintf(buffer,"$tex.op.%s[%i]",type,cur); switch ((*it).blendType) { case LWO::Texture::Normal: @@ -166,22 +212,18 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, c DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement"); } - pcMat->AddProperty((int*)&temp,1,buffer); + pcMat->AddProperty((int*)&temp,1,AI_MATKEY_TEXOP(type,cur)); - // add the UV source index - sprintf(buffer,"$tex.uvw.%s[%i]",type,cur); - temp = (*it).mRealUVIndex; - pcMat->AddProperty((int*)&temp,1,buffer); + // setup the mapping mode + pcMat->AddProperty((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur)); // add the u-wrapping - sprintf(buffer,"$tex.mapmodeu.%s[%i]",type,cur); temp = (unsigned int)GetMapMode((*it).wrapModeWidth); - pcMat->AddProperty((int*)&temp,1,buffer); + pcMat->AddProperty((int*)&temp,1,AI_MATKEY_MAPPINGMODE_U(type,cur)); // add the v-wrapping - sprintf(buffer,"$tex.mapmodev.%s[%i]",type,cur); temp = (unsigned int)GetMapMode((*it).wrapModeHeight); - pcMat->AddProperty((int*)&temp,1,buffer); + pcMat->AddProperty((int*)&temp,1,AI_MATKEY_MAPPINGMODE_V(type,cur)); ++cur; } @@ -237,17 +279,20 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE); // opacity - float f = 1.0f-surf.mTransparency; - pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); + if (10e10f != surf.mTransparency) + { + float f = 1.0f-surf.mTransparency; + pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); + } // ADD TEXTURES to the material // TODO: find out how we can handle COLOR textures correctly... - bool b = HandleTextures(pcMat,surf.mColorTextures,"diffuse"); - b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,"diffuse")); - HandleTextures(pcMat,surf.mSpecularTextures,"specular"); - HandleTextures(pcMat,surf.mGlossinessTextures,"shininess"); - HandleTextures(pcMat,surf.mBumpTextures,"height"); - HandleTextures(pcMat,surf.mOpacityTextures,"opacity"); + bool b = HandleTextures(pcMat,surf.mColorTextures,aiTextureType_DIFFUSE); + b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,aiTextureType_DIFFUSE)); + HandleTextures(pcMat,surf.mSpecularTextures,aiTextureType_SPECULAR); + HandleTextures(pcMat,surf.mGlossinessTextures,aiTextureType_SHININESS); + HandleTextures(pcMat,surf.mBumpTextures,aiTextureType_HEIGHT); + HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY); // now we need to know which shader we must use // iterate through the shader list of the surface and @@ -255,7 +300,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end(); it != end;++it) { - if (!(*it).enabled)continue; + //if (!(*it).enabled)continue; if ((*it).functionName == "LW_SuperCelShader" || (*it).functionName == "AH_CelShader") { @@ -298,20 +343,11 @@ void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer, for (TextureList::iterator it = list.begin(), end = list.end(); it != end;++it) { - if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex)continue; - switch ((*it).mapMode) + // Ignore textures with non-UV mappings for the moment. + if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex || + (*it).mapMode != LWO::Texture::UV) { - // TODO: implement these special mappings ... - case LWO::Texture::Spherical: - case LWO::Texture::Cylindrical: - case LWO::Texture::Cubic: - case LWO::Texture::Planar: - case LWO::Texture::FrontProjection: - - DefaultLogger::get()->warn("LWO2: Only UV mapping is currently supported."); continue; - - default: ; } for (unsigned int i = 0; i < layer.mUVChannels.size();++i) { @@ -391,6 +427,9 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex ) switch (head->type) { case AI_LWO_PROJ: + tex.mapMode = (Texture::MappingMode)GetU2(); + break; + case AI_LWO_WRAP: tex.wrapModeWidth = (Texture::Wrap)GetU2(); tex.wrapModeHeight = (Texture::Wrap)GetU2(); break; @@ -650,10 +689,45 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) // transparency case AI_LWO_TRAN: { + if (surf.mTransparency == 10e10f)break; + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4); surf.mTransparency = GetF4(); break; } + // transparency mode + case AI_LWO_ALPH: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ALPH,6); + uint16_t mode = GetU2(); + switch (mode) + { + // The surface has no effect on the alpha channel when rendered + case 0: + surf.mTransparency = 10e10f; + break; + + // The alpha channel will be written with the constant value + // following the mode in the subchunk. + case 1: + surf.mTransparency = GetF4(); + break; + + // The alpha value comes from the shadow density + case 3: + DefaultLogger::get()->error("LWO2: Unsupported alpha mode: shadow_density"); + surf.mTransparency = 10e10f; + } + break; + } + // wireframe mode + case AI_LWO_LINE: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LINE,2); + if (GetU2() & 0x1) + surf.mWireframe = true; + break; + } // glossiness case AI_LWO_GLOS: { @@ -696,6 +770,18 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) surf.mMaximumSmoothAngle = GetF4(); break; } + // vertex color channel to be applied to the surface + case AI_LWO_VCOL: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,VCOL,12); + surf.mDiffuseValue *= GetF4(); // strength + ReadVSizedIntLWO2(mFileBuffer); // skip envelope + surf.mVCMapType = GetU4(); // type of the channel + + // name of the channel + GetS0(surf.mVCMap, (unsigned int) (next - mFileBuffer )); + break; + } // surface bock entry case AI_LWO_BLOK: { diff --git a/code/MDLFileData.h b/code/MDLFileData.h index 7c82329e7..51eba243c 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -110,7 +110,7 @@ namespace MDL { // material key that is set for dummy materials that are // just referencing another material #if (!defined AI_MDL7_REFERRER_MATERIAL) -# define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&" +# define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&",0,0 #endif // --------------------------------------------------------------------------- diff --git a/code/MaterialSystem.cpp b/code/MaterialSystem.cpp index da512dc1c..4ee093983 100644 --- a/code/MaterialSystem.cpp +++ b/code/MaterialSystem.cpp @@ -43,15 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -// we are using sprintf only on fixed-size buffers, so the -// compiler should automatically expand the template sprintf_s<> -#if _MSC_VER >= 1400 -# define sprintf sprintf_s -#endif - // ------------------------------------------------------------------------------------------------ aiReturn aiGetMaterialProperty(const aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, const aiMaterialProperty** pPropOut) { ai_assert (pMat != NULL); @@ -59,22 +55,25 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat, ai_assert (pPropOut != 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) { - if (NULL != pMat->mProperties[i]) - { - if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey )) - { - *pPropOut = pMat->mProperties[i]; - return AI_SUCCESS; - } - } + *pPropOut = pMat->mProperties[i]; + return AI_SUCCESS; } + } *pPropOut = NULL; return AI_FAILURE; } + // ------------------------------------------------------------------------------------------------ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, float* pOut, unsigned int* pMax) { @@ -84,56 +83,51 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, for (unsigned int i = 0; i < pMat->mNumProperties;++i) { - if (NULL != pMat->mProperties[i]) + aiMaterialProperty* prop = pMat->mProperties[i]; + + if (prop && !::strcmp( prop->mKey.data, pKey ) && + prop->mSemantic == type && prop->mIndex == index) { - if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey )) + // data is given in floats, simply copy it + if( aiPTI_Float == pMat->mProperties[i]->mType || + aiPTI_Buffer == pMat->mProperties[i]->mType) { - // 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); + unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float); - if (NULL != pMax) - iWrite = *pMax < iWrite ? *pMax : iWrite; + if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite; + ::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (float)); - memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (float)); - - if (NULL != 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 (NULL != pMax) - iWrite = *pMax < iWrite ? *pMax : iWrite; - - for (unsigned int a = 0; a < iWrite;++a) - { - pOut[a] = (float) ((int*)pMat->mProperties[i]->mData)[a]; - } - if (NULL != pMax) - *pMax = iWrite; - } - // it is a string ... no way to read something out of this - else - { - if (NULL != pMax) - *pMax = 0; - return AI_FAILURE; - } - return AI_SUCCESS; + 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; } } return AI_FAILURE; } + // ------------------------------------------------------------------------------------------------ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, int* pOut, unsigned int* pMax) { @@ -142,69 +136,66 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, ai_assert (pOut != NULL); for (unsigned int i = 0; i < pMat->mNumProperties;++i) { - if (NULL != pMat->mProperties[i]) + aiMaterialProperty* prop = pMat->mProperties[i]; + + if (prop && !::strcmp( prop->mKey.data, pKey ) && + prop->mSemantic == type && prop->mIndex == index) { - if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey )) + // data is given in ints, simply copy it + if( aiPTI_Integer == pMat->mProperties[i]->mType || + aiPTI_Buffer == pMat->mProperties[i]->mType) { - // 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); + unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(int); - if (NULL != pMax) - iWrite = *pMax < iWrite ? *pMax : iWrite; + if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite; + ::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (int)); - memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (int)); - - if (NULL != 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); - - if (NULL != pMax) - iWrite = *pMax < iWrite ? *pMax : iWrite; - - for (unsigned int a = 0; a < iWrite;++a) - { - pOut[a] = (int) ((float*)pMat->mProperties[i]->mData)[a]; - } - if (NULL != pMax) - *pMax = iWrite; - } - // it is a string ... no way to read something out of this - else - { - if (NULL != pMax) - *pMax = 0; - return AI_FAILURE; - } - return AI_SUCCESS; + 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); + + 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; } } return AI_FAILURE; } + // ------------------------------------------------------------------------------------------------ aiReturn aiGetMaterialColor(const aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, aiColor4D* pOut) { unsigned int iMax = 4; - aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,(float*)pOut,&iMax); + 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; return eRet; } + // ------------------------------------------------------------------------------------------------ aiReturn aiGetMaterialString(const aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, aiString* pOut) { ai_assert (pMat != NULL); @@ -213,37 +204,39 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat, for (unsigned int i = 0; i < pMat->mNumProperties;++i) { - if (NULL != pMat->mProperties[i]) + aiMaterialProperty* prop = pMat->mProperties[i]; + + if (prop && !::strcmp( prop->mKey.data, pKey ) && + prop->mSemantic == type && prop->mIndex == index) { - if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey )) + if( aiPTI_String == pMat->mProperties[i]->mType) { - 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; + 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; } } return AI_FAILURE; } + // ------------------------------------------------------------------------------------------------ MaterialHelper::MaterialHelper() { - // allocate 5 entries by default - this->mNumProperties = 0; - this->mNumAllocated = 5; - this->mProperties = new aiMaterialProperty*[5]; - return; + // Allocate 5 entries by default + mNumProperties = 0; + mNumAllocated = 5; + mProperties = new aiMaterialProperty*[5]; } + // ------------------------------------------------------------------------------------------------ MaterialHelper::~MaterialHelper() { Clear(); } + // ------------------------------------------------------------------------------------------------ void MaterialHelper::Clear() { @@ -252,7 +245,11 @@ void MaterialHelper::Clear() // delete this entry delete mProperties[i]; } + mNumProperties = 0; + + // The array remains } + // ------------------------------------------------------------------------------------------------ uint32_t MaterialHelper::ComputeHash() { @@ -262,45 +259,62 @@ uint32_t MaterialHelper::ComputeHash() aiMaterialProperty* prop; // NOTE: We need to exclude the material name from the hash - if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME)) + if ((prop = this->mProperties[i]) && ::strcmp(prop->mKey.data,"$mat.name")) { 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 + // We print them to a string to make sure the quality + // of the hash isn't decreased. + char buff[32]; + unsigned int len; + + len = itoa10(buff,prop->mSemantic); + hash = SuperFastHash(buff,len-1,hash); + + len = itoa10(buff,prop->mIndex); + hash = SuperFastHash(buff,len-1,hash); } } return hash; } + // ------------------------------------------------------------------------------------------------ -aiReturn MaterialHelper::RemoveProperty (const char* pKey) +aiReturn MaterialHelper::RemoveProperty (const char* pKey,unsigned int type, + unsigned int index) { ai_assert(NULL != pKey); - for (unsigned int i = 0; i < this->mNumProperties;++i) + for (unsigned int i = 0; i < mNumProperties;++i) { - if (this->mProperties[i]) // just for safety + aiMaterialProperty* prop = mProperties[i]; + + if (prop && !::strcmp( prop->mKey.data, pKey ) && + prop->mSemantic == type && prop->mIndex == index) { - if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey )) + // Delete this entry + delete mProperties[i]; + + // collapse the array behind --. + --mNumProperties; + for (unsigned int a = i; a < mNumProperties;++a) { - // delete this entry - delete this->mProperties[i]; - - // collapse the array behind --. - --this->mNumProperties; - for (unsigned int a = i; a < this->mNumProperties;++a) - { - this->mProperties[a] = this->mProperties[a+1]; - } - return AI_SUCCESS; + mProperties[a] = mProperties[a+1]; } + return AI_SUCCESS; } } return AI_FAILURE; } + // ------------------------------------------------------------------------------------------------ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput, - const unsigned int pSizeInBytes, + unsigned int pSizeInBytes, const char* pKey, + unsigned int type, + unsigned int index, aiPropertyTypeInfo pType) { ai_assert (pInput != NULL); @@ -310,27 +324,30 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput, // first search the list whether there is already an entry // with this name. unsigned int iOutIndex = 0xFFFFFFFF; - for (unsigned int i = 0; i < this->mNumProperties;++i) + for (unsigned int i = 0; i < mNumProperties;++i) { - if (this->mProperties[i]) + aiMaterialProperty* prop = mProperties[i]; + + if (prop && !::strcmp( prop->mKey.data, pKey ) && + prop->mSemantic == type && prop->mIndex == index) { - if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey )) - { - // delete this entry - delete this->mProperties[i]; - iOutIndex = i; - } + // delete this entry + delete this->mProperties[i]; + iOutIndex = i; } } + // Allocate a new material property aiMaterialProperty* pcNew = new aiMaterialProperty(); - // fill this + // Fill this pcNew->mType = pType; + pcNew->mSemantic = type; + pcNew->mIndex = index; pcNew->mDataLength = pSizeInBytes; pcNew->mData = new char[pSizeInBytes]; - memcpy (pcNew->mData,pInput,pSizeInBytes); + ::memcpy (pcNew->mData,pInput,pSizeInBytes); pcNew->mKey.length = ::strlen(pKey); ai_assert ( MAXLEN > pcNew->mKey.length); @@ -338,37 +355,41 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput, if (0xFFFFFFFF != iOutIndex) { - this->mProperties[iOutIndex] = pcNew; + mProperties[iOutIndex] = pcNew; return AI_SUCCESS; } // resize the array ... allocate storage for 5 other properties - if (this->mNumProperties == this->mNumAllocated) + if (mNumProperties == mNumAllocated) { - unsigned int iOld = this->mNumAllocated; - this->mNumAllocated += 5; + unsigned int iOld = mNumAllocated; + mNumAllocated += 5; - aiMaterialProperty** ppTemp = new aiMaterialProperty*[this->mNumAllocated]; + aiMaterialProperty** ppTemp = new aiMaterialProperty*[mNumAllocated]; if (NULL == ppTemp)return AI_OUTOFMEMORY; - ::memcpy (ppTemp,this->mProperties,iOld * sizeof(void*)); + ::memcpy (ppTemp,mProperties,iOld * sizeof(void*)); - delete[] this->mProperties; - this->mProperties = ppTemp; + delete[] mProperties; + mProperties = ppTemp; } // push back ... - this->mProperties[this->mNumProperties++] = pcNew; + mProperties[mNumProperties++] = pcNew; return AI_SUCCESS; } + // ------------------------------------------------------------------------------------------------ aiReturn MaterialHelper::AddProperty (const aiString* pInput, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { - // fix ... don't keep the whole string buffer + // Fix ... don't keep the whole string buffer return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+ (unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)), - pKey,aiPTI_String); + pKey,type,index, aiPTI_String); } + // ------------------------------------------------------------------------------------------------ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest, const MaterialHelper* pcSrc) @@ -400,7 +421,8 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest, for (unsigned int q = 0; q < iOldNum;++q) { prop = pcDest->mProperties[q]; - if (!ASSIMP_stricmp(propSrc->mKey.data,prop->mKey.data)) + if (prop && prop->mKey == propSrc->mKey && + prop->mSemantic == propSrc->mSemantic && prop->mIndex == propSrc->mIndex) { delete prop; @@ -411,171 +433,69 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest, } } + // 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); } return; } + // ------------------------------------------------------------------------------------------------ -// we need this dummy because the compiler would otherwise complain about -// empty, but controlled statements ... -void DummyAssertFunction() +aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, + aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* _mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + float* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/) { - ai_assert(false); -} -// ------------------------------------------------------------------------------------------------ -aiReturn aiGetMaterialTexture(const aiMaterial* pcMat, - unsigned int iIndex, - unsigned int iTexType, - aiString* szOut, - unsigned int* piUVIndex, - float* pfBlendFactor, - aiTextureOp* peTextureOp, - aiTextureMapMode* peMapMode) -{ - ai_assert(NULL != pcMat); - ai_assert(NULL != szOut); + ai_assert(NULL != mat && NULL != path); - const char* szPathBase; - const char* szUVBase; - const char* szBlendBase; - const char* szOpBase; - const char* aszMapModeBase[3]; - switch (iTexType) - { - case AI_TEXTYPE_DIFFUSE: - szPathBase = AI_MATKEY_TEXTURE_DIFFUSE_; - szUVBase = AI_MATKEY_UVWSRC_DIFFUSE_; - szBlendBase = AI_MATKEY_TEXBLEND_DIFFUSE_; - szOpBase = AI_MATKEY_TEXOP_DIFFUSE_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_DIFFUSE_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_DIFFUSE_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_DIFFUSE_; - break; - case AI_TEXTYPE_SPECULAR: - szPathBase = AI_MATKEY_TEXTURE_SPECULAR_; - szUVBase = AI_MATKEY_UVWSRC_SPECULAR_; - szBlendBase = AI_MATKEY_TEXBLEND_SPECULAR_; - szOpBase = AI_MATKEY_TEXOP_SPECULAR_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_SPECULAR_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_SPECULAR_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_SPECULAR_; - break; - case AI_TEXTYPE_AMBIENT: - szPathBase = AI_MATKEY_TEXTURE_AMBIENT_; - szUVBase = AI_MATKEY_UVWSRC_AMBIENT_; - szBlendBase = AI_MATKEY_TEXBLEND_AMBIENT_; - szOpBase = AI_MATKEY_TEXOP_AMBIENT_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_AMBIENT_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_AMBIENT_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_AMBIENT_; - break; - case AI_TEXTYPE_EMISSIVE: - szPathBase = AI_MATKEY_TEXTURE_EMISSIVE_; - szUVBase = AI_MATKEY_UVWSRC_EMISSIVE_; - szBlendBase = AI_MATKEY_TEXBLEND_EMISSIVE_; - szOpBase = AI_MATKEY_TEXOP_EMISSIVE_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_EMISSIVE_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_EMISSIVE_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_EMISSIVE_; - break; - case AI_TEXTYPE_HEIGHT: - szPathBase = AI_MATKEY_TEXTURE_HEIGHT_; - szUVBase = AI_MATKEY_UVWSRC_HEIGHT_; - szBlendBase = AI_MATKEY_TEXBLEND_HEIGHT_; - szOpBase = AI_MATKEY_TEXOP_HEIGHT_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_HEIGHT_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_HEIGHT_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_HEIGHT_; - break; - case AI_TEXTYPE_NORMALS: - szPathBase = AI_MATKEY_TEXTURE_NORMALS_; - szUVBase = AI_MATKEY_UVWSRC_NORMALS_; - szBlendBase = AI_MATKEY_TEXBLEND_NORMALS_; - szOpBase = AI_MATKEY_TEXOP_NORMALS_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_NORMALS_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_NORMALS_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_NORMALS_; - break; - case AI_TEXTYPE_SHININESS: - szPathBase = AI_MATKEY_TEXTURE_SHININESS_; - szUVBase = AI_MATKEY_UVWSRC_SHININESS_; - szBlendBase = AI_MATKEY_TEXBLEND_SHININESS_; - szOpBase = AI_MATKEY_TEXOP_SHININESS_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_SHININESS_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_SHININESS_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_SHININESS_; - break; - case AI_TEXTYPE_OPACITY: - szPathBase = AI_MATKEY_TEXTURE_OPACITY_; - szUVBase = AI_MATKEY_UVWSRC_OPACITY_; - szBlendBase = AI_MATKEY_TEXBLEND_OPACITY_; - szOpBase = AI_MATKEY_TEXOP_OPACITY_; - aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_OPACITY_; - aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_OPACITY_; - aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_OPACITY_; - break; - default: return AI_FAILURE; - }; - - char szKey[256]; - if (iIndex > 100)return AI_FAILURE; - - // get the path to the texture - if(0 >= sprintf(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction(); - if (AI_SUCCESS != aiGetMaterialString(pcMat,szKey,szOut)) + // Get the path to the texture + aiString string; + if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),&string)) { return AI_FAILURE; } - // get the UV index of the texture - if (piUVIndex) - { - int iUV; - if(0 >= sprintf(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction(); - if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,&iUV)) - iUV = 0; - *piUVIndex = iUV; - } - // get the blend factor of the texture - if (pfBlendFactor) - { - float fBlend; - if(0 >= sprintf(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction(); - if (AI_SUCCESS != aiGetMaterialFloat(pcMat,szKey,&fBlend)) - fBlend = 1.0f; + // Determine the mapping type of the texture + aiTextureMapping mapping = aiTextureMapping_UV; + aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping); + if (_mapping)*_mapping = mapping; - *pfBlendFactor = fBlend; + // Get the UV index of the texture + if (aiTextureMapping_UV == mapping && uvindex) + { + aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex); } - // get the texture operation of the texture - if (peTextureOp) + // Get the blend factor of the texture + if (blend) { - aiTextureOp op; - if(0 >= sprintf(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction(); - if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&op)) - op = aiTextureOp_Multiply; + aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend); + } - *peTextureOp = op; + // Get the texture operation of the texture + if (op) + { + aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op); } // get the texture mapping modes for the texture - if (peMapMode) + if (mapmode) { - aiTextureMapMode eMode; - for (unsigned int q = 0; q < 3;++q) - { - if(0 >= sprintf(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction(); - if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&eMode)) - { - eMode = aiTextureMapMode_Wrap; - } - peMapMode[q] = eMode; - } + aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]); + aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]); + aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_W(type,index),(int*)&mapmode[2]); } return AI_SUCCESS; } diff --git a/code/MaterialSystem.h b/code/MaterialSystem.h index 5a92b210e..d16b85c22 100644 --- a/code/MaterialSystem.h +++ b/code/MaterialSystem.h @@ -65,11 +65,15 @@ public: * \param pInput Pointer to input data * \param pSizeInBytes Size of input data * \param pKey Key/Usage of the property (AI_MATKEY_XXX) + * \param type Set by the AI_MATKEY_XXX macro + * \param index Set by the AI_MATKEY_XXX macro * \param pType Type information hint */ aiReturn AddBinaryProperty (const void* pInput, - const unsigned int pSizeInBytes, + unsigned int pSizeInBytes, const char* pKey, + unsigned int type, + unsigned int index, aiPropertyTypeInfo pType); @@ -79,9 +83,13 @@ public: * * \param pInput Input string * \param pKey Key/Usage of the property (AI_MATKEY_XXX) + * \param type Set by the AI_MATKEY_XXX macro + * \param index Set by the AI_MATKEY_XXX macro */ aiReturn AddProperty (const aiString* pInput, - const char* pKey); + const char* pKey, + unsigned int type, + unsigned int index); // ------------------------------------------------------------------- @@ -89,20 +97,26 @@ public: * \param pInput Pointer to the input data * \param pNumValues Number of values in the array * \param pKey Key/Usage of the property (AI_MATKEY_XXX) + * \param type Set by the AI_MATKEY_XXX macro + * \param index Set by the AI_MATKEY_XXX macro */ template aiReturn AddProperty (const TYPE* pInput, - const unsigned int pNumValues, - const char* pKey); + unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index); // ------------------------------------------------------------------- /** Remove a given key from the list * The function fails if the key isn't found * - * \param pKey Key/Usage to be deleted + * \param pKey Key to be deleted */ - aiReturn RemoveProperty (const char* pKey); + aiReturn RemoveProperty (const char* pKey, + unsigned int type, + unsigned int index); // ------------------------------------------------------------------- @@ -136,11 +150,13 @@ public: template aiReturn MaterialHelper::AddProperty (const TYPE* pInput, const unsigned int pNumValues, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { return this->AddBinaryProperty((const void*)pInput, pNumValues * sizeof(TYPE), - pKey,aiPTI_Buffer); + pKey,type,index,aiPTI_Buffer); } @@ -149,11 +165,13 @@ aiReturn MaterialHelper::AddProperty (const TYPE* pInput, template<> inline aiReturn MaterialHelper::AddProperty (const float* pInput, const unsigned int pNumValues, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { return this->AddBinaryProperty((const void*)pInput, pNumValues * sizeof(float), - pKey,aiPTI_Float); + pKey,type,index,aiPTI_Float); } @@ -162,11 +180,13 @@ inline aiReturn MaterialHelper::AddProperty (const float* pInput, template<> inline aiReturn MaterialHelper::AddProperty (const aiColor4D* pInput, const unsigned int pNumValues, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { return this->AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), - pKey,aiPTI_Float); + pKey,type,index,aiPTI_Float); } @@ -175,11 +195,13 @@ inline aiReturn MaterialHelper::AddProperty (const aiColor4D* pInput, template<> inline aiReturn MaterialHelper::AddProperty (const aiColor3D* pInput, const unsigned int pNumValues, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { return this->AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), - pKey,aiPTI_Float); + pKey,type,index,aiPTI_Float); } @@ -188,11 +210,13 @@ inline aiReturn MaterialHelper::AddProperty (const aiColor3D* pInput, template<> inline aiReturn MaterialHelper::AddProperty (const int* pInput, const unsigned int pNumValues, - const char* pKey) + const char* pKey, + unsigned int type, + unsigned int index) { return this->AddBinaryProperty((const void*)pInput, pNumValues * sizeof(int), - pKey,aiPTI_Integer); + pKey,type,index,aiPTI_Integer); } } diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index 92bfacec5..083881003 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -93,6 +93,54 @@ inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh) } +// ------------------------------------------------------------------------------------------------ +// Get a string for a given aiTextureType +inline const char* TextureTypeToString(aiTextureType in) +{ + switch (in) + { + case aiTextureType_DIFFUSE: + return "Diffuse"; + case aiTextureType_SPECULAR: + return "Specular"; + case aiTextureType_AMBIENT: + return "Ambient"; + case aiTextureType_EMISSIVE: + return "Emissive"; + case aiTextureType_OPACITY: + return "Opacity"; + case aiTextureType_NORMALS: + return "Normals"; + case aiTextureType_HEIGHT: + return "Height"; + case aiTextureType_SHININESS: + return "Shininess"; + } + return "LARGE ERROR, please leave the room immediately and call the police"; +} + +// ------------------------------------------------------------------------------------------------ +// Get a string for a given aiTextureMapping +inline const char* MappingTypeToString(aiTextureMapping in) +{ + switch (in) + { + case aiTextureMapping_UV: + return "UV"; + case aiTextureMapping_BOX: + return "Box"; + case aiTextureMapping_SPHERE: + return "Sphere"; + case aiTextureMapping_CYLINDER: + return "Cylinder"; + case aiTextureMapping_PLANE: + return "Plane"; + case aiTextureMapping_OTHER: + return "Other"; + } + return "LARGE ERROR, please leave the room immediately and call the police"; +} + // ------------------------------------------------------------------------------------------------ class ComputeSpatialSortProcess : public BaseProcess { diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index fbc148f1c..5cfc45609 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -47,34 +47,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -#if _MSC_VER >= 1400 -# define sprintf sprintf_s -#endif - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() { + // nothing to do here } + // ------------------------------------------------------------------------------------------------ // Destructor, private as well RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() { // nothing to do here } -// ------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; } -// ------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin"); - unsigned int iCnt = 0; + unsigned int iCnt = 0, unreferenced = 0; if (pScene->mNumMaterials) { // TODO: reimplement this algorithm to work in-place @@ -95,7 +95,11 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { // if the material is not referenced ... remove it - if (!abReferenced[i])continue; + if (!abReferenced[i]) + { + ++unreferenced; + continue; + } uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash(); for (unsigned int a = 0; a < i;++a) @@ -153,7 +157,8 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) else { char szBuffer[128]; // should be sufficiently large - ::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. Found %i redundant materials",iCnt); + ::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. %i redundant and %i unused materials", + iCnt,unreferenced); DefaultLogger::get()->info(szBuffer); } } diff --git a/code/TargetAnimation.cpp b/code/TargetAnimation.cpp index 08e1f2d4b..96f175bac 100644 --- a/code/TargetAnimation.cpp +++ b/code/TargetAnimation.cpp @@ -45,20 +45,20 @@ using namespace Assimp; // --------------------------------------------------------------------------- -KeyIterator::KeyIterator(std::vector* _objPos, +KeyIterator::KeyIterator(const std::vector* _objPos, const std::vector* _targetObjPos, const aiVector3D* defaultObjectPos /*= NULL*/, const aiVector3D* defaultTargetPos /*= NULL*/) : reachedEnd (false) , curTime (-1.) - , objPos(_objPos) + , objPos (_objPos) , targetObjPos (_targetObjPos) , nextObjPos (0) , nextTargetObjPos(0) { // Generate default transformation tracks if necessary - if (!objPos) + if (!objPos || objPos->empty()) { defaultObjPos.resize(1); defaultObjPos.front().mTime = 10e10; @@ -68,7 +68,7 @@ KeyIterator::KeyIterator(std::vector* _objPos, objPos = & defaultObjPos; } - if (!targetObjPos) + if (!targetObjPos || targetObjPos->empty()) { defaultTargetObjPos.resize(1); defaultTargetObjPos.front().mTime = 10e10; @@ -129,7 +129,7 @@ void KeyIterator::operator ++() const aiVectorKey& last = targetObjPos->at(nextTargetObjPos); const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1); - /*curTargetPosition = Interpolate(first.mValue, last.mValue, + /* curTargetPosition = Interpolate(first.mValue, last.mValue, (curTime-first.mTime) / (last.mTime-first.mTime));*/ } @@ -177,23 +177,31 @@ void TargetAnimationHelper::SetTargetAnimationChannel ( // --------------------------------------------------------------------------- void TargetAnimationHelper::SetMainAnimationChannel ( - std::vector* _objectPositions) + const std::vector* _objectPositions) { ai_assert(NULL != _objectPositions); objectPositions = _objectPositions; } +// --------------------------------------------------------------------------- +void TargetAnimationHelper::SetFixedMainAnimationChannel( + const aiVector3D& fixed) +{ + objectPositions = NULL; // just to avoid confusion + fixedMain = fixed; +} + // --------------------------------------------------------------------------- void TargetAnimationHelper::Process(std::vector* distanceTrack) { - ai_assert(NULL != objectPositions); + ai_assert(NULL != targetPositions); // Iterate through all object keys and interpolate their values if necessary. // Then get the corresponding target position, compute the difference // vector between object and target position. Then compute a rotation matrix // that rotates the base vector of the object coordinate system at that time // to match the diff vector. - KeyIterator iter(objectPositions,targetPositions); + KeyIterator iter(objectPositions,targetPositions,&fixedMain); unsigned int curTarget; for (;!iter.Finished();++iter) { diff --git a/code/TargetAnimation.h b/code/TargetAnimation.h index 43332bfb1..bd947559c 100644 --- a/code/TargetAnimation.h +++ b/code/TargetAnimation.h @@ -69,7 +69,7 @@ public: * @param defaultTargetPos Default target position to be used if * no animated track is available. May be NULL. */ - KeyIterator(std::vector* _objPos, + KeyIterator(const std::vector* _objPos, const std::vector* _targetObjPos, const aiVector3D* defaultObjectPos = NULL, const aiVector3D* defaultTargetPos = NULL); @@ -129,7 +129,8 @@ class ASSIMP_API TargetAnimationHelper public: TargetAnimationHelper() - : objectPositions (NULL) + : targetPositions (NULL) + , objectPositions (NULL) {} @@ -141,8 +142,8 @@ public: * * @param targetPositions Translation channel */ - void SetTargetAnimationChannel ( - const std::vector* targetPositions); + void SetTargetAnimationChannel (const + std::vector* targetPositions); // ------------------------------------------------------------------ @@ -150,9 +151,16 @@ public: * * @param objectPositions Translation channel */ - void SetMainAnimationChannel ( + void SetMainAnimationChannel ( const std::vector* objectPositions); + // ------------------------------------------------------------------ + /** Sets the main animation channel to a fixed value + * + * @param fixed Fixed value for the main animation channel + */ + void SetFixedMainAnimationChannel(const aiVector3D& fixed); + // ------------------------------------------------------------------ /** Computes final animation channels @@ -163,11 +171,11 @@ public: private: - const std::vector* targetPositions; - std::vector *objectPositions; + const std::vector* targetPositions,*objectPositions; + aiVector3D fixedMain; }; } // ! end namespace Assimp -#endif // include guard \ No newline at end of file +#endif // include guard diff --git a/code/TextureTransform.cpp b/code/TextureTransform.cpp index c8b7f08f3..114f481f0 100644 --- a/code/TextureTransform.cpp +++ b/code/TextureTransform.cpp @@ -44,533 +44,556 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" #include "TextureTransform.h" -namespace Assimp -{ +using namespace Assimp; + // ------------------------------------------------------------------------------------------------ -void TextureTransform::PreProcessUVTransform( - D3DS::Texture& rcIn) +// Constructor to be privately used by Importer +TextureTransformStep::TextureTransformStep() { + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +TextureTransformStep::~TextureTransformStep() +{ + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the processing step is present in the given flag field. +bool TextureTransformStep::IsActive( unsigned int pFlags) const +{ + return (pFlags & aiProcess_TransformUVCoords) != 0; +} + +// ------------------------------------------------------------------------------------------------ +// Setup properties +void TextureTransformStep::SetupProperties(const Importer* pImp) +{ + configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL); +} + +// ------------------------------------------------------------------------------------------------ +void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) +{ + /* This function tries to simplify the input UV transformation. + * That's very important as it allows us to reduce the number + * of output UV channels. The oder in which the transformations + * are applied is - as always - scaling, rotation, translation. + */ + char szTemp[512]; - int iField; + int rounded = 0; - if (rcIn.mOffsetU) + + /* Optimize the rotation angle. That's slightly difficult as + * we have an inprecise floating-point number (when comparing + * UV transformations we'll take that into account by using + * an epsilon of 5 degrees). If there is a rotation value, we can't + * perform any further optimizations. + */ + if (info.mRotation) { - if ((iField = (int)rcIn.mOffsetU)) + float out = info.mRotation; + if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI))) { - if (aiTextureMapMode_Wrap == rcIn.mMapMode) - { - float fNew = rcIn.mOffsetU-(float)iField; - sprintf(szTemp,"[wrap] Found texture coordinate U offset %f. " - "This can be optimized to %f",rcIn.mOffsetU,fNew); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetU = fNew; - } - else if (aiTextureMapMode_Mirror == rcIn.mMapMode) - { - if (0 != (iField % 2))iField--; - float fNew = rcIn.mOffsetU-(float)iField; + out -= rounded*(float)AI_MATH_PI; - sprintf(szTemp,"[mirror] Found texture coordinate U offset %f. " - "This can be optimized to %f",rcIn.mOffsetU,fNew); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetU = fNew; - } - else if (aiTextureMapMode_Clamp == rcIn.mMapMode) - { - sprintf(szTemp,"[clamp] Found texture coordinate U offset %f. " - "This can be clamped to 1.0f",rcIn.mOffsetU); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetU = 1.0f; - } - } - } - if (rcIn.mOffsetV) - { - if ((iField = (int)rcIn.mOffsetV)) - { - if (aiTextureMapMode_Wrap == rcIn.mMapMode) - { - float fNew = rcIn.mOffsetV-(float)iField; - sprintf(szTemp,"[wrap] Found texture coordinate V offset %f. " - "This can be optimized to %f",rcIn.mOffsetV,fNew); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetV = fNew; - } - else if (aiTextureMapMode_Mirror == rcIn.mMapMode) - { - if (0 != (iField % 2))iField--; - float fNew = rcIn.mOffsetV-(float)iField; - - sprintf(szTemp,"[mirror] Found texture coordinate V offset %f. " - "This can be optimized to %f",rcIn.mOffsetV,fNew); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetV = fNew; - } - else if (aiTextureMapMode_Clamp == rcIn.mMapMode) - { - sprintf(szTemp,"[clamp] Found texture coordinate U offset %f. " - "This can be clamped to 1.0f",rcIn.mOffsetV); - - DefaultLogger::get()->info(szTemp); - rcIn.mOffsetV = 1.0f; - } - } - } - if (rcIn.mRotation) - { - if ((iField = (int)(rcIn.mRotation / 3.141592654f))) - { - float fNew = rcIn.mRotation-(float)iField*3.141592654f; - - sprintf(szTemp,"[wrap] Found texture coordinate rotation %f. " - "This can be optimized to %f",rcIn.mRotation,fNew); + sprintf(szTemp,"Texture coordinate rotation %f can " + "be simplified to %f",info.mRotation,out); DefaultLogger::get()->info(szTemp); + } - rcIn.mRotation = fNew; + // Next step - convert negative rotation angles to positives + if (out < 0.f) + out = (float)AI_MATH_TWO_PI * 2 + out; + + info.mRotation = out; + return; + } + + float absTranslationX = info.mScaling.x * info.mTranslation.x; + float absTranslationY = info.mScaling.y * info.mTranslation.y; + + /* Optimize UV translation in the U direction. To determine whether + * or not we can optimize we need to look at the requested mapping + * type (e.g. if mirroring is active there IS a difference between + * offset 2 and 3) + */ + if ((rounded = (int)absTranslationX)) + { + float out; + szTemp[0] = 0; + if (aiTextureMapMode_Wrap == info.mapU) + { + // Wrap - simple take the fraction of the field + out = (absTranslationX-(float)rounded) / info.mScaling.x; + sprintf(szTemp,"[w] UV U offset %f can " + "be simplified to %f",info.mTranslation.x,out); + } + else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) + { + // Mirror + if (rounded % 2)rounded--; + out = (absTranslationX-(float)rounded) / info.mScaling.x; + + sprintf(szTemp,"[m/d] UV U offset %f can " + "be simplified to %f",info.mTranslation.x,out); + } + else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) + { + // Clamp - translations beyond 1,1 are senseless + sprintf(szTemp,"[c] UV U offset %f can " + "be clamped to 1.0f",info.mTranslation.x); + + out = 1.f; + } + if (szTemp[0]) + { + DefaultLogger::get()->info(szTemp); + info.mTranslation.x = out; + } + } + + /* Optimize UV translation in the V direction. To determine whether + * or not we can optimize we need to look at the requested mapping + * type (e.g. if mirroring is active there IS a difference between + * offset 2 and 3) + */ + if ((rounded = (int)absTranslationY)) + { + float out; + szTemp[0] = 0; + if (aiTextureMapMode_Wrap == info.mapV) + { + // Wrap - simple take the fraction of the field + out = (absTranslationY-(float)rounded) / info.mScaling.y; + sprintf(szTemp,"[w] UV V offset %f can " + "be simplified to %f",info.mTranslation.y,out); + } + else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) + { + // Mirror + if (rounded % 2)rounded--; + out = (absTranslationY-(float)rounded) / info.mScaling.y; + + sprintf(szTemp,"[m/d] UV V offset %f can " + "be simplified to %f",info.mTranslation.y,out); + } + else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) + { + // Clamp - translations beyond 1,1 are senseless + sprintf(szTemp,"[c] UV V offset %f can" + "be clamped to 1.0f",info.mTranslation.y); + + out = 1.f; + } + if (szTemp[0]) + { + DefaultLogger::get()->info(szTemp); + info.mTranslation.y = out; } } return; } + // ------------------------------------------------------------------------------------------------ -void TextureTransform::AddToList(std::vector& rasVec, - D3DS::Texture* pcTex) +void UpdateUVIndex(const std::list& l, unsigned int n) { - // check whether the texture is existing - if (0 == pcTex->mMapName.length())return; + // Don't set if == 0 && wasn't set before + for (std::list::const_iterator it = l.begin(); + it != l.end(); ++it) + { + const TTUpdateInfo& info = *it; - // search for an identical transformation in our list - for (std::vector::iterator - i = rasVec.begin(); - i != rasVec.end();++i) - { - if ((*i).fOffsetU == pcTex->mOffsetU && - (*i).fOffsetV == pcTex->mOffsetV && - (*i).fScaleU == pcTex->mScaleU && - (*i).fScaleV == pcTex->mScaleV && - (*i).fRotation == pcTex->mRotation && - (*i).iUVIndex == (unsigned int)pcTex->iUVSrc) + if (info.directShortcut) + *info.directShortcut = n; + else if (!n) { - (*i).pcTextures.push_back(pcTex); - return; + info.mat->AddProperty((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index)); } } - // this is a new transformation, so add it to the list - STransformVecInfo sInfo; - sInfo.fScaleU = pcTex->mScaleU; - sInfo.fScaleV = pcTex->mScaleV; - sInfo.fOffsetU = pcTex->mOffsetU; - sInfo.fOffsetV = pcTex->mOffsetV; - sInfo.fRotation = pcTex->mRotation; - sInfo.iUVIndex = pcTex->iUVSrc; - - // add the texture to the list - sInfo.pcTextures.push_back(pcTex); - - // and add the transformation itself to the second list - rasVec.push_back(sInfo); -} -// ------------------------------------------------------------------------------------------------ -void TextureTransform::ApplyScaleNOffset(D3DS::Material& material) -{ - unsigned int iCnt = 0; - D3DS::Texture* pcTexture = NULL; - - // diffuse texture - if (material.sTexDiffuse.mMapName.length()) - { - PreProcessUVTransform(material.sTexDiffuse); - if (HasUVTransform(material.sTexDiffuse)) - { - material.sTexDiffuse.bPrivate = true; - pcTexture = &material.sTexDiffuse; - ++iCnt; - } - } - // specular texture - if (material.sTexSpecular.mMapName.length()) - { - PreProcessUVTransform(material.sTexSpecular); - if (HasUVTransform(material.sTexSpecular)) - { - material.sTexSpecular.bPrivate = true; - pcTexture = &material.sTexSpecular; - ++iCnt; - } - } - // ambient texture - if (material.sTexAmbient.mMapName.length()) - { - PreProcessUVTransform(material.sTexAmbient); - if (HasUVTransform(material.sTexAmbient)) - { - material.sTexAmbient.bPrivate = true; - pcTexture = &material.sTexAmbient; - ++iCnt; - } - } - // emissive texture - if (material.sTexEmissive.mMapName.length()) - { - PreProcessUVTransform(material.sTexEmissive); - if (HasUVTransform(material.sTexEmissive)) - { - material.sTexEmissive.bPrivate = true; - pcTexture = &material.sTexEmissive; - ++iCnt; - } - } - // opacity texture - if (material.sTexOpacity.mMapName.length()) - { - PreProcessUVTransform(material.sTexOpacity); - if (HasUVTransform(material.sTexOpacity)) - { - material.sTexOpacity.bPrivate = true; - pcTexture = &material.sTexOpacity; - ++iCnt; - } - } - // bump texture - if (material.sTexBump.mMapName.length()) - { - PreProcessUVTransform(material.sTexBump); - if (HasUVTransform(material.sTexBump)) - { - material.sTexBump.bPrivate = true; - pcTexture = &material.sTexBump; - ++iCnt; - } - } - // shininess texture - if (material.sTexShininess.mMapName.length()) - { - PreProcessUVTransform(material.sTexShininess); - if (HasUVTransform(material.sTexShininess)) - { - material.sTexBump.bPrivate = true; - pcTexture = &material.sTexShininess; - ++iCnt; - } - } - if (0 != iCnt) - { - // if only one texture needs scaling/offset operations - // we can apply them directly to the first texture - // coordinate sets of all meshes referencing *this* material - // However, we can't do it now. We need to wait until - // everything is sorted by materials. - if (1 == iCnt && 0 == pcTexture->iUVSrc) - { - material.iBakeUVTransform = 1; - material.pcSingleTexture = pcTexture; - } - // we will need to generate a separate new texture channel - // for each texture. - // However, we can't do it now. We need to wait until - // everything is sorted by materials. - else material.iBakeUVTransform = 2; - } } + // ------------------------------------------------------------------------------------------------ -void TextureTransform::ApplyScaleNOffset(std::vector& materials) +inline const char* MappingModeToChar(aiTextureMapMode map) { - unsigned int iNum = 0; - for (std::vector::iterator - i = materials.begin(); - i != materials.end();++i,++iNum) - { - ApplyScaleNOffset(*i); - } - return; -} -// ------------------------------------------------------------------------------------------------ -void TextureTransform::BakeScaleNOffset( - aiMesh* pcMesh, D3DS::Material* pcSrc) -{ - // NOTE: we don't use a texture matrix to do the transformation - // it is more efficient this way ... + if (aiTextureMapMode_Wrap == map) + return "-w"; - if (!pcMesh->mTextureCoords[0])return; - if (0x1 == pcSrc->iBakeUVTransform) - { - char szTemp[512]; - int iLen; -#if _MSC_VER >= 1400 - iLen = ::sprintf_s(szTemp, -#else - iLen = ::sprintf(szTemp, -#endif - "Transforming existing UV channel. Source UV: %i" - " OffsetU: %f" - " OffsetV: %f" - " ScaleU: %f" - " ScaleV: %f" - " Rotation (rad): %f",0, - pcSrc->pcSingleTexture->mOffsetU, - pcSrc->pcSingleTexture->mOffsetV, - pcSrc->pcSingleTexture->mScaleU, - pcSrc->pcSingleTexture->mScaleV, - pcSrc->pcSingleTexture->mRotation); - - ai_assert(0 < iLen); - DefaultLogger::get()->info(std::string(szTemp,iLen)); - - if (!pcSrc->pcSingleTexture->mRotation) - { - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { - // scaling - pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU; - pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV; - - // offset - pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU; - pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV; - } - } - else - { - const float fSin = sinf(pcSrc->pcSingleTexture->mRotation); - const float fCos = cosf(pcSrc->pcSingleTexture->mRotation); - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { - // scaling - pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU; - pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV; - - // rotation - pcMesh->mTextureCoords[0][i].x *= fCos; - pcMesh->mTextureCoords[0][i].y *= fSin; - - // offset - pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU; - pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV; - } - } - } - else if (0x2 == pcSrc->iBakeUVTransform) - { - // first save all texture coordinate sets - aiVector3D* apvOriginalSets[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - apvOriginalSets[i] = pcMesh->mTextureCoords[i]; - } - unsigned int iNextEmpty = 0; - while (pcMesh->mTextureCoords[++iNextEmpty]); - - aiVector3D* apvOutputSets[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - apvOutputSets[i] = NULL; - - // now we need to find all textures in the material - // which require scaling/offset operations - std::vector sOps; - sOps.reserve(10); - TextureTransform::AddToList(sOps,&pcSrc->sTexDiffuse); - TextureTransform::AddToList(sOps,&pcSrc->sTexSpecular); - TextureTransform::AddToList(sOps,&pcSrc->sTexEmissive); - TextureTransform::AddToList(sOps,&pcSrc->sTexOpacity); - TextureTransform::AddToList(sOps,&pcSrc->sTexBump); - TextureTransform::AddToList(sOps,&pcSrc->sTexShininess); - TextureTransform::AddToList(sOps,&pcSrc->sTexAmbient); - - // check the list and find out how many we won't be able - // to generate. - std::vector sFilteredOps; - unsigned int iNumUntransformed = 0; - sFilteredOps.reserve(sOps.size()); - { - std::vector sWishList; - sWishList.reserve(sOps.size()); - for (unsigned int iUV = 0; iUV < AI_MAX_NUMBER_OF_TEXTURECOORDS;++iUV) - { - for (std::vector::iterator - i = sOps.begin(); - i != sOps.end();++i) - { - if (iUV != (*i).iUVIndex)continue; - if ((*i).IsUntransformed()) - { - sFilteredOps.push_back(&(*i)); - } - else sWishList.push_back(&(*i)); - } - } - // are we able to generate all? - const int iDiff = AI_MAX_NUMBER_OF_TEXTURECOORDS-(int) - (sWishList.size()+sFilteredOps.size()); - - iNumUntransformed = (unsigned int)sFilteredOps.size(); - if (0 >= iDiff) - { - DefaultLogger::get()->warn("There are too many combinations of different " - "UV transformation operations to generate an own UV channel for each " - "(maximum is AI_MAX_NUMBER_OF_TEXTURECOORDS = 4 or 6). " - "An untransformed UV channel will be used for all remaining transformations"); - - std::vector::const_iterator nash = sWishList.begin(); - for (;nash != sWishList.end()-iDiff;++nash) - { - sFilteredOps.push_back(*nash); - } - } - else - { - for (std::vector::const_iterator - nash = sWishList.begin(); - nash != sWishList.end();++nash)sFilteredOps.push_back(*nash); - } - } - - // now fill in all output IV indices - unsigned int iNum = 0; - for (std::vector::iterator - bogart = sFilteredOps.begin(); - bogart != sFilteredOps.end();++bogart,++iNum) - { - (**bogart).iUVIndex = iNum; - } - - iNum = 0; - for (; iNum < iNumUntransformed; ++iNum) - pcMesh->mTextureCoords[iNum] = apvOriginalSets[iNum]; - - // now generate the texture coordinate sets - for (std::vector::iterator - i = sFilteredOps.begin()+iNumUntransformed; - i != sFilteredOps.end();++i,++iNum) - { - const aiVector3D* _pvBase = apvOriginalSets[(**i).iUVIndex]; - aiVector3D* _pvOut = new aiVector3D[pcMesh->mNumVertices]; - pcMesh->mTextureCoords[iNum] = _pvOut; - - char szTemp[512]; - int iLen; -#if _MSC_VER >= 1400 - iLen = ::sprintf_s(szTemp, -#else - iLen = ::sprintf(szTemp, -#endif - "Generating additional UV channel. Source UV: %i" - " OffsetU: %f" - " OffsetV: %f" - " ScaleU: %f" - " ScaleV: %f" - " Rotation (rad): %f",0, - (**i).fOffsetU, - (**i).fOffsetV, - (**i).fScaleU, - (**i).fScaleV, - (**i).fRotation); - ai_assert(0 < iLen); - DefaultLogger::get()->info(std::string(szTemp,iLen)); - - const aiVector3D* pvBase = _pvBase; - aiVector3D* pvOut = _pvOut; - if (0.0f == (**i).fRotation) - { - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - { - // scaling - pvOut->x = pvBase->x * (**i).fScaleU; - pvOut->y = pvBase->y * (**i).fScaleV; - - // offset - pvOut->x += (**i).fOffsetU; - pvOut->y += (**i).fOffsetV; - - pvBase++; - pvOut++; - } - } - else - { - const float fSin = sinf((**i).fRotation); - const float fCos = cosf((**i).fRotation); - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - { - // scaling - pvOut->x = pvBase->x * (**i).fScaleU; - pvOut->y = pvBase->y * (**i).fScaleV; - - // rotation - pvOut->x *= fCos; - pvOut->y *= fSin; - - // offset - pvOut->x += (**i).fOffsetU; - pvOut->y += (**i).fOffsetV; - - pvBase++; - pvOut++; - } - } - } - - // now check which source texture coordinate sets - // can be deleted because they're not anymore required - for (iNum = 0; iNum < AI_MAX_NUMBER_OF_TEXTURECOORDS;++iNum) - { - for (unsigned int z = 0; z < iNumUntransformed;++z) - { - if (apvOriginalSets[iNum] == pcMesh->mTextureCoords[z]) - { - apvOriginalSets[iNum] = NULL; - break; - } - } - if (apvOriginalSets[iNum])delete[] apvOriginalSets[iNum]; - } - } - - // setup bitflags to indicate which texture coordinate - // channels are used (this class works for 2d texture coordinates only) - - unsigned int iIndex = 0; - while (pcMesh->HasTextureCoords(iIndex))pcMesh->mNumUVComponents[iIndex++] = 2; - return; -} -// ------------------------------------------------------------------------------------------------ -void TextureTransform::SetupMatUVSrc (aiMaterial* pcMat, const D3DS::Material* pcMatIn) -{ - ai_assert(NULL != pcMat); - ai_assert(NULL != pcMatIn); + if (aiTextureMapMode_Mirror == map) + return "-m"; - MaterialHelper* pcHelper = (MaterialHelper*)pcMat; - - if(pcMatIn->sTexDiffuse.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexDiffuse.iUVSrc,1, - AI_MATKEY_UVWSRC_DIFFUSE(0)); - - if(pcMatIn->sTexSpecular.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexSpecular.iUVSrc,1, - AI_MATKEY_UVWSRC_SPECULAR(0)); - - if(pcMatIn->sTexEmissive.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexEmissive.iUVSrc,1, - AI_MATKEY_UVWSRC_EMISSIVE(0)); - - if(pcMatIn->sTexBump.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexBump.iUVSrc,1, - AI_MATKEY_UVWSRC_HEIGHT(0)); - - if(pcMatIn->sTexShininess.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexShininess.iUVSrc,1, - AI_MATKEY_UVWSRC_SHININESS(0)); - - if(pcMatIn->sTexOpacity.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexOpacity.iUVSrc,1, - AI_MATKEY_UVWSRC_OPACITY(0)); - - if(pcMatIn->sTexAmbient.mMapName.length() > 0) - pcHelper->AddProperty(&pcMatIn->sTexAmbient.iUVSrc,1, - AI_MATKEY_UVWSRC_AMBIENT(0)); + return "-c"; } -}; + +// ------------------------------------------------------------------------------------------------ +void TextureTransformStep::Execute( aiScene* pScene) +{ + DefaultLogger::get()->debug("TransformUVCoordsProcess begin"); + + + /* We build a per-mesh list of texture transformations we'll need + * to apply. To achieve this, we iterate through all materials, + * find all textures and get their transformations and UV indices. + * Then we search for all meshes using this material. + */ + typedef std::list MeshTrafoList; + std::vector meshLists(pScene->mNumMeshes); + + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) + { + aiMaterial* mat = pScene->mMaterials[i]; + for (unsigned int a = 0; a < mat->mNumProperties;++a) + { + aiMaterialProperty* prop = mat->mProperties[a]; + if (!::strcmp( prop->mKey.data, "$tex.file")) + { + STransformVecInfo info; + + // Setup a shortcut structure to allow for a fast updating + // of the UV index later + TTUpdateInfo update; + update.mat = (MaterialHelper*) mat; + update.semantic = prop->mSemantic; + update.index = prop->mIndex; + + // Get textured properties and transform + for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) + { + aiMaterialProperty* prop2 = mat->mProperties[a2]; + if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) + continue; + + if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) + { + info.uvIndex = *((int*)prop2->mData); + + // Store a direct pointer for later use + update.directShortcut = (unsigned int*) &prop2->mData; + } + + else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) + info.mapU = *((aiTextureMapMode*)prop2->mData); + + else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) + info.mapV = *((aiTextureMapMode*)prop2->mData); + + else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) + { + // ValidateDS should check this + ai_assert(prop2->mDataLength >= 20); + + ::memcpy(&info.mTranslation.x,prop2->mData, + sizeof(float)*5); + + delete[] prop2->mData; + + // Directly remove this property from the list + mat->mNumProperties--; + for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) + mat->mProperties[a3] = mat->mProperties[a3+1]; + + // Warn: could be an underflow, but nevertheless it should work + --a2; + } + } + + // Find out which transformations are to be evaluated + if (!(configFlags & AI_UVTRAFO_ROTATION)) + info.mRotation = 0.f; + + if (!(configFlags & AI_UVTRAFO_SCALING)) + info.mScaling = aiVector2D(1.f,1.f); + + if (!(configFlags & AI_UVTRAFO_TRANSLATION)) + info.mTranslation = aiVector2D(0.f,0.f); + + // Do some preprocessing + PreProcessUVTransform(info); + info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u); + + // Find out whether this material is used by more than + // one mesh. This will make our task much, much more difficult! + unsigned int cnt = 0; + for (unsigned int n = 0; n < pScene->mNumMeshes;++n) + { + if (pScene->mMeshes[n]->mMaterialIndex == i) + ++cnt; + } + + if (!cnt)continue; + else if (1 != cnt) + { + // This material is referenced by more than one mesh! + // So we need to make sure the UV index for the texture + // is identical for each of it ... + info.lockedPos = AI_TT_UV_IDX_LOCK_TBD; + } + + // Get all coresponding meshes + for (unsigned int n = 0; n < pScene->mNumMeshes;++n) + { + aiMesh* mesh = pScene->mMeshes[n]; + if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0]) continue; + + unsigned int uv = info.uvIndex; + if (!mesh->mTextureCoords[uv]) + { + // If the requested UV index is not available, + // take the first one instead. + uv = 0; + } + + if (mesh->mNumUVComponents[info.uvIndex] >= 3) + { + DefaultLogger::get()->warn("UV transformations on 3D mapping channels " + "are not supported by this step"); + + continue; + } + + MeshTrafoList::iterator it; + + // Check whether we have this transform setup already + for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) + { + if ((*it) == info && (*it).uvIndex == uv) + { + (*it).updateList.push_back(update); + break; + } + } + if (it == meshLists[n].end()) + { + meshLists[n].push_back(info); + meshLists[n].back().uvIndex = uv; + meshLists[n].back().updateList.push_back(update); + } + } + } + } + } + + char buffer[1024]; // should be sufficiently large + unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0; + + // Now process all meshes. Important: we don't remove unreferenced UV channels. + // This is a job for the RemoveUnreferencedData-Step. + for (unsigned int q = 0; q < pScene->mNumMeshes;++q) + { + aiMesh* mesh = pScene->mMeshes[q]; + MeshTrafoList& trafo = meshLists[q]; + + inChannels += mesh->GetNumUVChannels(); + + if (!mesh->mTextureCoords[0] || trafo.empty() || + trafo.size() == 1 && trafo.begin()->IsUntransformed()) + { + outChannels += mesh->GetNumUVChannels(); + continue; + } + + // Move untransformed UV channels to the first + // position in the list .... except if we need + // a new locked index which should be as small as possible + bool veto = false; + unsigned int cnt = 0; + unsigned int untransformed = 0; + + MeshTrafoList::iterator it,it2; + for (it = trafo.begin();it != trafo.end(); ++it,++cnt) + { + if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) + { + // Lock this index and make sure it won't be changed + (*it).lockedPos = cnt; + veto = true; + continue; + } + + if (!veto && it != trafo.begin() && (*it).IsUntransformed()) + { + trafo.push_front((*it)); + trafo.erase(it); + + break; + } + } + + // Find all that are not at their 'locked' position + // and move them to it. Conflicts are possible but + // quite unlikely. + cnt = 0; + for (it = trafo.begin();it != trafo.end(); ++it,++cnt) + { + if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) + { + it2 = trafo.begin();unsigned int t = 0; + while (t != (*it).lockedPos)++it2; + + if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) + { + DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly"); + continue; + } + + std::swap(*it2,*it); + if ((*it).lockedPos == untransformed)untransformed = cnt; + } + } + + // ... and add dummies for all unreferenced channels + // at the end of the list + bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) + ref[n] = (!mesh->mTextureCoords[n] ? true : false); + + for (it = trafo.begin();it != trafo.end(); ++it) + ref[(*it).uvIndex] = true; + + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) + { + if (ref[n])continue; + trafo.push_back(STransformVecInfo()); + trafo.back().uvIndex = n; + } + + // Then check whether this list breaks the channel limit. + // The unimportant ones are at the end of the list, so + // it shouldn't be too worse if we remove them. + unsigned int size = (unsigned int)trafo.size(); + if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) + { + if (!DefaultLogger::isNullLogger()) + { + ::sprintf(buffer,"%i UV channels required but just %i available", + trafo.size(),AI_MAX_NUMBER_OF_TEXTURECOORDS); + + DefaultLogger::get()->error(buffer); + } + size = AI_MAX_NUMBER_OF_TEXTURECOORDS; + } + + + aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) + old[n] = mesh->mTextureCoords[n]; + + // Now continue and generate the output channels. Channels + // that we're not going to need later can be overridden. + it = trafo.begin(); + for (unsigned int n = 0; n < trafo.size();++n,++it) + { + if (n >= size) + { + // Try to use an untransformed channel for all channels we threw over board + UpdateUVIndex((*it).updateList,untransformed); + continue; + } + + outChannels++; + + // Write to the log + if (!DefaultLogger::isNullLogger()) + { + sprintf(buffer,"Mesh %i, channel %i: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s", + q,n, + (*it).mTranslation.x, + (*it).mTranslation.y, + (*it).mScaling.x, + (*it).mScaling.y, + AI_RAD_TO_DEG( (*it).mRotation), + MappingModeToChar ((*it).mapU), + MappingModeToChar ((*it).mapV)); + + DefaultLogger::get()->info(buffer); + } + + // Check whether we need a new buffer here + if (mesh->mTextureCoords[n]) + { + it2 = it;++it2; + for (unsigned int m = n+1; m < size;++m, ++it2) + { + if ((*it2).uvIndex == n) + { + it2 = trafo.begin(); + break; + } + } + if (it2 == trafo.begin()) + { + mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; + } + } + else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; + + aiVector3D* src = old[(*it).uvIndex]; + aiVector3D* dest, *end; + dest = mesh->mTextureCoords[n]; + + ai_assert(NULL != src); + + // Copy the data to the destination array + if (dest != src) + ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); + + end = dest + mesh->mNumVertices; + + // Build a transformation matrix and transform all UV coords with it + if (!(*it).IsUntransformed()) + { + const aiVector2D& trl = (*it).mTranslation; + const aiVector2D& scl = (*it).mScaling; + + ++transformedChannels; + aiMatrix3x3 matrix; + + aiMatrix3x3 m2,m3,m4,m5; + + m4.a1 = scl.x; + m4.b2 = scl.y; + + m2.a3 = m2.b3 = 0.5f; + m3.a3 = m3.b3 = -0.5f; + + if ((*it).mRotation > AI_TT_ROTATION_EPSILON ) + aiMatrix3x3::Rotation((*it).mRotation,matrix); + + m5.a3 += trl.x; m5.b3 += trl.y; + matrix = m2 * m4 * matrix * m3 * m5; + + + for (src = dest; src != end; ++src) + { + src->z = 1.f; + *src = matrix * *src; + src->x /= src->z; + src->y /= src->z; + src->z = 0.f; + } + } + + // Update all UV indices + UpdateUVIndex((*it).updateList,n); + } + } + + // Print some detailled statistics into the log + if (!DefaultLogger::isNullLogger()) + { + if (transformedChannels) + { + ::sprintf(buffer,"TransformUVCoordsProcess end: %i output channels (in: %i, modified: %i)", + outChannels,inChannels,transformedChannels); + + DefaultLogger::get()->info(buffer); + } + else DefaultLogger::get()->debug("TransformUVCoordsProcess finished"); + } +} + + diff --git a/code/TextureTransform.h b/code/TextureTransform.h index 21b303618..e6926929a 100644 --- a/code/TextureTransform.h +++ b/code/TextureTransform.h @@ -38,56 +38,107 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Definition of a helper class that processes texture transformations */ +/** @file Definition of a helper step that processes texture transformations */ #ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED #define AI_TEXTURE_TRANSFORM_H_INCLUDED #include "BaseImporter.h" -#include "../include/aiTypes.h" -#include "../include/aiMaterial.h" -#include "../include/aiMesh.h" - +#include "BaseProcess.h" struct aiNode; -#include "3DSHelper.h" -namespace Assimp +namespace Assimp { + +#define AI_TT_UV_IDX_LOCK_TBD 0xffffffff +#define AI_TT_UV_IDX_LOCK_NONE 0xeeeeeeee + + +#define AI_TT_ROTATION_EPSILON ((float)AI_DEG_TO_RAD(0.5)) + +// --------------------------------------------------------------------------- +/** Small helper structure representing a shortcut into the material list + * to be able to update some values quickly. +*/ +struct TTUpdateInfo { + TTUpdateInfo() + : mat (NULL) + , directShortcut (NULL) + , semantic (0) + , index (0) + {} + + //! Direct shortcut, if available + unsigned int* directShortcut; + + //! Material + MaterialHelper* mat; + + //! Texture type and index + unsigned int semantic, index; +}; -using namespace Assimp::D3DS; // --------------------------------------------------------------------------- /** Helper class representing texture coordinate transformations */ -struct STransformVecInfo +struct STransformVecInfo : public aiUVTransform { - //! Construction. The resulting matrix is the identity - STransformVecInfo () - : - fScaleU(1.0f),fScaleV(1.0f), - fOffsetU(0.0f),fOffsetV(0.0f), - fRotation(0.0f), - iUVIndex(0) + + STransformVecInfo() + : uvIndex (0) + , mapU (aiTextureMapMode_Wrap) + , mapV (aiTextureMapMode_Wrap) + , lockedPos (AI_TT_UV_IDX_LOCK_NONE) {} - //! Texture coordinate scaling in the x-direction - float fScaleU; - //! Texture coordinate scaling in the y-direction - float fScaleV; - //! Texture coordinate offset in the x-direction - float fOffsetU; - //! Texture coordinate offset in the y-direction - float fOffsetV; - //! Texture coordinate rotation, clockwise, in radians - float fRotation; - //! Source texture coordinate index - unsigned int iUVIndex; + unsigned int uvIndex; + + //! Texture mapping mode in the u, v direction + aiTextureMapMode mapU,mapV; + + //! Locked destination UV index + //! AI_TT_UV_IDX_LOCK_TBD - to be determined + //! AI_TT_UV_IDX_LOCK_NONE - none (default) + unsigned int lockedPos; + + //! Update info - shortcuts into all materials + //! that are referencing this transform setup + std::list updateList; - //! List of all textures that use this texture - //! coordinate transformations - std::vector pcTextures; + // ------------------------------------------------------------------- + /** Compare two transform setups + */ + inline bool operator== (const STransformVecInfo& other) const + { + // We use a small epsilon here + const float epsilon = 0.05f; + + if (fabs( mTranslation.x - other.mTranslation.x ) > epsilon || + fabs( mTranslation.y - other.mTranslation.y ) > epsilon) + { + return false; + } + + if (fabs( mScaling.x - other.mScaling.x ) > epsilon || + fabs( mScaling.y - other.mScaling.y ) > epsilon) + { + return false; + } + + if (fabs( mRotation - other.mRotation) > epsilon) + { + return false; + } + return true; + } + + inline bool operator!= (const STransformVecInfo& other) const + { + return !(*this == other); + } // ------------------------------------------------------------------- @@ -95,8 +146,9 @@ struct STransformVecInfo */ inline bool IsUntransformed() const { - return 1.0f == fScaleU && 1.0f == fScaleV && - !fOffsetU && !fOffsetV && !fRotation; + return (1.0f == mScaling.x && 1.f == mScaling.y && + !mTranslation.x && !mTranslation.y && + mRotation < AI_TT_ROTATION_EPSILON); } // ------------------------------------------------------------------- @@ -106,26 +158,26 @@ struct STransformVecInfo { mOut = aiMatrix3x3(); - if (1.0f != this->fScaleU || 1.0f != this->fScaleV) + if (1.0f != mScaling.x || 1.0f != mScaling.y) { aiMatrix3x3 mScale; - mScale.a1 = this->fScaleU; - mScale.b2 = this->fScaleV; + mScale.a1 = mScaling.x; + mScale.b2 = mScaling.y; mOut = mScale; } - if (this->fRotation) + if (mRotation) { aiMatrix3x3 mRot; - mRot.a1 = mRot.b2 = cosf(this->fRotation); - mRot.a2 = mRot.b1 = sinf(this->fRotation); + mRot.a1 = mRot.b2 = cos(mRotation); + mRot.a2 = mRot.b1 = sin(mRotation); mRot.a2 = -mRot.a2; mOut *= mRot; } - if (this->fOffsetU || this->fOffsetV) + if (mTranslation.x || mTranslation.y) { aiMatrix3x3 mTrans; - mTrans.a3 = this->fOffsetU; - mTrans.b3 = this->fOffsetV; + mTrans.a3 = mTranslation.x; + mTrans.b3 = mTranslation.y; mOut *= mTrans; } } @@ -133,73 +185,39 @@ struct STransformVecInfo // --------------------------------------------------------------------------- -/** Helper class used by the ASE/ASK and 3DS loaders to handle texture - * coordinate transformations correctly (such as offsets, scaling) +/** Helper step to compute final UV coordinate sets if there are scalings + * or rotations in the original data read from the file. */ -class ASSIMP_API TextureTransform +class ASSIMP_API TextureTransformStep : public BaseProcess { - //! Constructor, it is not possible to create instances of this class - TextureTransform() {} public: + TextureTransformStep(); + ~TextureTransformStep(); // ------------------------------------------------------------------- - /** Returns true if a texture requires UV transformations - * \param rcIn Input texture - */ - inline static bool HasUVTransform( - const D3DS::Texture& rcIn) - { - return (rcIn.mOffsetU || rcIn.mOffsetV || - 1.0f != rcIn.mScaleU || 1.0f != rcIn.mScaleV || rcIn.mRotation); - } + bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Must be called before HasUVTransform(rcIn) is called - * \param rcIn Input texture - */ - static void PreProcessUVTransform( - D3DS::Texture& rcIn); + void Execute( aiScene* pScene); // ------------------------------------------------------------------- - /** Check whether the texture coordinate transformation of - * a texture is already contained in a given list - * \param rasVec List of transformations - * \param pcTex Pointer to the texture - */ - static void AddToList(std::vector& rasVec, - D3DS::Texture* pcTex); + void SetupProperties(const Importer* pImp); + + +protected: + // ------------------------------------------------------------------- - /** Get a full list of all texture coordinate offsets required - * for a material - * \param materials List of materials to be processed + /** Preprocess a specific UV transformation setup + * + * @param info Transformation setup to be preprocessed. */ - static void ApplyScaleNOffset(std::vector& materials); + void PreProcessUVTransform(STransformVecInfo& info); - // ------------------------------------------------------------------- - /** Get a full list of all texture coordinate offsets required - * for a material - * \param material Material to be processed - */ - static void ApplyScaleNOffset(D3DS::Material& material); +private: - // ------------------------------------------------------------------- - /** Precompute as many texture coordinate transformations as possible - * \param pcMesh Mesh containing the texture coordinate data - * \param pcSrc Input material. Must have been passed to - * ApplyScaleNOffset - */ - static void BakeScaleNOffset(aiMesh* pcMesh, D3DS::Material* pcSrc); - - - // ------------------------------------------------------------------- - /** Setup the correct UV source for a material - * \param pcMat Final material to be changed - * \param pcMatIn Input material, unconverted - */ - static void SetupMatUVSrc (aiMaterial* pcMat, - const D3DS::Material* pcMatIn); + unsigned int configFlags; }; } diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index ba7ddefcc..596338e85 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -418,7 +418,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) { if (face.mIndices[a] >= pMesh->mNumVertices) { - this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); + ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); } // the MSB flag is temporarily used by the extra verbose // mode to tell us that the JoinVerticesProcess might have @@ -523,6 +523,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) ReportError("aiMesh::mBones is non-null although there are no bones"); } } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiMesh* pMesh, const aiBone* pBone,float* afSum) @@ -548,6 +549,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh, afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight; } } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) { @@ -576,36 +578,54 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) // Animation duration is allowed to be zero in cases where the anim contains only a single key frame. // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero"); } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, - const char* szType) + aiTextureType type) { - ai_assert(NULL != szType); + const char* szType; + switch (type) + { + case aiTextureType_DIFFUSE: + szType = "Diffuse";break; - // search all keys of the material ... - // textures must be specified with rising indices (e.g. diffuse #2 may not be - // specified if diffuse #1 is not there ...) + case aiTextureType_SPECULAR: + szType = "Specular";break; - // "$tex.file.[]" - char szBaseBuf[512]; - int iLen; - iLen = ::sprintf(szBaseBuf,"$tex.file.%s",szType); - if (0 >= iLen)return; + 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; + }; + + // **************************************************************************** + // Search all keys of the material ... + // textures must be specified with ascending indices + // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...) + // **************************************************************************** int iNumIndices = 0; int iIndex = -1; for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen )) + if (!::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == type) { - const char* sz = &prop->mKey.data[iLen]; - if (*sz) - { - ++sz; - iIndex = std::max(iIndex, (int)strtol10(sz,0)); - ++iNumIndices; - } + iIndex = std::max(iIndex, (int) prop->mIndex); + ++iNumIndices; if (aiPTI_String != prop->mType) this->ReportError("Material property %s is expected to be a string",prop->mKey.data); @@ -613,52 +633,73 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, } if (iIndex +1 != iNumIndices) { - this->ReportError("%s #%i is set, but there are only %i %s textures", + ReportError("%s #%i is set, but there are only %i %s textures", szType,iIndex,iNumIndices,szType); } if (!iNumIndices)return; - // now check whether all UV indices are valid ... - iLen = ::sprintf(szBaseBuf,"$tex.uvw.%s",szType); - if (0 >= iLen)return; + // TODO: check whether the mappings are correctly + std::vector mappings(iNumIndices); + // Now check whether all UV indices are valid ... bool bNoSpecified = true; for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen )) + if (prop->mSemantic != type)continue; + + if ((int)prop->mIndex >= iNumIndices) + { + ReportError("Found texture property with index %i, although there " + "are only %i textures of type %s", + prop->mIndex, iNumIndices, szType); + } + + if (!::strcmp(prop->mKey.data,"$tex.mapping")) + { + if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) + { + ReportError("Material property %s%i is expected to be an integer (size is %i)", + prop->mKey.data,prop->mIndex,prop->mDataLength); + } + mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); + } + else if (!::strcmp(prop->mKey.data,"$tex.uvtrafo")) + { + if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) + { + ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", + prop->mKey.data,prop->mIndex, prop->mDataLength); + } + mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); + } + else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) { if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) - this->ReportError("Material property %s is expected to be an integer",prop->mKey.data); - - const char* sz = &prop->mKey.data[iLen]; - if (*sz) { - ++sz; - iIndex = strtol10(sz,NULL); - bNoSpecified = false; + ReportError("Material property %s%i is expected to be an integer (size is %i)", + prop->mKey.data,prop->mIndex,prop->mDataLength); + } + bNoSpecified = false; - // ignore UV indices for texture channel that are not there ... - if (iIndex >= iNumIndices) + // Ignore UV indices for texture channels that are not there ... + + // Get the value + iIndex = *((unsigned int*)prop->mData); + + // Check whether there is a mesh using this material + // which has not enough UV channels ... + for (unsigned int a = 0; a < mScene->mNumMeshes;++a) + { + aiMesh* mesh = this->mScene->mMeshes[a]; + if(mesh->mMaterialIndex == (unsigned int)i) { - // get the value - iIndex = *((unsigned int*)prop->mData); - - // check whether there is a mesh using this material - // which has not enough UV channels ... - for (unsigned int a = 0; a < mScene->mNumMeshes;++a) + int iChannels = 0; + while (mesh->HasTextureCoords(iChannels))++iChannels; + if (iIndex >= iChannels) { - aiMesh* mesh = this->mScene->mMeshes[a]; - if(mesh->mMaterialIndex == (unsigned int)iIndex) - { - int iChannels = 0; - while (mesh->HasTextureCoords(iChannels))++iChannels; - if (iIndex >= iChannels) - { - this->ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", - iIndex,prop->mKey.data,a,iChannels); - } - } + ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", + iIndex,prop->mKey.data,a,iChannels); } } } @@ -669,7 +710,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, // Assume that all textures are using the first UV channel for (unsigned int a = 0; a < mScene->mNumMeshes;++a) { - aiMesh* mesh = this->mScene->mMeshes[a]; + aiMesh* mesh = mScene->mMeshes[a]; if(mesh->mMaterialIndex == (unsigned int)iIndex) { if (!mesh->mTextureCoords[0]) @@ -766,15 +807,16 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) } // check whether there are invalid texture keys - SearchForInvalidTextures(pMaterial,"diffuse"); - SearchForInvalidTextures(pMaterial,"specular"); - SearchForInvalidTextures(pMaterial,"ambient"); - SearchForInvalidTextures(pMaterial,"emissive"); - SearchForInvalidTextures(pMaterial,"opacity"); - SearchForInvalidTextures(pMaterial,"shininess"); - SearchForInvalidTextures(pMaterial,"normals"); - SearchForInvalidTextures(pMaterial,"height"); + SearchForInvalidTextures(pMaterial,aiTextureType_DIFFUSE); + SearchForInvalidTextures(pMaterial,aiTextureType_SPECULAR); + SearchForInvalidTextures(pMaterial,aiTextureType_AMBIENT); + SearchForInvalidTextures(pMaterial,aiTextureType_EMISSIVE); + SearchForInvalidTextures(pMaterial,aiTextureType_OPACITY); + SearchForInvalidTextures(pMaterial,aiTextureType_SHININESS); + SearchForInvalidTextures(pMaterial,aiTextureType_HEIGHT); + SearchForInvalidTextures(pMaterial,aiTextureType_NORMALS); } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiTexture* pTexture) { @@ -806,7 +848,7 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture) } const char* sz = pTexture->achFormatHint; - if ( sz[0] >= 'A' && sz[0] <= 'Z' || + if (sz[0] >= 'A' && sz[0] <= 'Z' || sz[1] >= 'A' && sz[1] <= 'Z' || sz[2] >= 'A' && sz[2] <= 'Z' || sz[3] >= 'A' && sz[3] <= 'Z') @@ -814,35 +856,13 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture) this->ReportError("aiTexture::achFormatHint contains non-lowercase characters"); } } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, const aiNodeAnim* pNodeAnim) { - this->Validate(&pNodeAnim->mNodeName); + Validate(&pNodeAnim->mNodeName); -#if 0 - // check whether there is a bone with this name ... - unsigned int i = 0; - for (; i < this->mScene->mNumMeshes;++i) - { - aiMesh* mesh = this->mScene->mMeshes[i]; - for (unsigned int a = 0; a < mesh->mNumBones;++a) - { - if (mesh->mBones[a]->mName == pNodeAnim->mBoneName) - goto __break_out; - } - } -__break_out: - if (i == this->mScene->mNumMeshes) - { - this->ReportWarning("aiNodeAnim::mBoneName is \"%s\". However, no bone with this name was found", - pNodeAnim->mBoneName.data); - } - if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mNumRotationKeys && !pNodeAnim->mNumScalingKeys) - { - this->ReportWarning("A bone animation channel has no keys"); - } -#endif // otherwise check whether one of the keys exceeds the total duration of the animation if (pNodeAnim->mNumPositionKeys) { @@ -934,11 +954,12 @@ __break_out: ReportError("A node animation channel must have at least one subtrack"); } } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiNode* pNode) { - if (!pNode)this->ReportError("A node of the scenegraph is NULL"); - if (pNode != this->mScene->mRootNode && !pNode->mParent) + if (!pNode)ReportError("A node of the scenegraph is NULL"); + if (pNode != mScene->mRootNode && !pNode->mParent) this->ReportError("A node has no valid parent (aiNode::mParent is NULL)"); this->Validate(&pNode->mName); @@ -948,21 +969,21 @@ void ValidateDSProcess::Validate( const aiNode* pNode) { if (!pNode->mMeshes) { - this->ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)", + ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)", pNode->mNumMeshes); } std::vector abHadMesh; - abHadMesh.resize(this->mScene->mNumMeshes,false); + abHadMesh.resize(mScene->mNumMeshes,false); for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - if (pNode->mMeshes[i] >= this->mScene->mNumMeshes) + if (pNode->mMeshes[i] >= mScene->mNumMeshes) { - this->ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)", - pNode->mMeshes[i],this->mScene->mNumMeshes-1); + ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)", + pNode->mMeshes[i],mScene->mNumMeshes-1); } if (abHadMesh[pNode->mMeshes[i]]) { - this->ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)", + ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)", i,pNode->mMeshes[i]); } abHadMesh[pNode->mMeshes[i]] = true; @@ -977,10 +998,11 @@ void ValidateDSProcess::Validate( const aiNode* pNode) } for (unsigned int i = 0; i < pNode->mNumChildren;++i) { - this->Validate(pNode->mChildren[i]); + Validate(pNode->mChildren[i]); } } } + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiString* pString) { @@ -995,11 +1017,11 @@ void ValidateDSProcess::Validate( const aiString* pString) if ('\0' == *sz) { if (pString->length != (unsigned int)(sz-pString->data)) - this->ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); + ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); break; } else if (sz >= &pString->data[MAXLEN]) - this->ReportError("aiString::data is invalid. There is no terminal character"); + ReportError("aiString::data is invalid. There is no terminal character"); ++sz; } } diff --git a/code/ValidateDataStructure.h b/code/ValidateDataStructure.h index 491f05176..5cacb03ed 100644 --- a/code/ValidateDataStructure.h +++ b/code/ValidateDataStructure.h @@ -134,11 +134,10 @@ protected: /** Search the material data structure for invalid or corrupt * texture keys. * @param pMaterial Input material - * @param szType Type of the texture (the purpose string that - * occurs in material keys, e.g. "diffuse", "ambient") + * @param type Type of the texture */ void SearchForInvalidTextures(const aiMaterial* pMaterial, - const char* szType); + aiTextureType type); // ------------------------------------------------------------------- /** Validates a texture diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index 0eac7e53f..e5f705db0 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -611,7 +611,6 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vectorAddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++)); } else if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) { - ::sprintf(key,AI_MATKEY_TEXTURE_NORMALS_ "[%i]",iNM++); + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++)); } else if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) { - ::sprintf(key,AI_MATKEY_TEXTURE_SPECULAR_ "[%i]",iSM++); + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++)); } else if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) { - ::sprintf(key,AI_MATKEY_TEXTURE_AMBIENT_ "[%i]",iAM++); + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++)); } else if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) { - ::sprintf(key,AI_MATKEY_TEXTURE_EMISSIVE_ "[%i]",iEM++); + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++)); } else { - // assume it is a diffuse texture - ::sprintf(key,AI_MATKEY_TEXTURE_DIFFUSE_ "[%i]",iDM++); + // Assume it is a diffuse texture + mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++)); } - - // place texture filename property under the corresponding name - aiString tex( oldMat.mTextures[b].mName); - mat->AddProperty( &tex, key); } } diff --git a/code/makefile b/code/makefile index 7849094db..14f1a6d98 100644 --- a/code/makefile +++ b/code/makefile @@ -74,7 +74,10 @@ SOURCES = AssimpPCH.cpp \ Q3DLoader.cpp \ ScenePreprocessor.cpp \ B3DImporter.cpp \ - TargetAnimation.cpp + TargetAnimation.cpp \ + ComputeUVMappingProcess.cpp \ + ColladaLoader.cpp \ + ColladaParser.cpp OBJECTS = $(SOURCES:.cpp=.o) diff --git a/code/makefile.mingw b/code/makefile.mingw index 7e67b2f66..949597d60 100644 --- a/code/makefile.mingw +++ b/code/makefile.mingw @@ -74,8 +74,10 @@ SOURCES = AssimpPCH.cpp \ Q3DLoader.cpp \ ScenePreprocessor.cpp \ B3DImporter.cpp \ - TargetAnimation.cpp - + TargetAnimation.cpp \ + ComputeUVMappingProcess.cpp \ + ColladaLoader.cpp \ + ColladaParser.cpp OBJECTS = $(SOURCES:.cpp=.o) diff --git a/include/BoostWorkaround/boost/scoped_array.h b/include/BoostWorkaround/boost/scoped_array.h new file mode 100644 index 000000000..fe17ce162 --- /dev/null +++ b/include/BoostWorkaround/boost/scoped_array.h @@ -0,0 +1,85 @@ + +#ifndef __AI_BOOST_SCOPED_ARRAY_INCLUDED +#define __AI_BOOST_SCOPED_ARRAY_INCLUDED + +#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED + +#include + +namespace boost { + +// small replacement for boost::scoped_array +template +class scoped_array +{ +public: + + // provide a default construtctor + scoped_array() + : ptr(0) + { + } + + // construction from an existing heap object of type T + scoped_array(T* _ptr) + : ptr(_ptr) + { + } + + // automatic destruction of the wrapped object at the + // end of our lifetime + ~scoped_array() + { + delete[] ptr; + } + + inline T* get() + { + return ptr; + } + + inline operator T*() + { + return ptr; + } + + inline T* operator-> () + { + return ptr; + } + + inline void reset (T* t = 0) + { + delete[] ptr; + ptr = t; + } + + T & operator[](std::ptrdiff_t i) const + { + return ptr[i]; + } + + void swap(scoped_array & b) + { + std::swap(ptr, b.ptr); + } + +private: + + // encapsulated object pointer + T* ptr; + +}; + +template +inline void swap(scoped_array & a, scoped_array & b) +{ + a.swap(b); +} + +} // end of namespace boost + +#else +# error "scoped_array.h was already included" +#endif +#endif // __AI_BOOST_SCOPED_ARRAY_INCLUDED \ No newline at end of file diff --git a/include/BoostWorkaround/boost/scoped_ptr.hpp b/include/BoostWorkaround/boost/scoped_ptr.hpp index 81bd8c69b..09a183899 100644 --- a/include/BoostWorkaround/boost/scoped_ptr.hpp +++ b/include/BoostWorkaround/boost/scoped_ptr.hpp @@ -16,7 +16,7 @@ public: // provide a default construtctor scoped_ptr() - : ptr(NULL) + : ptr(0) { } @@ -47,6 +47,17 @@ public: { return ptr; } + + inline void reset (T* t = 0) + { + delete ptr; + ptr = t; + } + + void swap(scoped_ptr & b) + { + std::swap(ptr, b.ptr); + } private: @@ -55,6 +66,12 @@ private: }; +template +inline void swap(scoped_ptr & a, scoped_ptr & b) +{ + a.swap(b); +} + } // end of namespace boost #else diff --git a/include/aiCamera.h b/include/aiCamera.h index cfba52ddf..a818d554d 100644 --- a/include/aiCamera.h +++ b/include/aiCamera.h @@ -55,6 +55,12 @@ extern "C" { /** Helper structure to describe a virtual camera. * * Cameras have a representation in the node graph and can be animated. + * Note - some file formats (such as 3DS, ASE) export a "target point" - + * the point the camera is looking at (it can even be animated). Assimp + * writes the target point as a subnode of the camera's main node, + * called ".Target". However, this is just additional information + * then, the transformation tracks of the camera main node make the + * camera already point in the right direction. * */ struct aiCamera diff --git a/include/aiConfig.h b/include/aiConfig.h index 13f1ac944..99053eb8d 100644 --- a/include/aiConfig.h +++ b/include/aiConfig.h @@ -101,15 +101,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_CONFIG_IMPORT_SMD_KEYFRAME "imp.smd.kf" -// --------------------------------------------------------------------------- -/** \brief Configures the 3DS loader to ignore pivot points in the file - * - * There are some faulty 3DS files which look only correctly with - * pivot points disabled. - * Property type: integer (0: false; !0: true). Default value: false. - */ -#define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot" - // --------------------------------------------------------------------------- /** \brief Configures the AC loader to collect all surfaces which have the @@ -305,6 +296,23 @@ enum aiComponent #define AI_CONFIG_PP_SBP_REMOVE "pp.sbp.remove" + +#define AI_UVTRAFO_SCALING 0x1 +#define AI_UVTRAFO_ROTATION 0x2 +#define AI_UVTRAFO_TRANSLATION 0x4 +#define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION) + +// --------------------------------------------------------------------------- +/** \brief Input parameter to the #aiProcess_TransformUVCoords step: + * Specifies which UV transformations are evaluated. + * + * This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer + * property, of course). By default all transformations are enabled + * (AI_UVTRAFO_ALL). + */ +#define AI_CONFIG_PP_TUV_EVALUATE "pp.tuv.process" + + // --------------------------------------------------------------------------- /** \brief Causes assimp to favour speed against import quality. * diff --git a/include/aiDefines.h b/include/aiDefines.h index e73cc5d6c..7ee0ac167 100644 --- a/include/aiDefines.h +++ b/include/aiDefines.h @@ -78,6 +78,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OPTIMIZEGRAPH // SORTBYPTYPE // FINDINVALIDDATA + // TRANSFORMTEXCOORDS + // GENUVCOORDS // ************************************************************ diff --git a/include/aiLight.h b/include/aiLight.h index baa8d0882..5c1306809 100644 --- a/include/aiLight.h +++ b/include/aiLight.h @@ -87,6 +87,12 @@ enum aiLightSourceType * Assimp supports multiple sorts of light sources, including * directional, point and spot lights. All of them are defined with just * a single structure and distinguished by their parameters. + * Note - some file formats (such as 3DS, ASE) export a "target point" - + * the point a spot light is looking at (it can even be animated). Assimp + * writes the target point as a subnode of a spotlights's main node, + * called ".Target". However, this is just additional information + * then, the transformation tracks of the main node make the + * spot light already point in the right direction. */ struct aiLight { diff --git a/include/aiMaterial.h b/include/aiMaterial.h index 4e379dabe..c02a98bec 100644 --- a/include/aiMaterial.h +++ b/include/aiMaterial.h @@ -59,7 +59,6 @@ extern "C" { /** Defines type identifiers for use within the material system. * */ -// --------------------------------------------------------------------------- enum aiPropertyTypeInfo { /** Array of single-precision floats @@ -86,10 +85,9 @@ enum aiPropertyTypeInfo }; // --------------------------------------------------------------------------- -/** Defines texture operations like add, mul ... +/** Defines how the Nth texture is combined with all previous textures. * */ -// --------------------------------------------------------------------------- enum aiTextureOp { /** T = T1 * T2 @@ -124,21 +122,24 @@ enum aiTextureOp }; // --------------------------------------------------------------------------- -/** Defines texture mapping for use within the material system. -* +/** Defines how UV coordinates beyond the valid range are handled. */ -// --------------------------------------------------------------------------- enum aiTextureMapMode { /** A texture coordinate u|v is translated to u%1|v%1 */ aiTextureMapMode_Wrap = 0x0, - /** Texture coordinates outside the area formed by 1|1 and 0|0 - * are clamped to the nearest valid value on an axis + /** Texture coordinates outside [0...1] + * are clamped to the nearest valid value. */ aiTextureMapMode_Clamp = 0x1, + /** If the texture coordinates for a pixel are outside [0...1] + * the texture is not applied to that pixel + */ + aiTextureMapMode_Decal = 0x3, + /** A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and * 1-(u%1)|1-(v%1) otherwise */ @@ -151,6 +152,127 @@ enum aiTextureMapMode _aiTextureMapMode_Force32Bit = 0x9fffffff }; +// --------------------------------------------------------------------------- +/** Defines how the mapping coords for a texture are generated. +* +* See the AI_MATKEY_MAPPING property for more details +*/ +enum aiTextureMapping +{ + /** The mapping coordinates are taken from an UV channel. + * + * The AI_MATKEY_UVSRC key specifies from which (remember, + * meshes can have more than one UV channel). + */ + aiTextureMapping_UV = 0x0 , + + /** Spherical mapping + */ + aiTextureMapping_SPHERE = 0x1, + + /** Cylindrical mapping + */ + aiTextureMapping_CYLINDER = 0x2, + + /** Cubic mapping + */ + aiTextureMapping_BOX = 0x3, + + /** Planar mapping + */ + aiTextureMapping_PLANE = 0x4, + + /** Undefined mapping. Have fun. + */ + aiTextureMapping_OTHER = 0x5, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. + */ + _aiTextureMapping_Force32Bit = 0x9fffffff +}; + +// --------------------------------------------------------------------------- +/** Defines which mesh axes are used to construct the projection shape + * for non-UV mappings around the model. + * + * This corresponds to the AI_MATKEY_TEXMAP_AXIS property. +*/ +enum aiAxis +{ + aiAxis_X = 0x0, + aiAxis_Y = 0x1, + aiAxis_Z = 0x2, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. + */ + _aiAxis_Force32Bit = 0x9fffffff +}; + +// --------------------------------------------------------------------------- +/** Defines the purpose of a texture +*/ +enum aiTextureType +{ + /** The texture is combined with the result of the diffuse + * lighting equation. + */ + aiTextureType_DIFFUSE = 0x0, + + /** The texture is combined with the result of the specular + * lighting equation. + */ + aiTextureType_SPECULAR = 0x1, + + /** The texture is combined with the result of the ambient + * lighting equation. + */ + aiTextureType_AMBIENT = 0x2, + + /** The texture is added to the result of the lighting + * calculation. It isn't influenced by any lighting. + */ + aiTextureType_EMISSIVE = 0x3, + + /** The texture is a height map and serves as input for + * a normal map generator. + */ + aiTextureType_HEIGHT = 0x4, + + /** The texture is a (tangent space) normal-map. + * + * If the normal map does also contain a height channel + * for use with techniques such as Parallax Occlusion Mapping + * it is registered once as a normalmap. + */ + aiTextureType_NORMALS = 0x5, + + /** The texture defines the glossiness of the material. + * + * The glossiness is in fact the exponent of the specular + * lighting equation. Normally there is a conversion + * function define to map the linear color values in the + * texture to a suitable exponent. Have fun. + */ + aiTextureType_SHININESS = 0x6, + + /** The texture defines a per-pixel opacity. + * + * Normally 'white' means opaque and 'black' means + * 'transparency'. Or quite the opposite. Have fun. + */ + aiTextureType_OPACITY = 0x7, + + + /** This value is not used. It is just there to force the + * compiler to map this enum to a 32 Bit integer. + */ + _aiTextureType_Force32Bit = 0x9fffffff +}; + // --------------------------------------------------------------------------- /** Defines all shading models supported by the library * @@ -160,7 +282,6 @@ enum aiTextureMapMode * specular term for diffuse shading models like Oren-Nayar remains * undefined) */ -// --------------------------------------------------------------------------- enum aiShadingMode { /** Flat shading. Shading is done on per-face base, @@ -228,21 +349,70 @@ enum aiShadingMode _aiShadingMode_Force32Bit = 0x9fffffff }; +#include "./Compiler/pushpack1.h" + +// --------------------------------------------------------------------------- +/** Defines how an UV channel is transformed. +* +* This is just a helper structure for the AI_MATKEY_UVTRANSFORM key. +* See its documentation for more details. +*/ +struct aiUVTransform +{ + /** Translation on the u and v axes. + */ + aiVector2D mTranslation; + + /** Scaling on the u and v axes. + */ + aiVector2D mScaling; + + /** Rotation - in counter-clockwise direction. + * + * The rotation angle is specified in radians. The + * rotation center is 0.5f|0.5f. + */ + float mRotation; + + +#ifdef __cplusplus + + aiUVTransform() + : mScaling (1.f,1.f) + , mRotation (0.f) + { + // nothing to be done here ... + } + +#endif + +} PACK_STRUCT; + +#include "./Compiler/poppack1.h" // --------------------------------------------------------------------------- /** Data structure for a single property inside a material * * @see aiMaterial */ -// --------------------------------------------------------------------------- struct aiMaterialProperty { /** Specifies the name of the property (key) * - * Keys are case insensitive. + * Keys are case insensitive. */ C_STRUCT aiString mKey; + /** Textures: Specifies the exact usage semantic + */ + unsigned int mSemantic; + + /** Textures: Specifies the index of the texture + * + * Textures are counted per-type. + */ + unsigned int mIndex; + /** Size of the buffer mData is pointing to, in bytes * This value may not be 0. */ @@ -270,6 +440,7 @@ struct aiMaterialProperty aiMaterialProperty() { mData = NULL; + mIndex = mSemantic = 0; } ~aiMaterialProperty() @@ -284,16 +455,6 @@ struct aiMaterialProperty } // need to end extern C block to allow template member functions #endif -// supported texture types -#define AI_TEXTYPE_OPACITY 0x0 -#define AI_TEXTYPE_SPECULAR 0x1 -#define AI_TEXTYPE_AMBIENT 0x2 -#define AI_TEXTYPE_EMISSIVE 0x3 -#define AI_TEXTYPE_HEIGHT 0x4 -#define AI_TEXTYPE_NORMALS 0x5 -#define AI_TEXTYPE_SHININESS 0x6 -#define AI_TEXTYPE_DIFFUSE 0x7 -#define AI_TEXTYPE_GLOSSINESS 0x8 // --------------------------------------------------------------------------- /** Data structure for a material @@ -303,10 +464,11 @@ struct aiMaterialProperty * The library defines a set of standard keys (AI_MATKEY) which should be * enough for nearly all purposes. */ -// --------------------------------------------------------------------------- struct ASSIMP_API aiMaterial { + #ifdef __cplusplus + protected: aiMaterial() {} public: @@ -322,8 +484,8 @@ public: * NULL is a valid value for this parameter. */ template - inline aiReturn Get(const char* pKey,Type* pOut, - unsigned int* pMax); + inline aiReturn Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, unsigned int* pMax); // ------------------------------------------------------------------- /** Retrieve a Type value with a specific key @@ -333,37 +495,40 @@ public: * @param pOut Reference to receive the output value */ template - inline aiReturn Get(const char* pKey,Type& pOut); + inline aiReturn Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut); // ------------------------------------------------------------------- - /** Helper function to get a texture from a material + /** Helper function to get a texture from a material structure. * * This function is provided just for convinience. - * @param iIndex Index of the texture to retrieve. If the index is too + * @param mat Pointer to the input material. May not be NULL + * @param index Index of the texture to retrieve. If the index is too * large the function fails. - * @param iTexType One of the AI_TEXTYPE constants. Specifies the type of - * the texture to retrieve (e.g. diffuse, specular, height map ...) - * @param szPath Receives the output path + * @param type Specifies the type of the texture to retrieve (e.g. diffuse, + * specular, height map ...) + * @param path Receives the output path * NULL is no allowed as value - * @param piUVIndex Receives the UV index of the texture. + * @param uvindex Receives the UV index of the texture. + * NULL is allowed as value. The return value is + * @param blend Receives the blend factor for the texture * NULL is allowed as value. - * @param pfBlendFactor Receives the blend factor for the texture - * NULL is allowed as value. - * @param peTextureOp Receives the texture operation to perform between + * @param op Receives the texture operation to perform between * this texture and the previous texture. NULL is allowed as value. - * @param peMapMode Receives the mapping modes to be used for the texture. + * @param mapmode Receives the mapping modes to be used for the texture. * The parameter may be NULL but if it is a valid pointer it MUST * point to an array of 3 aiTextureMapMode variables (one for each * axis: UVW order (=XYZ)). */ // ------------------------------------------------------------------- - inline aiReturn GetTexture(unsigned int iIndex, - unsigned int iTexType, - C_STRUCT aiString* szPath, - unsigned int* piUVIndex = NULL, - float* pfBlendFactor = NULL, - aiTextureOp* peTextureOp = NULL, - aiTextureMapMode* peMapMode = NULL); + inline aiReturn GetTexture(aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping = NULL, + unsigned int* uvindex = NULL, + float* blend = NULL, + aiTextureOp* op = NULL, + aiTextureMapMode* mapmode = NULL); #endif /** List of all material properties loaded. @@ -381,69 +546,6 @@ extern "C" { #endif -// --------------------------------------------------------------------------- -/** @def AI_BUILD_KEY - * Build a material texture key from an index that is not a compile-time constant. - * Applications could do this (C-example): - * @code - * int i; - * struct aiMaterial* pMat = .... - * for (i = 0;true;++i) { - * if (AI_SUCCESS != aiGetMaterialFloat(pMat,AI_MATKEY_TEXTURE_DIFFUSE(i),...)) { - * ... - * } - * } - * @endcode - * However, this is wrong because AI_MATKEY_TEXTURE_DIFFUSE() builds the key - * string at compile time.
- * Therefore, the indexing results in a - * material key like this : "$tex.file.diffuse[i]" - and it is not very - * propable that there is a key with this name ... (except the programmer - * of an ASSIMP loader has made the same fault :-) ).
- * This is the right way: - * @code - * int i; - * char szBuffer[512]; - * struct aiMaterial* pMat = .... - * for (i = 0;true;++i) { - * AI_BUILD_KEY(AI_MATKEY_TEXTURE_DIFFUSE_,i,szBuffer); - * if (AI_SUCCESS != aiGetMaterialFloat(pMat,szBuffer,...)) { - * ... - * } - * } - * @endcode - * @param base Base material key. This is the same key you'd have used - * normally with an extra underscore as suffix (e.g. AI_MATKEY_TEXTURE_DIFFUSE_) - * @param index Index to be used. - * @param out Array of chars to receive the output value. It must be - * sufficiently large. This will be checked via a static assertion for - * C++0x. For MSVC8 and later versions the security enhanced version of - * sprintf() will be used. However, if your buffer is at least 256 bytes - * long you'll never overrun. -*/ -// --------------------------------------------------------------------------- -#if _MSC_VER >= 1400 - - // MSVC 8+. Use the sprintf_s function with security enhancements -# define AI_BUILD_KEY(base,index,out) \ - ::sprintf_s(out,"%s[%i]",base,index); - -#elif (defined ASSIMP_BUILD_CPP_09) - - // C++09 compiler. Use a static assertion to validate the size - // of the output buffer -# define AI_BUILD_KEY(base,index,out) \ - static_assert(sizeof(out) >= 180,"Output buffer is too small"); \ - ::sprintf(out,"%s[%i]",base,index); - -#else - - // otherwise ... simply hope the buffer is large enough :-) -# define AI_BUILD_KEY(base,index,out) \ - ::snprintf(out,256,"%s[%i]",base,index); -#endif - - // --------------------------------------------------------------------------- /** @def AI_MATKEY_NAME * Defines the name of the material @@ -451,16 +553,17 @@ extern "C" { * Type: string (aiString)
* Default value: none
*/ -#define AI_MATKEY_NAME "$mat.name" +#define AI_MATKEY_NAME "$mat.name",0,0 + -// --------------------------------------------------------------------------- /** @def AI_MATKEY_TWOSIDED * Indicates that the material must be rendered two-sided *
* Type: int
* Default value: 0
*/ -#define AI_MATKEY_TWOSIDED "$mat.twosided" +#define AI_MATKEY_TWOSIDED "$mat.twosided",0,0 + /** @def AI_MATKEY_SHADING_MODE * Defines the shading model to use (aiShadingMode) @@ -468,7 +571,8 @@ extern "C" { * Type: int (aiShadingMode)
* Default value: aiShadingMode_Gouraud
*/ -#define AI_MATKEY_SHADING_MODEL "$mat.shadingm" +#define AI_MATKEY_SHADING_MODEL "$mat.shadingm",0,0 + /** @def AI_MATKEY_ENABLE_WIREFRAM * Integer property. 1 to enable wireframe for rendering @@ -476,7 +580,8 @@ extern "C" { * Type: int
* Default value: 0
*/ -#define AI_MATKEY_ENABLE_WIREFRAME "$mat.wireframe" +#define AI_MATKEY_ENABLE_WIREFRAME "$mat.wireframe",0,0 + /** @def AI_MATKEY_OPACITY * Defines the base opacity of the material @@ -484,7 +589,8 @@ extern "C" { * Type: float
* Default value: 1.0f
*/ -#define AI_MATKEY_OPACITY "$mat.opacity" +#define AI_MATKEY_OPACITY "$mat.opacity",0,0 + /** @def AI_MATKEY_BUMPSCALING * Defines the height scaling of a bump map (for stuff like Parallax @@ -493,7 +599,8 @@ extern "C" { * Type: float
* Default value: 1.0f
*/ -#define AI_MATKEY_BUMPSCALING "$mat.bumpscaling" +#define AI_MATKEY_BUMPSCALING "$mat.bumpscaling",0,0 + /** @def AI_MATKEY_SHININESS * Defines the base shininess of the material @@ -502,7 +609,8 @@ extern "C" { * Type: float
* Default value: 0.0f
*/ -#define AI_MATKEY_SHININESS "$mat.shininess" +#define AI_MATKEY_SHININESS "$mat.shininess",0,0 + /** @def AI_MATKEY_SHININESS_STRENGTH * Defines the strength of the specular highlight. @@ -511,7 +619,7 @@ extern "C" { * Type: float
* Default value: 1.0f
*/ -#define AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent" +#define AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent",0,0 /** @def AI_MATKEY_REFRACTI * Index of refraction of the material. This is used by some shading models, @@ -521,7 +629,7 @@ extern "C" { * Type: float
* Default value: 1.0f
*/ -#define AI_MATKEY_REFRACTI "$mat.refracti" +#define AI_MATKEY_REFRACTI "$mat.refracti",0,0 // --------------------------------------------------------------------------- /** @def AI_MATKEY_COLOR_DIFFUSE @@ -530,7 +638,7 @@ extern "C" { * Type: color (aiColor4D or aiColor3D)
* Default value: 0.0f|0.0f|0.0f|1.0f
*/ -#define AI_MATKEY_COLOR_DIFFUSE "$clr.diffuse" +#define AI_MATKEY_COLOR_DIFFUSE "$clr.diffuse",0,0 /** @def AI_MATKEY_COLOR_AMBIENT * Defines the ambient base color of the material @@ -538,7 +646,7 @@ extern "C" { * Type: color (aiColor4D or aiColor3D)
* Default value: 0.0f|0.0f|0.0f|1.0f
*/ -#define AI_MATKEY_COLOR_AMBIENT "$clr.ambient" +#define AI_MATKEY_COLOR_AMBIENT "$clr.ambient",0,0 /** @def AI_MATKEY_COLOR_SPECULAR * Defines the specular base color of the material @@ -546,7 +654,7 @@ extern "C" { * Type: color (aiColor4D or aiColor3D)
* Default value: 0.0f|0.0f|0.0f|1.0f
*/ -#define AI_MATKEY_COLOR_SPECULAR "$clr.specular" +#define AI_MATKEY_COLOR_SPECULAR "$clr.specular",0,0 /** @def AI_MATKEY_COLOR_EMISSIVE * Defines the emissive base color of the material @@ -554,366 +662,382 @@ extern "C" { * Type: color (aiColor4D or aiColor3D)
* Default value: 0.0f|0.0f|0.0f|1.0f
*/ -#define AI_MATKEY_COLOR_EMISSIVE "$clr.emissive" - +#define AI_MATKEY_COLOR_EMISSIVE "$clr.emissive",0,0 // --------------------------------------------------------------------------- -/** @def AI_MATKEY_TEXTURE_DIFFUSE -* Defines a specific diffuse texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_DIFFUSE(N) "$tex.file.diffuse["#N"]" -#define AI_MATKEY_TEXTURE_DIFFUSE_ "$tex.file.diffuse" - -/** @def AI_MATKEY_TEXTURE_AMBIENT - * Defines a specific ambient texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_AMBIENT(N) "$tex.file.ambient["#N"]" -#define AI_MATKEY_TEXTURE_AMBIENT_ "$tex.file.ambient" - -/** @def AI_MATKEY_TEXTURE_SPECULAR - * Defines a specific specular texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_SPECULAR(N) "$tex.file.specular["#N"]" -#define AI_MATKEY_TEXTURE_SPECULAR_ "$tex.file.specular" - -/** @def AI_MATKEY_TEXTURE_EMISSIVE - * Defines a specific emissive texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_EMISSIVE(N) "$tex.file.emissive["#N"]" -#define AI_MATKEY_TEXTURE_EMISSIVE_ "$tex.file.emissive" - -/** @def AI_MATKEY_TEXTURE_NORMALS - * Defines a specific normal texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_NORMALS(N) "$tex.file.normals["#N"]" -#define AI_MATKEY_TEXTURE_NORMALS_ "$tex.file.normals" - -/** @def AI_MATKEY_TEXTURE_HEIGHT - * Defines a specified bumpmap texture (=heightmap) channel of the material - * This is very similar to #AI_MATKEY_TEXTURE_NORMALS. It is provided - * to allow applications to determine whether the input data for - * normal mapping is already a normal map or needs to be converted from - * a heightmap to a normal map. - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_HEIGHT(N) "$tex.file.height["#N"]" -#define AI_MATKEY_TEXTURE_HEIGHT_ "$tex.file.height" - -/** @def AI_MATKEY_TEXTURE_SHININESS - * Defines a specific shininess texture channel of the material. - * The shininess corresponds to the specular exponent used in the - * phong lighting equation. However, it is undefined how the exponent - * is encoded in the texture. A possible way would be the following: - * pixel value c € (0,1), n = 2^(10c+2). - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_SHININESS(N) "$tex.file.shininess["#N"]" -#define AI_MATKEY_TEXTURE_SHININESS_ "$tex.file.shininess" - - -/** @def AI_MATKEY_TEXTURE_OPACITY - * Defines a specific opacity texture channel of the material - *
- * Type: string (aiString)
- * Default value: none
- * @note The key string is built at compile time, therefore it is not - * posible to use this macro in a loop with varying values for N. - * However, you can use the macro suffixed with '_' to build the key - * dynamically. The AI_BUILD_KEY()-macro can be used to do this. -*/ -#define AI_MATKEY_TEXTURE_OPACITY(N) "$tex.file.opacity["#N"]" -#define AI_MATKEY_TEXTURE_OPACITY_ "$tex.file.opacity" - - -// --------------------------------------------------------------------------- -/** @def AI_MATKEY_TEXOP_DIFFUSE - * Specifies the blend operation too be used to combine the Nth - * diffuse texture with the (N-1)th diffuse texture (or the diffuse - * base color for the first diffuse texture) - *
- * Type: int (aiTextureOp)
- * Default value: 0
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. +/** @def AI_MATKEY_TEXTURE + * Parameters: type, N
+ * Specifies the path to the th texture of type . + * This can either be a path to the texture or a string of the form '*' + * where i is an index into the array of embedded textures that has been + * imported along with the scene. See aiTexture for more details. + * Type: String
+ * Default value to be assumed if this key isn't there:n/a
*/ // --------------------------------------------------------------------------- -#define AI_MATKEY_TEXOP_DIFFUSE(N) "$tex.op.diffuse["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_AMBIENT(N) "$tex.op.ambient["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_SPECULAR(N) "$tex.op.specular["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_EMISSIVE(N) "$tex.op.emissive["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_NORMALS(N) "$tex.op.normals["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_HEIGHT(N) "$tex.op.height["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_SHININESS(N)"$tex.op.shininess["#N"]" -/** @see AI_MATKEY_TEXOP_DIFFUSE */ -#define AI_MATKEY_TEXOP_OPACITY(N) "$tex.op.opacity["#N"]" +#define AI_MATKEY_TEXTURE(type, N) "$tex.file",type,N + +// for backward compatibility +#define AI_MATKEY_TEXTURE_DIFFUSE(N) \ + AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXTURE_SPECULAR(N) \ + AI_MATKEY_TEXTURE(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXTURE_AMBIENT(N) \ + AI_MATKEY_TEXTURE(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXTURE_EMISSIVE(N) \ + AI_MATKEY_TEXTURE(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXTURE_NORMALS(N) \ + AI_MATKEY_TEXTURE(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXTURE_HEIGHT(N) \ + AI_MATKEY_TEXTURE(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXTURE_SHININESS(N) \ + AI_MATKEY_TEXTURE(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXTURE_OPACITY(N) \ + AI_MATKEY_TEXTURE(aiTextureType_OPACITY,N) -#define AI_MATKEY_TEXOP_DIFFUSE_ "$tex.op.diffuse" -#define AI_MATKEY_TEXOP_AMBIENT_ "$tex.op.ambient" -#define AI_MATKEY_TEXOP_SPECULAR_ "$tex.op.specular" -#define AI_MATKEY_TEXOP_EMISSIVE_ "$tex.op.emissive" -#define AI_MATKEY_TEXOP_NORMALS_ "$tex.op.normals" -#define AI_MATKEY_TEXOP_HEIGHT_ "$tex.op.height" -#define AI_MATKEY_TEXOP_SHININESS_ "$tex.op.shininess" -#define AI_MATKEY_TEXOP_OPACITY_ "$tex.op.opacity" // --------------------------------------------------------------------------- -/** @def AI_MATKEY_UVWSRC_DIFFUSE - * Specifies the UV channel to be used for the Nth diffuse texture - *
+/** @def AI_MATKEY_UVWSRC + * Parameters: type, N
+ * Specifies which UV channel is used as source for the mapping coordinates + * of the th texture of type . * Type: int
- * Default value: 0
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. + * Default value to be assumed if this key isn't there:0
+ * Requires: AI_MATKEY_TEXTURE(type,N) and + * AI_MATKEY_TEXTURE_MAPPING(type,N) == UV
*/ // --------------------------------------------------------------------------- -#define AI_MATKEY_UVWSRC_DIFFUSE(N) "$tex.uvw.diffuse["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_AMBIENT(N) "$tex.uvw.ambient["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_SPECULAR(N) "$tex.uvw.specular["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_EMISSIVE(N) "$tex.uvw.emissive["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_NORMALS(N) "$tex.uvw.normals["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_HEIGHT(N) "$tex.uvw.height["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_SHININESS(N) "$tex.uvw.shininess["#N"]" -/** @see AI_MATKEY_UVWSRC_DIFFUSE */ -#define AI_MATKEY_UVWSRC_OPACITY(N) "$tex.uvw.opacity["#N"]" +#define AI_MATKEY_UVWSRC(type, N) "$tex.uvwsrc",type,N + +// for backward compatibility +#define AI_MATKEY_UVWSRC_DIFFUSE(N) \ + AI_MATKEY_UVWSRC(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_UVWSRC_SPECULAR(N) \ + AI_MATKEY_UVWSRC(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_UVWSRC_AMBIENT(N) \ + AI_MATKEY_UVWSRC(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_UVWSRC_EMISSIVE(N) \ + AI_MATKEY_UVWSRC(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_UVWSRC_NORMALS(N) \ + AI_MATKEY_UVWSRC(aiTextureType_NORMALS,N) + +#define AI_MATKEY_UVWSRC_HEIGHT(N) \ + AI_MATKEY_UVWSRC(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_UVWSRC_SHININESS(N) \ + AI_MATKEY_UVWSRC(aiTextureType_SHININESS,N) + +#define AI_MATKEY_UVWSRC_OPACITY(N) \ + AI_MATKEY_UVWSRC(aiTextureType_OPACITY,N) -#define AI_MATKEY_UVWSRC_DIFFUSE_ "$tex.uvw.diffuse" -#define AI_MATKEY_UVWSRC_AMBIENT_ "$tex.uvw.ambient" -#define AI_MATKEY_UVWSRC_SPECULAR_ "$tex.uvw.specular" -#define AI_MATKEY_UVWSRC_EMISSIVE_ "$tex.uvw.emissive" -#define AI_MATKEY_UVWSRC_NORMALS_ "$tex.uvw.normals" -#define AI_MATKEY_UVWSRC_HEIGHT_ "$tex.uvw.height" -#define AI_MATKEY_UVWSRC_SHININESS_ "$tex.uvw.shininess" -#define AI_MATKEY_UVWSRC_OPACITY_ "$tex.uvw.opacity" // --------------------------------------------------------------------------- -/** @def AI_MATKEY_TEXBLEND_DIFFUSE - * Specifies the blend factor to be used for the Nth diffuse texture. +/** @def AI_MATKEY_TEXOP + * Parameters: type, N
+ * Specifies how the of the th texture of type is combined with + * the result of all color values from all previous textures combined. + * Type: int (aiTextureOp)
+ * Default value to be assumed if this key isn't there:multiply
+ * Requires: AI_MATKEY_TEXTURE(type,N)
+ */ +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXOP(type, N) "$tex.op",type,N + +// for backward compatibility +#define AI_MATKEY_TEXOP_DIFFUSE(N) \ + AI_MATKEY_TEXOP(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXOP_SPECULAR(N) \ + AI_MATKEY_TEXOP(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXOP_AMBIENT(N) \ + AI_MATKEY_TEXOP(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXOP_EMISSIVE(N) \ + AI_MATKEY_TEXOP(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXOP_NORMALS(N) \ + AI_MATKEY_TEXOP(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXOP_HEIGHT(N) \ + AI_MATKEY_TEXOP(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXOP_SHININESS(N) \ + AI_MATKEY_TEXOP(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXOP_OPACITY(N) \ + AI_MATKEY_TEXOP(aiTextureType_OPACITY,N) + + +// --------------------------------------------------------------------------- +/** @def AI_MATKEY_MAPPING + * Parameters: type, N
+ * Specifies how the of the th texture of type is mapped. + *
+ * Type: int (aiTextureMapping)
+ * Default value to be assumed if this key isn't there:UV
+ * Requires: AI_MATKEY_TEXTURE(type,N)
+ */ +// --------------------------------------------------------------------------- +#define AI_MATKEY_MAPPING(type, N) "$tex.mapping",type,N + +// for backward compatibility +#define AI_MATKEY_MAPPING_DIFFUSE(N) \ + AI_MATKEY_MAPPING(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPING_SPECULAR(N) \ + AI_MATKEY_MAPPING(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPING_AMBIENT(N) \ + AI_MATKEY_MAPPING(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPING_EMISSIVE(N) \ + AI_MATKEY_MAPPING(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPING_NORMALS(N) \ + AI_MATKEY_MAPPING(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPING_HEIGHT(N) \ + AI_MATKEY_MAPPING(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPING_SHININESS(N) \ + AI_MATKEY_MAPPING(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPING_OPACITY(N) \ + AI_MATKEY_MAPPING(aiTextureType_OPACITY,N) + +// --------------------------------------------------------------------------- +/** @def AI_MATKEY_TEXBLEND ( + * Parameters: type, N
+ * Specifies the strength of the th texture of type . This is just + * a multiplier for the texture's color values. *
* Type: float
- * Default value: 1.0f
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. + * Default value to be assumed if this key isn't there: 1.f
+ * Requires: AI_MATKEY_TEXTURE(type,N)
*/ // --------------------------------------------------------------------------- -#define AI_MATKEY_TEXBLEND_DIFFUSE(N) "$tex.blend.diffuse["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_AMBIENT(N) "$tex.blend.ambient["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_SPECULAR(N) "$tex.blend.specular["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_EMISSIVE(N) "$tex.blend.emissive["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_NORMALS(N) "$tex.blend.normals["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_HEIGHT(N) "$tex.blend.height["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_SHININESS(N) "$tex.blend.shininess["#N"]" -/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ -#define AI_MATKEY_TEXBLEND_OPACITY(N) "$tex.blend.opacity["#N"]" +#define AI_MATKEY_TEXBLEND(type, N) "$tex.blend",type,N -#define AI_MATKEY_TEXBLEND_DIFFUSE_ "$tex.blend.diffuse" -#define AI_MATKEY_TEXBLEND_AMBIENT_ "$tex.blend.ambient" -#define AI_MATKEY_TEXBLEND_SPECULAR_ "$tex.blend.specular" -#define AI_MATKEY_TEXBLEND_EMISSIVE_ "$tex.blend.emissive" -#define AI_MATKEY_TEXBLEND_NORMALS_ "$tex.blend.normals" -#define AI_MATKEY_TEXBLEND_HEIGHT_ "$tex.blend.height" -#define AI_MATKEY_TEXBLEND_SHININESS_ "$tex.blend.shininess" -#define AI_MATKEY_TEXBLEND_OPACITY_ "$tex.blend.opacity" +// for backward compatibility +#define AI_MATKEY_TEXBLEND_DIFFUSE(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_TEXBLEND_SPECULAR(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_TEXBLEND_AMBIENT(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_TEXBLEND_EMISSIVE(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_TEXBLEND_NORMALS(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_NORMALS,N) + +#define AI_MATKEY_TEXBLEND_HEIGHT(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_TEXBLEND_SHININESS(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_SHININESS,N) + +#define AI_MATKEY_TEXBLEND_OPACITY(N) \ + AI_MATKEY_TEXBLEND(aiTextureType_OPACITY,N) // --------------------------------------------------------------------------- -/** @def AI_MATKEY_MAPPINGMODE_U_DIFFUSE - * Specifies the texture mapping mode for the Nth diffuse texture in +/** @def AI_MATKEY_MAPPINGMODE_U + * Parameters: type, N
+ * Specifies the texture mapping mode for the th texture of type in * the u (x) direction *
* Type: int (aiTextureMapMode)
* Default value: aiTextureMapMode_Wrap
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. + * Requires: AI_MATKEY_TEXTURE(type,N)
*/ // --------------------------------------------------------------------------- -#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) "$tex.mapmodeu.diffuse["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_AMBIENT(N) "$tex.mapmodeu.ambient["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_SPECULAR(N) "$tex.mapmodeu.specular["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_EMISSIVE(N) "$tex.mapmodeu.emissive["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_NORMALS(N) "$tex.mapmodeu.normals["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_HEIGHT(N) "$tex.mapmodeu.height["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_SHININESS(N)"$tex.mapmodeu.shininess["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_U_OPACITY(N) "$tex.mapmodeu.opacity["#N"]" +#define AI_MATKEY_MAPPINGMODE_U(type, N) "$tex.mapmodeu",type,N -#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE_ "$tex.mapmodeu.diffuse" -#define AI_MATKEY_MAPPINGMODE_U_AMBIENT_ "$tex.mapmodeu.ambient" -#define AI_MATKEY_MAPPINGMODE_U_SPECULAR_ "$tex.mapmodeu.specular" -#define AI_MATKEY_MAPPINGMODE_U_EMISSIVE_ "$tex.mapmodeu.emissive" -#define AI_MATKEY_MAPPINGMODE_U_NORMALS_ "$tex.mapmodeu.normals" -#define AI_MATKEY_MAPPINGMODE_U_HEIGHT_ "$tex.mapmodeu.height" -#define AI_MATKEY_MAPPINGMODE_U_SHININESS_ "$tex.mapmodeu.shininess" -#define AI_MATKEY_MAPPINGMODE_U_OPACITY_ "$tex.mapmodeu.opacity" +// for backward compatibility +#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPINGMODE_U_SPECULAR(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPINGMODE_U_AMBIENT(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPINGMODE_U_EMISSIVE(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPINGMODE_U_NORMALS(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPINGMODE_U_HEIGHT(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPINGMODE_U_SHININESS(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPINGMODE_U_OPACITY(N) \ + AI_MATKEY_MAPPINGMODE_U(aiTextureType_OPACITY,N) // --------------------------------------------------------------------------- -/** @def AI_MATKEY_MAPPINGMODE_V_DIFFUSE - * Specifies the texture mapping mode for the Nth diffuse texture in - * the v (y) direction - *
- * Type: int (aiTextureMapMode)
- * Default value: aiTextureMapMode_Wrap
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. - */ -// --------------------------------------------------------------------------- -#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) "$tex.mapmodev.diffuse["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_AMBIENT(N) "$tex.mapmodev.ambient["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_SPECULAR(N) "$tex.mapmodev.specular["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_EMISSIVE(N) "$tex.mapmodev.emissive["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_NORMALS(N) "$tex.mapmodev.normals["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_HEIGHT(N) "$tex.mapmodev.height["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_SHININESS(N)"$tex.mapmodev.shininess["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_V_OPACITY(N) "$tex.mapmodev.opacity["#N"]" - -#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE_ "$tex.mapmodev.diffuse" -#define AI_MATKEY_MAPPINGMODE_V_AMBIENT_ "$tex.mapmodev.ambient" -#define AI_MATKEY_MAPPINGMODE_V_SPECULAR_ "$tex.mapmodev.specular" -#define AI_MATKEY_MAPPINGMODE_V_EMISSIVE_ "$tex.mapmodev.emissive" -#define AI_MATKEY_MAPPINGMODE_V_NORMALS_ "$tex.mapmodev.normals" -#define AI_MATKEY_MAPPINGMODE_V_HEIGHT_ "$tex.mapmodev.height" -#define AI_MATKEY_MAPPINGMODE_V_SHININESS_ "$tex.mapmodev.shininess" -#define AI_MATKEY_MAPPINGMODE_V_OPACITY_ "$tex.mapmodev.opacity" - -// --------------------------------------------------------------------------- -/** @def AI_MATKEY_MAPPINGMODE_W_DIFFUSE - * Specifies the texture mapping mode for the Nth diffuse texture in +/** @def AI_MATKEY_MAPPINGMODE_V + * Parameters: type, N
+ * Specifies the texture mapping mode for the th texture of type in * the w (z) direction *
* Type: int (aiTextureMapMode)
* Default value: aiTextureMapMode_Wrap
- * Requires: AI_MATKEY_TEXTURE_DIFFUSE(0)
- * @note The key string is built at compile time, therefore it is not posible - * to use this macro in a loop with varying values for N. However, you can - * use the macro suffixed with '_' to build the key dynamically. The - * AI_BUILD_KEY()-macro can be used to do this. + * Requires: AI_MATKEY_TEXTURE(type,N)
*/ // --------------------------------------------------------------------------- -#define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N) "$tex.mapmodew.diffuse["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_AMBIENT(N) "$tex.mapmodew.ambient["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_SPECULAR(N) "$tex.mapmodew.specular["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_EMISSIVE(N) "$tex.mapmodew.emissive["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_NORMALS(N) "$tex.mapmodew.normals["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_HEIGHT(N) "$tex.mapmodew.bump["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_SHININESS(N)"$tex.mapmodew.shininess["#N"]" -/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ -#define AI_MATKEY_MAPPINGMODE_W_OPACITY(N) "$tex.mapmodew.opacity["#N"]" +#define AI_MATKEY_MAPPINGMODE_V(type, N) "$tex.mapmodev",type,N -#define AI_MATKEY_MAPPINGMODE_W_DIFFUSE_ "$tex.mapmodew.diffuse" -#define AI_MATKEY_MAPPINGMODE_W_AMBIENT_ "$tex.mapmodew.ambient" -#define AI_MATKEY_MAPPINGMODE_W_SPECULAR_ "$tex.mapmodew.specular" -#define AI_MATKEY_MAPPINGMODE_W_EMISSIVE_ "$tex.mapmodew.emissive" -#define AI_MATKEY_MAPPINGMODE_W_NORMALS_ "$tex.mapmodew.normals" -#define AI_MATKEY_MAPPINGMODE_W_HEIGHT_ "$tex.mapmodew.height" -#define AI_MATKEY_MAPPINGMODE_W_SHININESS_ "$tex.mapmodew.shininess" -#define AI_MATKEY_MAPPINGMODE_W_OPACITY_ "$tex.mapmodew.opacity" +// for backward compatibility +#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_DIFFUSE,N) -#define AI_MATKEY_ORENNAYAR_ROUGHNESS "$shading.orennayar.roughness" -#define AI_MATKEY_MINNAERT_DARKNESS "$shading.minnaert.darkness" -#define AI_MATKEY_COOK_TORRANCE_PARAM "$shading.cookt.param" +#define AI_MATKEY_MAPPINGMODE_V_SPECULAR(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPINGMODE_V_AMBIENT(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPINGMODE_V_EMISSIVE(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPINGMODE_V_NORMALS(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPINGMODE_V_HEIGHT(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPINGMODE_V_SHININESS(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPINGMODE_V_OPACITY(N) \ + AI_MATKEY_MAPPINGMODE_V(aiTextureType_OPACITY,N) + +// --------------------------------------------------------------------------- +/** @def AI_MATKEY_MAPPINGMODE_W + * Parameters: type, N
+ * Specifies the texture mapping mode for the th texture of type in + * the w (z) direction + *
+ * Type: int (aiTextureMapMode)
+ * Default value: aiTextureMapMode_Wrap
+ * Requires: AI_MATKEY_TEXTURE(type,N)
+ */ +// --------------------------------------------------------------------------- +#define AI_MATKEY_MAPPINGMODE_W(type, N) "$tex.mapmodew",type,N + +// for backward compatibility +#define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_MAPPINGMODE_W_SPECULAR(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_MAPPINGMODE_W_AMBIENT(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_MAPPINGMODE_W_EMISSIVE(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_MAPPINGMODE_W_NORMALS(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_NORMALS,N) + +#define AI_MATKEY_MAPPINGMODE_W_HEIGHT(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_MAPPINGMODE_W_SHININESS(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_SHININESS,N) + +#define AI_MATKEY_MAPPINGMODE_W_OPACITY(N) \ + AI_MATKEY_MAPPINGMODE_W(aiTextureType_OPACITY,N) + + +// --------------------------------------------------------------------------- +/** @def AI_MATKEY_TEXMAP_AXIS + * Parameters: type, N
+ * Specifies the main mapping axis th texture of type . + * This applies to non-UV mapped textures. For spherical, cylindrical and + * planar this is the main axis of the corresponding geometric shape. + *
+ * Type: int (aiAxis)
+ * Default value: aiAxis_Z
+ * Requires: AI_MATKEY_TEXTURE(type,N) and + * AI_MATKEY_TEXTURE_MAPPING(type,N) != UV
+ */ +// --------------------------------------------------------------------------- +#define AI_MATKEY_TEXMAP_AXIS(type, N) "$tex.mapaxis",type,N + +// --------------------------------------------------------------------------- +/** @def AI_MATKEY_UVTRANSFORM + * Parameters: type, N
+ * Specifies how the UV mapping coordinates for theth texture of type + * are transformed before they're used for mapping. This is an array + * of five floats - use the aiUVTransform structure for simplicity. + *
+ * Type: Array of 5 floats
+ * Default value: 0.f,0.f,1.f,1.f,0.f
+ * Requires: AI_MATKEY_TEXTURE(type,N) and + * AI_MATKEY_TEXTURE_MAPPING(type,N) == UV
+ * Note:Transformed 3D texture coordinates are not supported + */ +// --------------------------------------------------------------------------- +#define AI_MATKEY_UVTRANSFORM(type, N) "$tex.uvtrafo",type,N + +// for backward compatibility +#define AI_MATKEY_UVTRANSFORM_DIFFUSE(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE,N) + +#define AI_MATKEY_UVTRANSFORM_SPECULAR(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_SPECULAR,N) + +#define AI_MATKEY_UVTRANSFORM_AMBIENT(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_AMBIENT,N) + +#define AI_MATKEY_UVTRANSFORM_EMISSIVE(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_EMISSIVE,N) + +#define AI_MATKEY_UVTRANSFORM_NORMALS(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_NORMALS,N) + +#define AI_MATKEY_UVTRANSFORM_HEIGHT(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_HEIGHT,N) + +#define AI_MATKEY_UVTRANSFORM_SHININESS(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_SHININESS,N) + +#define AI_MATKEY_UVTRANSFORM_OPACITY(N) \ + AI_MATKEY_UVTRANSFORM(aiTextureType_OPACITY,N) + + + + +#define AI_MATKEY_ORENNAYAR_ROUGHNESS "$shading.orennayar.roughness",0,0 +#define AI_MATKEY_MINNAERT_DARKNESS "$shading.minnaert.darkness",0,0 +#define AI_MATKEY_COOK_TORRANCE_PARAM "$shading.cookt.param",0,0 /** @def AI_MATKEY_GLOBAL_BACKGROUND_IMAGE * Global property defined by some loaders. Contains the path to * the image file to be used as background image. */ -#define AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "$global.bg.image2d" +#define AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "$global.bg.image2d",0,0 // --------------------------------------------------------------------------- @@ -927,6 +1051,8 @@ extern "C" { // --------------------------------------------------------------------------- ASSIMP_API aiReturn aiGetMaterialProperty(const C_STRUCT aiMaterial* pMat, const char* pKey, + aiTextureType type, + unsigned int index, const C_STRUCT aiMaterialProperty** pPropOut); @@ -934,57 +1060,118 @@ ASSIMP_API aiReturn aiGetMaterialProperty(const C_STRUCT aiMaterial* pMat, /** Retrieve an array of float values with a specific key * from the material * +* Pass one of the AI_MATKEY_XXX constants for the last three parameters (the +* example reads the AI_MATKEY_UVTRANSFORM property of the first diffuse texture) +* @begincode +* +* aiUVTransform trafo; +* unsigned int max = sizeof(aiUVTransform); +* if (AI_SUCCESS != aiGetMaterialFloatArray(mat, AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE,0), +* (float*)&trafo, &max) || sizeof(aiUVTransform) != max) +* { +* // error handling +* } +* @endcode +* * @param pMat Pointer to the input material. May not be NULL * @param pKey Key to search for. One of the AI_MATKEY_XXX constants. * @param pOut Pointer to a buffer to receive the result. * @param pMax Specifies the size of the given buffer, in float's. * Receives the number of values (not bytes!) read. +* @param type (see the code sample above) +* @param index (see the code sample above) +* @return Specifies whether the key has been found. If not, the output +* arrays remains unmodified and pMax is set to 0. */ // --------------------------------------------------------------------------- ASSIMP_API aiReturn aiGetMaterialFloatArray(const C_STRUCT aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, float* pOut, unsigned int* pMax); + + #ifdef __cplusplus -// inline it + +// --------------------------------------------------------------------------- +/** Retrieve a single float property with a specific key from the material. +* +* Pass one of the AI_MATKEY_XXX constants for the last three parameters (the +* example reads the AI_MATKEY_SPECULAR_STRENGTH property of the first diffuse texture) +* @begincode +* +* float specStrength = 1.f; // default value, remains unmodified if we fail. +* aiGetMaterialFloat(mat, AI_MATKEY_SPECULAR_STRENGTH, +* (float*)&specStrength); +* @endcode +* +* @param pMat Pointer to the input material. May not be NULL +* @param pKey Key to search for. One of the AI_MATKEY_XXX constants. +* @param pOut Receives the output float. +* @param type (see the code sample above) +* @param index (see the code sample above) +* @return Specifies whether the key has been found. If not, the output +* float remains unmodified. +*/ +// --------------------------------------------------------------------------- inline aiReturn aiGetMaterialFloat(const C_STRUCT aiMaterial* pMat, - const char* pKey, - float* pOut) - {return aiGetMaterialFloatArray(pMat,pKey,pOut,(unsigned int*)0x0);} + const char* pKey, + unsigned int type, + unsigned int index, + float* pOut) +{ + return aiGetMaterialFloatArray(pMat,pKey,type,index,pOut,(unsigned int*)0x0); +} + #else -// use our friend, the C preprocessor -#define aiGetMaterialFloat (pMat, pKey, pOut) \ - aiGetMaterialFloatArray(pMat, pKey, pOut, NULL) + +// Use our friend, the C preprocessor +#define aiGetMaterialFloat (pMat, type, index, pKey, pOut) \ + aiGetMaterialFloatArray(pMat, type, index, pKey, pOut, NULL) + #endif //!__cplusplus // --------------------------------------------------------------------------- /** Retrieve an array of integer values with a specific key -* from the material +* from a material * -* @param pMat Pointer to the input material. May not be NULL -* @param pKey Key to search for. One of the AI_MATKEY_XXX constants. -* @param pOut Pointer to a buffer to receive the result. -* @param pMax Specifies the size of the given buffer, in int's. -* Receives the number of values (not bytes!) read. +* See the sample for aiGetMaterialFloatArray for more information. */ // --------------------------------------------------------------------------- ASSIMP_API aiReturn aiGetMaterialIntegerArray(const C_STRUCT aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, int* pOut, unsigned int* pMax); + #ifdef __cplusplus -// inline it + +// --------------------------------------------------------------------------- +/** Retrieve an integer property with a specific key from a material +* +* See the sample for aiGetMaterialFloat for more information. +*/ +// --------------------------------------------------------------------------- inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial* pMat, - const char* pKey, - int* pOut) - {return aiGetMaterialIntegerArray(pMat,pKey,pOut,(unsigned int*)0x0);} + const char* pKey, + unsigned int type, + unsigned int index, + int* pOut) +{ + return aiGetMaterialIntegerArray(pMat,pKey,type,index,pOut,(unsigned int*)0x0); +} + #else + // use our friend, the C preprocessor -#define aiGetMaterialInteger (pMat, pKey, pOut) \ - aiGetMaterialIntegerArray(pMat, pKey, pOut, NULL) +#define aiGetMaterialInteger (pMat, type, index, pKey, pOut) \ + aiGetMaterialIntegerArray(pMat, type, index, pKey, pOut, NULL) + #endif //!__cplusplus @@ -992,70 +1179,72 @@ inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial* pMat, // --------------------------------------------------------------------------- /** Retrieve a color value from the material property table * -* @param pMat Pointer to the input material. May not be NULL -* @param pKey Key to search for. One of the AI_MATKEY_XXX constants. -* @param pOut Pointer to a buffer to receive the result. +* See the sample for aiGetMaterialFloat for more information. */ // --------------------------------------------------------------------------- ASSIMP_API aiReturn aiGetMaterialColor(const C_STRUCT aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, aiColor4D* pOut); // --------------------------------------------------------------------------- /** Retrieve a string from the material property table * -* @param pMat Pointer to the input material. May not be NULL -* @param pKey Key to search for. One of the AI_MATKEY_XXX constants. -* @param pOut Pointer to a buffer to receive the result. +* See the sample for aiGetMaterialFloat for more information. */ // --------------------------------------------------------------------------- ASSIMP_API aiReturn aiGetMaterialString(const C_STRUCT aiMaterial* pMat, const char* pKey, + unsigned int type, + unsigned int index, aiString* pOut); // --------------------------------------------------------------------------- -/** Helper function to get a texture from a material +/** Helper function to get a texture from a material structure. * * This function is provided just for convinience. - * @param pMat Pointer to the input material. May not be NULL - * @param iIndex Index of the texture to retrieve. If the index is too + * @param mat Pointer to the input material. May not be NULL + * @param index Index of the texture to retrieve. If the index is too * large the function fails. - * @param iTexType One of the AI_TEXTYPE constants. Specifies the type of - * the texture to retrieve (e.g. diffuse, specular, height map ...) - * @param szPath Receives the output path + * @param type Specifies the type of the texture to retrieve (e.g. diffuse, + * specular, height map ...) + * @param path Receives the output path * NULL is no allowed as value - * @param piUVIndex Receives the UV index of the texture. + * @param uvindex Receives the UV index of the texture. + * NULL is allowed as value. The return value is + * @param blend Receives the blend factor for the texture * NULL is allowed as value. - * @param pfBlendFactor Receives the blend factor for the texture - * NULL is allowed as value. - * @param peTextureOp Receives the texture operation to perform between + * @param op Receives the texture operation to perform between * this texture and the previous texture. NULL is allowed as value. - * @param peMapMode Receives the mapping modes to be used for the texture. + * @param mapmode Receives the mapping modes to be used for the texture. * The parameter may be NULL but if it is a valid pointer it MUST * point to an array of 3 aiTextureMapMode variables (one for each * axis: UVW order (=XYZ)). */ // --------------------------------------------------------------------------- #ifdef __cplusplus -ASSIMP_API aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* pMat, - unsigned int iIndex, - unsigned int iTexType, - C_STRUCT aiString* szPath, - unsigned int* piUVIndex = NULL, - float* pfBlendFactor = NULL, - aiTextureOp* peTextureOp = NULL, - aiTextureMapMode* peMapMode = NULL); +ASSIMP_API aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, + aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping = NULL, + unsigned int* uvindex = NULL, + float* blend = NULL, + aiTextureOp* op = NULL, + aiTextureMapMode* mapmode = NULL); #else -aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* pMat, - unsigned int iIndex, - unsigned int iTexType, - C_STRUCT aiString* szPath, - unsigned int* piUVIndex, - float* pfBlendFactor, - aiTextureOp* peTextureOp, - aiTextureMapMode* peMapMode); +aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, + aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + float* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/); #endif // !#ifdef __cplusplus #ifdef __cplusplus diff --git a/include/aiMaterial.inl b/include/aiMaterial.inl index 4f12cf34d..c99c4e88a 100644 --- a/include/aiMaterial.inl +++ b/include/aiMaterial.inl @@ -1,135 +1,146 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 Defines the material system of the library - * - */ - -#ifndef AI_MATERIAL_INL_INC -#define AI_MATERIAL_INL_INC - -// --------------------------------------------------------------------------- -inline aiReturn aiMaterial::GetTexture(unsigned int iIndex, - unsigned int iTexType, - aiString* szPath, - unsigned int* piUVIndex , - float* pfBlendFactor , - aiTextureOp* peTextureOp , - aiTextureMapMode* peMapMode ) -{ - return aiGetMaterialTexture(this,iIndex,iTexType,szPath, - piUVIndex,pfBlendFactor,peTextureOp,peMapMode); -} -// --------------------------------------------------------------------------- -template -inline aiReturn aiMaterial::Get(const char* pKey,Type* pOut, - unsigned int* pMax) -{ - unsigned int iNum = pMax ? *pMax : 1; - - aiMaterialProperty* prop; - aiReturn ret = aiGetMaterialProperty(this,pKey,&prop); - if ( AI_SUCCESS == ret ) - { - if (prop->mDataLength < sizeof(Type)*iNum)return AI_FAILURE; - if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE; - - iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type)); - ::memcpy(pOut,prop->mData,iNum * sizeof(Type)); - if (pMax)*pMax = iNum; - } - return ret; -} -// --------------------------------------------------------------------------- -template -inline aiReturn aiMaterial::Get(const char* pKey,Type& pOut) -{ - aiMaterialProperty* prop; - aiReturn ret = aiGetMaterialProperty(this,pKey,&prop); - if ( AI_SUCCESS == ret ) - { - if (prop->mDataLength < sizeof(Type))return AI_FAILURE; - if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE; - - ::memcpy(&pOut,prop->mData,sizeof(Type)); - } - return ret; -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,float* pOut, - unsigned int* pMax) -{ - return aiGetMaterialFloatArray(this,pKey,pOut,pMax); -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,int* pOut, - unsigned int* pMax) -{ - return aiGetMaterialIntegerArray(this,pKey,pOut,pMax); -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,float& pOut) -{ - return aiGetMaterialFloat(this,pKey,&pOut); -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,int& pOut) -{ - return aiGetMaterialInteger(this,pKey,&pOut); -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,aiColor4D& pOut) -{ - return aiGetMaterialColor(this,pKey,&pOut); -} -// --------------------------------------------------------------------------- -template <> -inline aiReturn aiMaterial::Get(const char* pKey,aiString& pOut) -{ - return aiGetMaterialString(this,pKey,&pOut); -} - -#endif //! AI_MATERIAL_INL_INC +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 Defines the material system of the library + * + */ + +#ifndef AI_MATERIAL_INL_INC +#define AI_MATERIAL_INL_INC + +// --------------------------------------------------------------------------- +inline aiReturn aiMaterial::GetTexture( aiTextureType type, + unsigned int idx, + C_STRUCT aiString* path, + aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + float* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/) +{ + return aiGetMaterialTexture(this,type,idx,path,mapping,uvindex,blend,op,mapmode); +} + +// --------------------------------------------------------------------------- +template +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, + unsigned int* pMax) +{ + unsigned int iNum = pMax ? *pMax : 1; + + aiMaterialProperty* prop; + aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop); + if ( AI_SUCCESS == ret ) + { + if (prop->mDataLength < sizeof(Type)*iNum)return AI_FAILURE; + if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE; + + iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type)); + ::memcpy(pOut,prop->mData,iNum * sizeof(Type)); + if (pMax)*pMax = iNum; + } + return ret; +} + +// --------------------------------------------------------------------------- +template +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut) +{ + aiMaterialProperty* prop; + aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop); + if ( AI_SUCCESS == ret ) + { + if (prop->mDataLength < sizeof(Type))return AI_FAILURE; + if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE; + + ::memcpy(&pOut,prop->mData,sizeof(Type)); + } + return ret; +} + +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,float* pOut, + unsigned int* pMax) +{ + return aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int* pOut, + unsigned int* pMax) +{ + return aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,float& pOut) +{ + return aiGetMaterialFloat(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int& pOut) +{ + return aiGetMaterialInteger(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor4D& pOut) +{ + return aiGetMaterialColor(this,pKey,type,idx,&pOut); +} +// --------------------------------------------------------------------------- +template <> +inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiString& pOut) +{ + return aiGetMaterialString(this,pKey,type,idx,&pOut); +} + +#endif //! AI_MATERIAL_INL_INC diff --git a/include/aiMatrix3x3.h b/include/aiMatrix3x3.h index 4b21237d4..8b4efd00a 100644 --- a/include/aiMatrix3x3.h +++ b/include/aiMatrix3x3.h @@ -48,11 +48,11 @@ extern "C" { #endif struct aiMatrix4x4; +struct aiVector2D; // --------------------------------------------------------------------------- /** Represents a row-major 3x3 matrix */ -// --------------------------------------------------------------------------- struct aiMatrix3x3 { #ifdef __cplusplus @@ -77,6 +77,22 @@ struct aiMatrix3x3 aiMatrix3x3 operator* (const aiMatrix3x3& m) const; aiMatrix3x3& Transpose(); + + /** \brief Returns a rotation matrix + * \param a Rotation angle, in radians + * \param out Receives the output matrix + * \return Reference to the output matrix + */ + static aiMatrix3x3& Rotation(float a, aiMatrix3x3& out); + + + /** \brief Returns a translation matrix + * \param v Translation vector + * \param out Receives the output matrix + * \return Reference to the output matrix + */ + static aiMatrix3x3& Translation( const aiVector2D& v, aiMatrix3x3& out); + #endif // __cplusplus diff --git a/include/aiMatrix3x3.inl b/include/aiMatrix3x3.inl index 656263cb5..7706f1f2a 100644 --- a/include/aiMatrix3x3.inl +++ b/include/aiMatrix3x3.inl @@ -51,6 +51,27 @@ inline aiMatrix3x3& aiMatrix3x3::Transpose() return *this; } +// ------------------------------------------------------------------------------------------------ +inline aiMatrix3x3& aiMatrix3x3::Rotation(float a, aiMatrix3x3& out) +{ + out.a1 = out.b2 = ::cos(a); + out.b1 = ::sin(a); + out.a2 = - out.b1; + + out.a3 = out.b3 = out.c1 = out.c2 = 0.f; + out.c3 = 1.f; + + return out; +} + +// ------------------------------------------------------------------------------------------------ +inline aiMatrix3x3& aiMatrix3x3::Translation( const aiVector2D& v, aiMatrix3x3& out) +{ + out = aiMatrix3x3(); + out.a3 = v.x; + out.b3 = v.y; + return out; +} #endif // __cplusplus diff --git a/include/aiMesh.h b/include/aiMesh.h index 8ef7e5742..0b74778c9 100644 --- a/include/aiMesh.h +++ b/include/aiMesh.h @@ -504,6 +504,23 @@ struct aiMesh else return mTextureCoords[pIndex] != NULL && mNumVertices > 0; } + + //! Get the number of UV channels the mesh contains + inline unsigned int GetNumUVChannels() const + { + unsigned int n = 0; + while (n < AI_MAX_NUMBER_OF_TEXTURECOORDS && mTextureCoords[n])++n; + return n; + } + + //! Get the number of vertex color channels the mesh contains + inline unsigned int GetNumColorChannels() const + { + unsigned int n = 0; + while (n < AI_MAX_NUMBER_OF_COLOR_SETS && mColors[n])++n; + return n; + } + //! Check whether the mesh contains bones inline bool HasBones() const { return mBones != NULL && mNumBones > 0; } diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index a9f6c810f..c579cccec 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -230,7 +230,6 @@ enum aiPostProcessSteps */ aiProcess_FindDegenerates = 0x10000, - /** This step searches all meshes for invalid data, such as zeroed * normal vectors or invalid UV coords and removes them. * @@ -240,6 +239,26 @@ enum aiPostProcessSteps * The step will also remove meshes that are infinitely small. */ aiProcess_FindInvalidData = 0x20000, + + /** This step converts non-UV mappings (such as spherical or + * cylindrical) to proper UV mapping channels. + * + * Most applications will support UV mapping only, so you will + * propably want to specify this step in every case. + */ + aiProcess_GenUVCoords = 0x40000, + + /** This step pretransforms UV coordinates by the UV transformations + * (such as scalings or rotations). + * + * UV transformations are specified per-texture - see the + * AI_MATKEY_UVTRANSFORM key for more information on this topic. + * This step finds all textures with transformed input UV + * coordinates and generates a new, transformed, UV channel for it. + * Most applications won't support UV transformations, so you will + * propably want to specify this step in every case. + */ + aiProcess_TransformUVCoords = 0x80000, }; @@ -254,7 +273,8 @@ enum aiPostProcessSteps aiProcess_CalcTangentSpace | \ aiProcess_GenNormals | \ aiProcess_JoinIdenticalVertices | \ - aiProcess_Triangulate + aiProcess_Triangulate | \ + aiProcess_GenUVCoords /** @def AI_POSTPROCESS_DEFAULT_REALTIME @@ -274,7 +294,8 @@ enum aiPostProcessSteps aiProcess_RemoveRedundantMaterials | \ aiProcess_SplitLargeMeshes | \ aiProcess_OptimizeGraph | \ - aiProcess_Triangulate + aiProcess_Triangulate | \ + aiProcess_GenUVCoords #ifdef __cplusplus diff --git a/include/aiTypes.h b/include/aiTypes.h index 7fdd73868..2bd80cff9 100644 --- a/include/aiTypes.h +++ b/include/aiTypes.h @@ -47,13 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "aiDefines.h" -// include math helper classes and their implementations +// include math helper classes #include "aiVector3D.h" #include "aiMatrix3x3.h" #include "aiMatrix4x4.h" -#include "aiVector3D.inl" -#include "aiMatrix3x3.inl" -#include "aiMatrix4x4.inl" #ifdef __cplusplus # include @@ -72,7 +69,6 @@ const size_t MAXLEN = 1024; // --------------------------------------------------------------------------- /** Represents a two-dimensional vector. */ -// --------------------------------------------------------------------------- struct aiVector2D { #ifdef __cplusplus @@ -86,6 +82,25 @@ struct aiVector2D float x, y; } PACK_STRUCT; + +// --------------------------------------------------------------------------- +/** Represents a plane in a three-dimensional, euclidean space +*/ +struct aiPlane +{ +#ifdef __cplusplus + aiPlane () : a(0.f), b(0.f), c(0.f), d(0.f) {} + aiPlane (float _a, float _b, float _c, float _d) + : a(_a), b(_b), c(_c), d(_d) {} + + aiPlane (const aiPlane& o) : a(o.a), b(o.b), c(o.c), d(o.d) {} + +#endif // !__cplusplus + + //! Plane equation + float a,b,c,d; +} PACK_STRUCT; + // aiVector3D type moved to separate header due to size of operators // aiQuaternion type moved to separate header due to size of operators // aiMatrix4x4 type moved to separate header due to size of operators @@ -93,7 +108,6 @@ struct aiVector2D // --------------------------------------------------------------------------- /** Represents a color in Red-Green-Blue space. */ -// --------------------------------------------------------------------------- struct aiColor3D { #ifdef __cplusplus @@ -136,7 +150,6 @@ struct aiColor3D /** Represents a color in Red-Green-Blue space including an * alpha component. */ -// --------------------------------------------------------------------------- struct aiColor4D { #ifdef __cplusplus @@ -157,7 +170,7 @@ struct aiColor4D inline bool IsBlack() const { - // the alpha component doesn't care here. black is black. + // The alpha component doesn't care here. black is black. return !r && !g && !b; } @@ -173,7 +186,6 @@ struct aiColor4D // --------------------------------------------------------------------------- /** Represents a string, zero byte terminated */ -// --------------------------------------------------------------------------- struct aiString { #ifdef __cplusplus @@ -188,7 +200,7 @@ struct aiString length(rOther.length) { ::memcpy( data, rOther.data, rOther.length); - this->data[this->length] = '\0'; + data[length] = '\0'; } //! Constructor from std::string @@ -212,17 +224,36 @@ struct aiString //! comparison operator bool operator==(const aiString& other) const { - return (this->length == other.length && + return (length == other.length && 0 == strcmp(this->data,other.data)); } //! inverse comparison operator bool operator!=(const aiString& other) const { - return (this->length != other.length || + return (length != other.length || 0 != ::strcmp(this->data,other.data)); } + //! Append a string to the string + inline void Append (const char* app) + { + const size_t len = ::strlen(app); + if (!len)return; + + if (length + len >= MAXLEN) + return; + + ::memcpy(&data[length],app,len+1); + length += len; + } + + //! Clear the string + inline void Clear () + { + length = 0; + data[0] = '\0'; + } #endif // !__cplusplus @@ -240,18 +271,21 @@ struct aiString * To check whether or not a function failed check against * AI_SUCCESS. The error codes are mainly used by the C-API. */ -// --------------------------------------------------------------------------- enum aiReturn { //! Indicates that a function was successful AI_SUCCESS = 0x0, + //! Indicates that a function failed AI_FAILURE = -0x1, + //! Indicates that a file was invalid AI_INVALIDFILE = -0x2, + //! Indicates that not enough memory was available //! to perform the requested operation AI_OUTOFMEMORY = -0x3, + //! Indicates that an illegal argument has been //! passed to a function. This is rarely used, //! most functions assert in this case. @@ -264,7 +298,6 @@ enum aiReturn * animations) of an import. * @see Importer::GetMemoryRequirements() */ -// --------------------------------------------------------------------------- struct aiMemoryInfo { #ifdef __cplusplus @@ -276,6 +309,8 @@ struct aiMemoryInfo , meshes (0) , nodes (0) , animations (0) + , cameras (0) + , lights (0) , total (0) {} @@ -283,14 +318,25 @@ struct aiMemoryInfo //! Storage allocated for texture data, in bytes unsigned int textures; + //! Storage allocated for material data, in bytes unsigned int materials; + //! Storage allocated for mesh data, in bytes unsigned int meshes; + //! Storage allocated for node data, in bytes unsigned int nodes; + //! Storage allocated for animation data, in bytes unsigned int animations; + + //! Storage allocated for camera data, in bytes + unsigned int cameras; + + //! Storage allocated for light data, in bytes + unsigned int lights; + //! Storage allocated for the import, in bytes unsigned int total; }; @@ -299,5 +345,12 @@ struct aiMemoryInfo #ifdef __cplusplus } #endif //! __cplusplus + +// Include implementations +#include "aiVector3D.inl" +#include "aiMatrix3x3.inl" +#include "aiMatrix4x4.inl" + + #endif //!! include guard diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index eeea4ba9c..2860c62eb 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -244,7 +244,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[i]; switch (this->m_pcCurrentTexture->iType) { - case AI_TEXTYPE_DIFFUSE: + case aiTextureType_DIFFUSE: if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture != piTexture) { pcMesh->piDiffuseTexture->Release(); @@ -257,7 +257,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - case AI_TEXTYPE_AMBIENT: + case aiTextureType_AMBIENT: if (pcMesh->piAmbientTexture && pcMesh->piAmbientTexture != piTexture) { pcMesh->piAmbientTexture->Release(); @@ -270,7 +270,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - case AI_TEXTYPE_SPECULAR: + case aiTextureType_SPECULAR: if (pcMesh->piSpecularTexture && pcMesh->piSpecularTexture != piTexture) { pcMesh->piSpecularTexture->Release(); @@ -283,7 +283,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - case AI_TEXTYPE_EMISSIVE: + case aiTextureType_EMISSIVE: if (pcMesh->piEmissiveTexture && pcMesh->piEmissiveTexture != piTexture) { pcMesh->piEmissiveTexture->Release(); @@ -296,7 +296,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - case AI_TEXTYPE_SHININESS: + case aiTextureType_SHININESS: if (pcMesh->piShininessTexture && pcMesh->piShininessTexture != piTexture) { pcMesh->piShininessTexture->Release(); @@ -309,8 +309,8 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - case AI_TEXTYPE_NORMALS: - case AI_TEXTYPE_HEIGHT: + case aiTextureType_NORMALS: + case aiTextureType_HEIGHT: if (pcMesh->piNormalTexture && pcMesh->piNormalTexture != piTexture) { pcMesh->piNormalTexture->Release(); @@ -325,7 +325,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) } } break; - default: //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000: + default: //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000: if (pcMesh->piOpacityTexture && pcMesh->piOpacityTexture != piTexture) { pcMesh->piOpacityTexture->Release(); @@ -340,42 +340,44 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) break; }; } - // now update the material itself aiString szOld; const char* szKey = NULL; +#if 0 switch (this->m_pcCurrentTexture->iType) { - case AI_TEXTYPE_DIFFUSE: + case aiTextureType_DIFFUSE: szKey = AI_MATKEY_TEXTURE_DIFFUSE(0); break; - case AI_TEXTYPE_AMBIENT: + case aiTextureType_AMBIENT: szKey = AI_MATKEY_TEXTURE_AMBIENT(0); break; - case AI_TEXTYPE_SPECULAR: + case aiTextureType_SPECULAR: szKey = AI_MATKEY_TEXTURE_SPECULAR(0); break; - case AI_TEXTYPE_EMISSIVE: + case aiTextureType_EMISSIVE: szKey = AI_MATKEY_TEXTURE_EMISSIVE(0); break; - case AI_TEXTYPE_NORMALS: + case aiTextureType_NORMALS: szKey = AI_MATKEY_TEXTURE_NORMALS(0); break; - case AI_TEXTYPE_HEIGHT: + case aiTextureType_HEIGHT: szKey = AI_MATKEY_TEXTURE_HEIGHT(0); break; - case AI_TEXTYPE_SHININESS: + case aiTextureType_SHININESS: szKey = AI_MATKEY_TEXTURE_SHININESS(0); break; - default: //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000: + default: //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000: szKey = AI_MATKEY_TEXTURE_OPACITY(0); break; }; +#endif ai_assert(NULL != szKey); - aiGetMaterialString(pcMat,szKey,&szOld); - pcMat->AddProperty(&szString,szKey); + aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE(m_pcCurrentTexture->iType,0),&szOld); + pcMat->AddProperty(&szString,AI_MATKEY_TEXTURE(m_pcCurrentTexture->iType,0)); +#if 0 char szBuffer[512]; sprintf(szBuffer,"%s%s",szKey,"_old"); @@ -388,6 +390,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath) { pcMat->RemoveProperty(szBuffer); } +#endif return 1; } //------------------------------------------------------------------------------- @@ -426,31 +429,31 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType, IDirect3DTexture9** piTexture; switch (iType) { - case AI_TEXTYPE_DIFFUSE: + case aiTextureType_DIFFUSE: piTexture = &g_pcAsset->apcMeshes[iMesh]->piDiffuseTexture; szType = "Diffuse"; break; - case AI_TEXTYPE_SPECULAR: + case aiTextureType_SPECULAR: piTexture = &g_pcAsset->apcMeshes[iMesh]->piSpecularTexture; szType = "Specular"; break; - case AI_TEXTYPE_AMBIENT: + case aiTextureType_AMBIENT: piTexture = &g_pcAsset->apcMeshes[iMesh]->piAmbientTexture; szType = "Ambient"; break; - case AI_TEXTYPE_EMISSIVE: + case aiTextureType_EMISSIVE: piTexture = &g_pcAsset->apcMeshes[iMesh]->piEmissiveTexture; szType = "Emissive"; break; - case AI_TEXTYPE_HEIGHT: + case aiTextureType_HEIGHT: piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture; szType = "HeightMap"; break; - case AI_TEXTYPE_NORMALS: + case aiTextureType_NORMALS: piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture; szType = "NormalMap"; break; - case AI_TEXTYPE_SHININESS: + case aiTextureType_SHININESS: piTexture = &g_pcAsset->apcMeshes[iMesh]->piShininessTexture; szType = "Shininess"; break; @@ -578,8 +581,8 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, (LPARAM)(LPTVINSERTSTRUCT)&sNew); // for each texture in the list ... add it - // NOTE: This expects that AI_TEXTYPE_DIFFUSE is 7 - ai_assert(7 == AI_TEXTYPE_DIFFUSE); + // NOTE: This expects that aiTextureType_DIFFUSE is 7 + ai_assert(7 == aiTextureType_DIFFUSE); unsigned int iUV; float fBlend; aiTextureOp eOp; @@ -590,12 +593,12 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, unsigned int iNum = 0; while (true) { - if (AI_SUCCESS != aiGetMaterialTexture(pcMat,iNum,i, - &szPath,&iUV,&fBlend,&eOp)) + if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum, + &szPath,NULL, &iUV,&fBlend,&eOp)) { break; } - if (AI_TEXTYPE_OPACITY == i)bNoOpacity = false; + if (aiTextureType_OPACITY == i)bNoOpacity = false; AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh); ++iNum; } @@ -619,7 +622,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, { // seems the diffuse texture contains alpha, therefore it has been // added to the opacity channel, too. Add a special value ... - AddTextureToDisplayList(AI_TEXTYPE_OPACITY | 0x40000000, + AddTextureToDisplayList(aiTextureType_OPACITY | 0x40000000, 0,&szPath,hTexture,iUV,fBlend,eOp,iMesh); } } @@ -967,7 +970,7 @@ int CDisplay::OnSetupTextureView(TextureInfo* pcNew) ShowNormalUIComponents(); } - if ((AI_TEXTYPE_OPACITY | 0x40000000) == pcNew->iType) + if ((aiTextureType_OPACITY | 0x40000000) == pcNew->iType) { // for opacity textures display a warn message CLogDisplay::Instance().AddEntry("[INFO] This texture is not existing in the " @@ -1204,7 +1207,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam) g_pcAsset->apcMeshes[i],"DIFFUSE_COLOR")); } } - szMatKey = AI_MATKEY_COLOR_DIFFUSE; + szMatKey = "$clr.diffuse"; break; case ID_SOLONG_CLEARSPECULARCOLOR: for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) @@ -1215,7 +1218,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam) g_pcAsset->apcMeshes[i],"SPECULAR_COLOR")); } } - szMatKey = AI_MATKEY_COLOR_SPECULAR; + szMatKey = "$clr.specular"; break; case ID_SOLONG_CLEARAMBIENTCOLOR: for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) @@ -1226,7 +1229,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam) g_pcAsset->apcMeshes[i],"AMBIENT_COLOR")); } } - szMatKey = AI_MATKEY_COLOR_AMBIENT; + szMatKey = "$clr.ambient"; break; case ID_SOLONG_CLEAREMISSIVECOLOR: for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) @@ -1237,7 +1240,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam) g_pcAsset->apcMeshes[i],"EMISSIVE_COLOR")); } } - szMatKey = AI_MATKEY_COLOR_EMISSIVE; + szMatKey = "$clr.emissive"; break; default: @@ -1283,7 +1286,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam) // change the material key ... Assimp::MaterialHelper* pcMat = (Assimp::MaterialHelper*)g_pcAsset->pcScene->mMaterials[ this->m_pcCurrentMaterial->iIndex]; - pcMat->AddProperty(&clrOld,1,szMatKey); + pcMat->AddProperty(&clrOld,1,szMatKey,0,0); if (ID_SOLONG_CLEARSPECULARCOLOR == LOWORD(wParam) && aiShadingMode_Gouraud == apclrOut.front().pMesh->eShadingMode) @@ -1420,35 +1423,35 @@ int CDisplay::HandleTreeViewPopup2(WPARAM wParam,LPARAM lParam) switch (this->m_pcCurrentTexture->iType) { - case AI_TEXTYPE_DIFFUSE: + case aiTextureType_DIFFUSE: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_DIFFUSE(0)); break; - case AI_TEXTYPE_SPECULAR: + case aiTextureType_SPECULAR: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SPECULAR(0)); break; - case AI_TEXTYPE_AMBIENT: + case aiTextureType_AMBIENT: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_AMBIENT(0)); break; - case AI_TEXTYPE_EMISSIVE: + case aiTextureType_EMISSIVE: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_EMISSIVE(0)); break; - case AI_TEXTYPE_NORMALS: + case aiTextureType_NORMALS: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_NORMALS(0)); break; - case AI_TEXTYPE_HEIGHT: + case aiTextureType_HEIGHT: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_HEIGHT(0)); break; - case AI_TEXTYPE_SHININESS: + case aiTextureType_SHININESS: pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SHININESS(0)); break; - case (AI_TEXTYPE_OPACITY | 0x40000000): + case (aiTextureType_OPACITY | 0x40000000): // set a special property to indicate that no alpha channel is required {int iVal = 1; - pcMat->AddProperty(&iVal,1,"no_a_from_d");} + pcMat->AddProperty(&iVal,1,"no_a_from_d",0,0);} break; - default: //case AI_TEXTYPE_OPACITY + default: //case aiTextureType_OPACITY pcMat->RemoveProperty(AI_MATKEY_TEXTURE_OPACITY(0)); }; @@ -1505,41 +1508,42 @@ int CDisplay::HandleTreeViewPopup2(WPARAM wParam,LPARAM lParam) TreeView_Select(GetDlgItem(g_hDlg,IDC_TREE1),this->m_hRoot,TVGN_CARET); return 1; } - +#if 0 case ID_HEY_RESETTEXTURE: { aiString szOld; aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[this->m_pcCurrentTexture->iMatIndex]; switch (this->m_pcCurrentTexture->iType) { - case AI_TEXTYPE_DIFFUSE: + case aiTextureType_DIFFUSE: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0) "_old",&szOld); break; - case AI_TEXTYPE_SPECULAR: + case aiTextureType_SPECULAR: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0) "_old",&szOld); break; - case AI_TEXTYPE_AMBIENT: + case aiTextureType_AMBIENT: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0) "_old",&szOld); break; - case AI_TEXTYPE_EMISSIVE: + case aiTextureType_EMISSIVE: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0) "_old",&szOld); break; - case AI_TEXTYPE_NORMALS: + case aiTextureType_NORMALS: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0) "_old",&szOld); break; - case AI_TEXTYPE_HEIGHT: + case aiTextureType_HEIGHT: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0) "_old",&szOld); break; - case AI_TEXTYPE_SHININESS: + case aiTextureType_SHININESS: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0) "_old",&szOld); break; - default : //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000: + default : //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000: aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0) "_old",&szOld); break; }; if (0 != szOld.length)this->ReplaceCurrentTexture(szOld.data); return 1; } +#endif } return 0; } @@ -2195,11 +2199,11 @@ int CDisplay::RenderTextureView() // commit the texture to the shader g_piPassThroughEffect->SetTexture("TEXTURE_2D",*this->m_pcCurrentTexture->piTexture); - if (AI_TEXTYPE_OPACITY == this->m_pcCurrentTexture->iType) + if (aiTextureType_OPACITY == this->m_pcCurrentTexture->iType) { g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromR"); } - else if ((AI_TEXTYPE_OPACITY | 0x40000000) == this->m_pcCurrentTexture->iType) + else if ((aiTextureType_OPACITY | 0x40000000) == this->m_pcCurrentTexture->iType) { g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromA"); } @@ -2212,8 +2216,8 @@ int CDisplay::RenderTextureView() g_piPassThroughEffect->Begin(&dw,0); g_piPassThroughEffect->BeginPass(0); - if (AI_TEXTYPE_HEIGHT == this->m_pcCurrentTexture->iType || - AI_TEXTYPE_NORMALS == this->m_pcCurrentTexture->iType) + if (aiTextureType_HEIGHT == this->m_pcCurrentTexture->iType || + aiTextureType_NORMALS == this->m_pcCurrentTexture->iType) { // manually disable alpha blending g_piDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index 6025b473f..efb30a855 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -786,6 +786,9 @@ int CMaterialManager::CreateMaterial( aiString szPath; + aiTextureMapMode mapU(aiTextureMapMode_Wrap),mapV(aiTextureMapMode_Wrap); + + bool bib =false; if (pcSource->mTextureCoords[0]) { @@ -795,6 +798,9 @@ int CMaterialManager::CreateMaterial( if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath)) { LoadTexture(&pcMesh->piDiffuseTexture,&szPath); + + aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU); + aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV); } if (pcSource->mTextureCoords[1]) @@ -833,7 +839,7 @@ int CMaterialManager::CreateMaterial( // NOTE: This special value is set by the tree view if the user // manually removes the alpha texture from the view ... - if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",&iVal)) + if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",0,0,&iVal)) { pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture; pcMesh->piOpacityTexture->AddRef(); @@ -879,6 +885,7 @@ int CMaterialManager::CreateMaterial( { LoadTexture(&pcMesh->piNormalTexture,&szPath); } + else bib = true; bHM = true; } @@ -968,6 +975,28 @@ int CMaterialManager::CreateMaterial( sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE"; sMacro[iCurrent].Definition = "1"; ++iCurrent; + + if (mapU == aiTextureMapMode_Wrap) + sMacro[iCurrent].Name = "AV_WRAPU"; + else if (mapU == aiTextureMapMode_Mirror) + sMacro[iCurrent].Name = "AV_MIRRORU"; + else // if (mapU == aiTextureMapMode_Clamp) + sMacro[iCurrent].Name = "AV_CLAMPU"; + + sMacro[iCurrent].Definition = "1"; + ++iCurrent; + + + + if (mapV == aiTextureMapMode_Wrap) + sMacro[iCurrent].Name = "AV_WRAPV"; + else if (mapV == aiTextureMapMode_Mirror) + sMacro[iCurrent].Name = "AV_MIRRORV"; + else // if (mapV == aiTextureMapMode_Clamp) + sMacro[iCurrent].Name = "AV_CLAMPV"; + + sMacro[iCurrent].Definition = "1"; + ++iCurrent; } if (pcMesh->piDiffuseTexture2) { @@ -993,7 +1022,7 @@ int CMaterialManager::CreateMaterial( sMacro[iCurrent].Definition = "1"; ++iCurrent; } - if (pcMesh->piNormalTexture) + if (pcMesh->piNormalTexture && !bib) { sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE"; sMacro[iCurrent].Definition = "1"; diff --git a/tools/assimp_view/Shaders.cpp b/tools/assimp_view/Shaders.cpp index 553903033..2a61c0861 100644 --- a/tools/assimp_view/Shaders.cpp +++ b/tools/assimp_view/Shaders.cpp @@ -530,6 +530,24 @@ std::string g_szMaterialShader = std::string( "sampler DIFFUSE_SAMPLER\n" "{\n" "Texture = ;\n" + "#ifdef AV_WRAPU\n" + "AddressU = WRAP;\n" + "#endif\n" + "#ifdef AV_MIRRORU\n" + "AddressU = MIRROR;\n" + "#endif\n" + "#ifdef AV_CLAMPU\n" + "AddressU = CLAMP;\n" + "#endif\n" + "#ifdef AV_WRAPV\n" + "AddressV = WRAP;\n" + "#endif\n" + "#ifdef AV_MIRRORV\n" + "AddressV = MIRROR;\n" + "#endif\n" + "#ifdef AV_CLAMPV\n" + "AddressV = CLAMP;\n" + "#endif\n" "MinFilter=LINEAR;\n" "MagFilter=LINEAR;\n" "MipFilter=LINEAR;\n" diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index fed293702..69feddd26 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -140,7 +140,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter) aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType | - aiProcess_FindDegenerates | aiProcess_FindInvalidData); // validate the output data structure + aiProcess_FindDegenerates | aiProcess_FindInvalidData | + aiProcess_GenUVCoords | aiProcess_TransformUVCoords ); // validate the output data structure // get the end time of zje operation, calculate delta t double fEnd = (double)timeGetTime(); diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index 845a98353..ccf30c422 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -726,6 +726,10 @@ RelativePath="..\..\include\BoostWorkaround\boost\format.hpp" > + + @@ -903,14 +907,6 @@ RelativePath="..\..\code\TargetAnimation.h" > - - - - @@ -1344,6 +1340,14 @@ + + + + + + + @@ -1574,6 +1586,14 @@ RelativePath="..\..\code\SplitLargeMeshes.h" > + + + +