123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- /*
- ---------------------------------------------------------------------------
- Open Asset Import Library (assimp)
- ---------------------------------------------------------------------------
- Copyright (c) 2006-2022, assimp team
- All rights reserved.
- Redistribution and use of this software in source and binary forms,
- with or without modification, are permitted provided that the following
- conditions are met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
- * Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ---------------------------------------------------------------------------
- */
- /** @file XFileImporter.cpp
- * @brief Implementation of the XFile importer class
- */
- #ifndef ASSIMP_BUILD_NO_X_IMPORTER
- #include "AssetLib/X/XFileImporter.h"
- #include "AssetLib/X/XFileParser.h"
- #include "PostProcessing/ConvertToLHProcess.h"
- #include <assimp/TinyFormatter.h>
- #include <assimp/IOSystem.hpp>
- #include <assimp/scene.h>
- #include <assimp/DefaultLogger.hpp>
- #include <assimp/importerdesc.h>
- #include <cctype>
- #include <memory>
- namespace Assimp {
- using namespace Assimp::Formatter;
- static constexpr aiImporterDesc desc = {
- "Direct3D XFile Importer",
- "",
- "",
- "",
- aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
- 1,
- 3,
- 1,
- 5,
- "x"
- };
- // ------------------------------------------------------------------------------------------------
- // Returns whether the class can handle the format of the given file.
- bool XFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
- static const uint32_t token[] = { AI_MAKE_MAGIC("xof ") };
- return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token));
- }
- // ------------------------------------------------------------------------------------------------
- // Get file extension list
- const aiImporterDesc *XFileImporter::GetInfo() const {
- return &desc;
- }
- // ------------------------------------------------------------------------------------------------
- // Imports the given file into the given scene structure.
- void XFileImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
- // read file into memory
- std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
- if (file == nullptr) {
- throw DeadlyImportError("Failed to open file ", pFile, ".");
- }
- static const size_t MinSize = 16;
- size_t fileSize = file->FileSize();
- if (fileSize < MinSize) {
- throw DeadlyImportError("XFile is too small.");
- }
- // in the hope that binary files will never start with a BOM ...
- mBuffer.resize(fileSize + 1);
- file->Read(&mBuffer.front(), 1, fileSize);
- ConvertToUTF8(mBuffer);
- // parse the file into a temporary representation
- XFileParser parser(mBuffer);
- // and create the proper return structures out of it
- CreateDataRepresentationFromImport(pScene, parser.GetImportedData());
- // if nothing came from it, report it as error
- if (!pScene->mRootNode) {
- throw DeadlyImportError("XFile is ill-formatted - no content imported.");
- }
- }
- // ------------------------------------------------------------------------------------------------
- // Constructs the return data structure out of the imported data.
- void XFileImporter::CreateDataRepresentationFromImport(aiScene *pScene, XFile::Scene *pData) {
- // Read the global materials first so that meshes referring to them can find them later
- ConvertMaterials(pScene, pData->mGlobalMaterials);
- // copy nodes, extracting meshes and materials on the way
- pScene->mRootNode = CreateNodes(pScene, nullptr, pData->mRootNode);
- // extract animations
- CreateAnimations(pScene, pData);
- // read the global meshes that were stored outside of any node
- if (!pData->mGlobalMeshes.empty()) {
- // create a root node to hold them if there isn't any, yet
- if (pScene->mRootNode == nullptr) {
- pScene->mRootNode = new aiNode;
- pScene->mRootNode->mName.Set("$dummy_node");
- }
- // convert all global meshes and store them in the root node.
- // If there was one before, the global meshes now suddenly have its transformation matrix...
- // Don't know what to do there, I don't want to insert another node under the present root node
- // just to avoid this.
- CreateMeshes(pScene, pScene->mRootNode, pData->mGlobalMeshes);
- }
- if (!pScene->mRootNode) {
- throw DeadlyImportError("No root node");
- }
- // Convert everything to OpenGL space... it's the same operation as the conversion back, so we can reuse the step directly
- MakeLeftHandedProcess convertProcess;
- convertProcess.Execute(pScene);
- FlipWindingOrderProcess flipper;
- flipper.Execute(pScene);
- // finally: create a dummy material if not material was imported
- if (pScene->mNumMaterials == 0) {
- pScene->mNumMaterials = 1;
- // create the Material
- aiMaterial *mat = new aiMaterial;
- int shadeMode = (int)aiShadingMode_Gouraud;
- mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
- // material colours
- int specExp = 1;
- aiColor3D clr = aiColor3D(0, 0, 0);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_EMISSIVE);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
- clr = aiColor3D(0.5f, 0.5f, 0.5f);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
- mat->AddProperty(&specExp, 1, AI_MATKEY_SHININESS);
- pScene->mMaterials = new aiMaterial *[1];
- pScene->mMaterials[0] = mat;
- }
- }
- // ------------------------------------------------------------------------------------------------
- // Recursively creates scene nodes from the imported hierarchy.
- aiNode *XFileImporter::CreateNodes(aiScene *pScene, aiNode *pParent, const XFile::Node *pNode) {
- if (!pNode) {
- return nullptr;
- }
- // create node
- aiNode *node = new aiNode;
- node->mName.length = (ai_uint32)pNode->mName.length();
- node->mParent = pParent;
- memcpy(node->mName.data, pNode->mName.c_str(), pNode->mName.length());
- node->mName.data[node->mName.length] = 0;
- node->mTransformation = pNode->mTrafoMatrix;
- // convert meshes from the source node
- CreateMeshes(pScene, node, pNode->mMeshes);
- // handle children
- if (!pNode->mChildren.empty()) {
- node->mNumChildren = (unsigned int)pNode->mChildren.size();
- node->mChildren = new aiNode *[node->mNumChildren];
- for (unsigned int a = 0; a < pNode->mChildren.size(); ++a) {
- node->mChildren[a] = CreateNodes(pScene, node, pNode->mChildren[a]);
- }
- }
- return node;
- }
- // ------------------------------------------------------------------------------------------------
- // Creates the meshes for the given node.
- void XFileImporter::CreateMeshes(aiScene *pScene, aiNode *pNode, const std::vector<XFile::Mesh *> &pMeshes) {
- if (pMeshes.empty()) {
- return;
- }
- // create a mesh for each mesh-material combination in the source node
- std::vector<aiMesh *> meshes;
- for (unsigned int a = 0; a < pMeshes.size(); ++a) {
- XFile::Mesh *sourceMesh = pMeshes[a];
- if (nullptr == sourceMesh) {
- continue;
- }
- // first convert its materials so that we can find them with their index afterwards
- ConvertMaterials(pScene, sourceMesh->mMaterials);
- unsigned int numMaterials = std::max((unsigned int)sourceMesh->mMaterials.size(), 1u);
- for (unsigned int b = 0; b < numMaterials; ++b) {
- // collect the faces belonging to this material
- std::vector<unsigned int> faces;
- unsigned int numVertices = 0;
- if (!sourceMesh->mFaceMaterials.empty()) {
- // if there is a per-face material defined, select the faces with the corresponding material
- for (unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c) {
- if (sourceMesh->mFaceMaterials[c] == b) {
- faces.push_back(c);
- numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
- }
- }
- } else {
- // if there is no per-face material, place everything into one mesh
- for (unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c) {
- faces.push_back(c);
- numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
- }
- }
- // no faces/vertices using this material? strange...
- if (numVertices == 0) {
- continue;
- }
- // create a submesh using this material
- aiMesh *mesh = new aiMesh;
- meshes.push_back(mesh);
- // find the material in the scene's material list. Either own material
- // or referenced material, it should already have a valid index
- if (!sourceMesh->mFaceMaterials.empty()) {
- mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
- } else {
- mesh->mMaterialIndex = 0;
- }
- // Create properly sized data arrays in the mesh. We store unique vertices per face,
- // as specified
- mesh->mNumVertices = numVertices;
- mesh->mVertices = new aiVector3D[numVertices];
- mesh->mNumFaces = (unsigned int)faces.size();
- mesh->mFaces = new aiFace[mesh->mNumFaces];
- // name
- mesh->mName.Set(sourceMesh->mName);
- // normals?
- if (sourceMesh->mNormals.size() > 0) {
- mesh->mNormals = new aiVector3D[numVertices];
- }
- // texture coords
- for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
- if (!sourceMesh->mTexCoords[c].empty()) {
- mesh->mTextureCoords[c] = new aiVector3D[numVertices];
- }
- }
- // vertex colors
- for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
- if (!sourceMesh->mColors[c].empty()) {
- mesh->mColors[c] = new aiColor4D[numVertices];
- }
- }
- // now collect the vertex data of all data streams present in the imported mesh
- unsigned int newIndex(0);
- std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
- orgPoints.resize(numVertices, 0);
- for (unsigned int c = 0; c < faces.size(); ++c) {
- unsigned int f = faces[c]; // index of the source face
- const XFile::Face &pf = sourceMesh->mPosFaces[f]; // position source face
- // create face. either triangle or triangle fan depending on the index count
- aiFace &df = mesh->mFaces[c]; // destination face
- df.mNumIndices = (unsigned int)pf.mIndices.size();
- df.mIndices = new unsigned int[df.mNumIndices];
- // collect vertex data for indices of this face
- for (unsigned int d = 0; d < df.mNumIndices; ++d) {
- df.mIndices[d] = newIndex;
- const unsigned int newIdx = pf.mIndices[d];
- if (newIdx >= sourceMesh->mPositions.size()) {
- continue;
- }
- orgPoints[newIndex] = pf.mIndices[d];
- // Position
- mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
- // Normal, if present
- if (mesh->HasNormals()) {
- if (sourceMesh->mNormFaces[f].mIndices.size() > d) {
- const size_t idx(sourceMesh->mNormFaces[f].mIndices[d]);
- if (idx < sourceMesh->mNormals.size()) {
- mesh->mNormals[newIndex] = sourceMesh->mNormals[idx];
- }
- }
- }
- // texture coord sets
- for (unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e) {
- if (mesh->HasTextureCoords(e)) {
- aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
- mesh->mTextureCoords[e][newIndex] = aiVector3D(tex.x, 1.0f - tex.y, 0.0f);
- }
- }
- // vertex color sets
- for (unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e) {
- if (mesh->HasVertexColors(e)) {
- mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
- }
- }
- newIndex++;
- }
- }
- // there should be as much new vertices as we calculated before
- ai_assert(newIndex == numVertices);
- // convert all bones of the source mesh which influence vertices in this newly created mesh
- const std::vector<XFile::Bone> &bones = sourceMesh->mBones;
- std::vector<aiBone *> newBones;
- for (unsigned int c = 0; c < bones.size(); ++c) {
- const XFile::Bone &obone = bones[c];
- // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
- std::vector<ai_real> oldWeights(sourceMesh->mPositions.size(), 0.0);
- for (unsigned int d = 0; d < obone.mWeights.size(); ++d) {
- const unsigned int boneIdx = obone.mWeights[d].mVertex;
- if (boneIdx < obone.mWeights.size()) {
- oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight;
- }
- }
- // collect all vertex weights that influence a vertex in the new mesh
- std::vector<aiVertexWeight> newWeights;
- newWeights.reserve(numVertices);
- for (unsigned int d = 0; d < orgPoints.size(); ++d) {
- // does the new vertex stem from an old vertex which was influenced by this bone?
- ai_real w = oldWeights[orgPoints[d]];
- if (w > 0.0) {
- newWeights.emplace_back(d, w);
- }
- }
- // if the bone has no weights in the newly created mesh, ignore it
- if (newWeights.empty()) {
- continue;
- }
- // create
- aiBone *nbone = new aiBone;
- newBones.push_back(nbone);
- // copy name and matrix
- nbone->mName.Set(obone.mName);
- nbone->mOffsetMatrix = obone.mOffsetMatrix;
- nbone->mNumWeights = (unsigned int)newWeights.size();
- nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
- for (unsigned int d = 0; d < newWeights.size(); ++d) {
- nbone->mWeights[d] = newWeights[d];
- }
- }
- // store the bones in the mesh
- mesh->mNumBones = (unsigned int)newBones.size();
- if (!newBones.empty()) {
- mesh->mBones = new aiBone *[mesh->mNumBones];
- std::copy(newBones.begin(), newBones.end(), mesh->mBones);
- }
- }
- }
- // reallocate scene mesh array to be large enough
- aiMesh **prevArray = pScene->mMeshes;
- pScene->mMeshes = new aiMesh *[pScene->mNumMeshes + meshes.size()];
- if (prevArray) {
- memcpy(pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof(aiMesh *));
- delete[] prevArray;
- }
- // allocate mesh index array in the node
- pNode->mNumMeshes = (unsigned int)meshes.size();
- pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
- // store all meshes in the mesh library of the scene and store their indices in the node
- for (unsigned int a = 0; a < meshes.size(); a++) {
- pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
- pNode->mMeshes[a] = pScene->mNumMeshes;
- pScene->mNumMeshes++;
- }
- }
- // ------------------------------------------------------------------------------------------------
- // Converts the animations from the given imported data and creates them in the scene.
- void XFileImporter::CreateAnimations(aiScene *pScene, const XFile::Scene *pData) {
- std::vector<aiAnimation *> newAnims;
- for (unsigned int a = 0; a < pData->mAnims.size(); ++a) {
- const XFile::Animation *anim = pData->mAnims[a];
- // some exporters mock me with empty animation tags.
- if (anim->mAnims.empty()) {
- continue;
- }
- // create a new animation to hold the data
- aiAnimation *nanim = new aiAnimation;
- newAnims.push_back(nanim);
- nanim->mName.Set(anim->mName);
- // duration will be determined by the maximum length
- nanim->mDuration = 0;
- nanim->mTicksPerSecond = pData->mAnimTicksPerSecond;
- nanim->mNumChannels = (unsigned int)anim->mAnims.size();
- nanim->mChannels = new aiNodeAnim *[nanim->mNumChannels];
- for (unsigned int b = 0; b < anim->mAnims.size(); ++b) {
- const XFile::AnimBone *bone = anim->mAnims[b];
- aiNodeAnim *nbone = new aiNodeAnim;
- nbone->mNodeName.Set(bone->mBoneName);
- nanim->mChannels[b] = nbone;
- // key-frames are given as combined transformation matrix keys
- if (!bone->mTrafoKeys.empty()) {
- nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
- nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
- nbone->mNumRotationKeys = (unsigned int)bone->mTrafoKeys.size();
- nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
- nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
- nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
- for (unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
- // deconstruct each matrix into separate position, rotation and scaling
- double time = bone->mTrafoKeys[c].mTime;
- aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
- // extract position
- aiVector3D pos(trafo.a4, trafo.b4, trafo.c4);
- nbone->mPositionKeys[c].mTime = time;
- nbone->mPositionKeys[c].mValue = pos;
- // extract scaling
- aiVector3D scale;
- scale.x = aiVector3D(trafo.a1, trafo.b1, trafo.c1).Length();
- scale.y = aiVector3D(trafo.a2, trafo.b2, trafo.c2).Length();
- scale.z = aiVector3D(trafo.a3, trafo.b3, trafo.c3).Length();
- nbone->mScalingKeys[c].mTime = time;
- nbone->mScalingKeys[c].mValue = scale;
- // reconstruct rotation matrix without scaling
- aiMatrix3x3 rotmat(
- trafo.a1 / scale.x, trafo.a2 / scale.y, trafo.a3 / scale.z,
- trafo.b1 / scale.x, trafo.b2 / scale.y, trafo.b3 / scale.z,
- trafo.c1 / scale.x, trafo.c2 / scale.y, trafo.c3 / scale.z);
- // and convert it into a quaternion
- nbone->mRotationKeys[c].mTime = time;
- nbone->mRotationKeys[c].mValue = aiQuaternion(rotmat);
- }
- // longest lasting key sequence determines duration
- nanim->mDuration = std::max(nanim->mDuration, bone->mTrafoKeys.back().mTime);
- } else {
- // separate key sequences for position, rotation, scaling
- nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
- if (nbone->mNumPositionKeys != 0) {
- nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
- for (unsigned int c = 0; c < nbone->mNumPositionKeys; ++c) {
- aiVector3D pos = bone->mPosKeys[c].mValue;
- nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
- nbone->mPositionKeys[c].mValue = pos;
- }
- }
- // rotation
- nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
- if (nbone->mNumRotationKeys != 0) {
- nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
- for (unsigned int c = 0; c < nbone->mNumRotationKeys; ++c) {
- aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
- nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
- nbone->mRotationKeys[c].mValue = aiQuaternion(rotmat);
- nbone->mRotationKeys[c].mValue.w *= -1.0f; // needs quat inversion
- }
- }
- // scaling
- nbone->mNumScalingKeys = (unsigned int)bone->mScaleKeys.size();
- if (nbone->mNumScalingKeys != 0) {
- nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
- for (unsigned int c = 0; c < nbone->mNumScalingKeys; c++)
- nbone->mScalingKeys[c] = bone->mScaleKeys[c];
- }
- // longest lasting key sequence determines duration
- if (bone->mPosKeys.size() > 0)
- nanim->mDuration = std::max(nanim->mDuration, bone->mPosKeys.back().mTime);
- if (bone->mRotKeys.size() > 0)
- nanim->mDuration = std::max(nanim->mDuration, bone->mRotKeys.back().mTime);
- if (bone->mScaleKeys.size() > 0)
- nanim->mDuration = std::max(nanim->mDuration, bone->mScaleKeys.back().mTime);
- }
- }
- }
- // store all converted animations in the scene
- if (newAnims.size() > 0) {
- pScene->mNumAnimations = (unsigned int)newAnims.size();
- pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations];
- for (unsigned int a = 0; a < newAnims.size(); a++)
- pScene->mAnimations[a] = newAnims[a];
- }
- }
- // ------------------------------------------------------------------------------------------------
- // Converts all materials in the given array and stores them in the scene's material list.
- void XFileImporter::ConvertMaterials(aiScene *pScene, std::vector<XFile::Material> &pMaterials) {
- // count the non-referrer materials in the array
- unsigned int numNewMaterials(0);
- for (unsigned int a = 0; a < pMaterials.size(); ++a) {
- if (!pMaterials[a].mIsReference) {
- ++numNewMaterials;
- }
- }
- // resize the scene's material list to offer enough space for the new materials
- if (numNewMaterials > 0) {
- aiMaterial **prevMats = pScene->mMaterials;
- pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials + numNewMaterials];
- if (nullptr != prevMats) {
- ::memcpy(pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof(aiMaterial *));
- delete[] prevMats;
- }
- }
- // convert all the materials given in the array
- for (unsigned int a = 0; a < pMaterials.size(); ++a) {
- XFile::Material &oldMat = pMaterials[a];
- if (oldMat.mIsReference) {
- // find the material it refers to by name, and store its index
- for (size_t b = 0; b < pScene->mNumMaterials; ++b) {
- aiString name;
- pScene->mMaterials[b]->Get(AI_MATKEY_NAME, name);
- if (strcmp(name.C_Str(), oldMat.mName.data()) == 0) {
- oldMat.sceneIndex = b;
- break;
- }
- }
- if (oldMat.sceneIndex == SIZE_MAX) {
- ASSIMP_LOG_WARN("Could not resolve global material reference \"", oldMat.mName, "\"");
- oldMat.sceneIndex = 0;
- }
- continue;
- }
- aiMaterial *mat = new aiMaterial;
- aiString name;
- name.Set(oldMat.mName);
- mat->AddProperty(&name, AI_MATKEY_NAME);
- // Shading model: hard-coded to PHONG, there is no such information in an XFile
- // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
- // for some models in the SDK (e.g. good old tiny.x)
- int shadeMode = (int)oldMat.mSpecularExponent == 0.0f ? aiShadingMode_Gouraud : aiShadingMode_Phong;
- mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
- // material colours
- // Unclear: there's no ambient colour, but emissive. What to put for ambient?
- // Probably nothing at all, let the user select a suitable default.
- mat->AddProperty(&oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
- mat->AddProperty(&oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
- mat->AddProperty(&oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
- mat->AddProperty(&oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
- // texture, if there is one
- if (1 == oldMat.mTextures.size()) {
- const XFile::TexEntry &otex = oldMat.mTextures.back();
- if (otex.mName.length()) {
- // if there is only one texture assume it contains the diffuse color
- aiString tex(otex.mName);
- if (otex.mIsNormalMap) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(0));
- } else {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
- }
- }
- } else {
- // Otherwise ... try to search for typical strings in the
- // texture's file name like 'bump' or 'diffuse'
- unsigned int iHM = 0, iNM = 0, iDM = 0, iSM = 0, iAM = 0, iEM = 0;
- for (unsigned int b = 0; b < oldMat.mTextures.size(); ++b) {
- const XFile::TexEntry &otex = oldMat.mTextures[b];
- std::string sz = otex.mName;
- if (!sz.length()) {
- continue;
- }
- // find the file name
- std::string::size_type s = sz.find_last_of("\\/");
- if (std::string::npos == s) {
- s = 0;
- }
- // cut off the file extension
- std::string::size_type sExt = sz.find_last_of('.');
- if (std::string::npos != sExt) {
- sz[sExt] = '\0';
- }
- // convert to lower case for easier comparison
- for (unsigned int c = 0; c < sz.length(); ++c) {
- sz[c] = (char)tolower((unsigned char)sz[c]);
- }
- // Place texture filename property under the corresponding name
- aiString tex(oldMat.mTextures[b].mName);
- // bump map
- if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
- } else if (otex.mIsNormalMap || std::string::npos != sz.find("normal", s) || std::string::npos != sz.find("nm", s)) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
- } else if (std::string::npos != sz.find("spec", s) || std::string::npos != sz.find("glanz", s)) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
- } else if (std::string::npos != sz.find("ambi", s) || std::string::npos != sz.find("env", s)) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
- } else if (std::string::npos != sz.find("emissive", s) || std::string::npos != sz.find("self", s)) {
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
- } else {
- // Assume it is a diffuse texture
- mat->AddProperty(&tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
- }
- }
- }
- pScene->mMaterials[pScene->mNumMaterials] = mat;
- oldMat.sceneIndex = pScene->mNumMaterials;
- pScene->mNumMaterials++;
- }
- }
- } // namespace Assimp
- #endif // !! ASSIMP_BUILD_NO_X_IMPORTER
|