From fb1ddb90703ed683a14b4eb2513fe15edabc7265 Mon Sep 17 00:00:00 2001 From: diiigle Date: Tue, 31 Dec 2013 19:27:47 +0100 Subject: [PATCH] Add loading of recursive referenced files --- code/LDrawImporter.cpp | 185 ++++++++++++++++++++++++++++++++-------- code/LDrawImporter.h | 10 ++- include/assimp/config.h | 11 +++ 3 files changed, 169 insertions(+), 37 deletions(-) diff --git a/code/LDrawImporter.cpp b/code/LDrawImporter.cpp index 1e82a99fc..38ed53202 100644 --- a/code/LDrawImporter.cpp +++ b/code/LDrawImporter.cpp @@ -44,10 +44,16 @@ bool LDrawImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, return false; } // ------------------------------------------------------------------------------- -const aiImporterDesc* LDrawImporter::GetInfo() const { +const aiImporterDesc* LDrawImporter::GetInfo() const +{ return &desc; } // ------------------------------------------------------------------------------- +void LDrawImporter::SetupProperties(const Importer* pImp) +{ + _libPath = pImp->GetPropertyString(AI_CONFIG_IMPORT_LDRAW_LIB_PATH, ""); +} +// ------------------------------------------------------------------------------- void LDrawImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { @@ -65,9 +71,26 @@ void LDrawImporter::InternReadFile(const std::string& pFile, const char * buffer = &vecBuffer[0]; + char DS = pIOHandler->getOsSeparator(); + //ensure _libPath points to a valid path + if (_libPath == ""){ + //use the models folder as root + _libPath = GetFolderPath(pFile, DS); + } + else if (_libPath.find_last_of(DS) != (_libPath.size() - 1)) + { + _libPath += DS; + } + + //setup a batch loader, it's quite probable we will need it + BatchLoader loader(pIOHandler); + BatchLoader::PropertyMap loaderParams = BatchLoader::PropertyMap(); + SetGenericProperty(loaderParams.strings, AI_CONFIG_IMPORT_LDRAW_LIB_PATH, _libPath); + //TODO estimate sizes - std::vector * vertices = new std::vector(); - std::vector * faces = new std::vector(); + std::vector vertices = std::vector(); + std::vector faces = std::vector(); + std::vector> fileIds = std::vector>(); unsigned int primitivesType = 0; @@ -86,25 +109,74 @@ void LDrawImporter::InternReadFile(const std::string& pFile, int command = ::atoi(lp); ++lp; if (command == 0){ - //its a comment + //it's a comment continue; } else if (command == 1){ - //its a sub file reference, load it + //it's a sub file reference, load it + float * params = NULL; + //read a colour constant and 12 floats of a 4x4 matrix + if (!ReadNumFloats(lp, params, 13)){ + ThrowException(Formatter::format("could not read ") << 13 << " command parameter floats from the line '" << line << "'"); + } + aiMatrix4x4 *mat = new aiMatrix4x4( + params[4], params[5], params[6], params[1], + params[7], params[8], params[9], params[2], + params[10], params[11], params[12], params[3], + 0.0f, 0.0f, 0.0f, 1.0f + ); + //we read 13 tokens from lp, so we can safely skip them + for (unsigned int i = 0; i < 13; ++i){ + SkipToken(lp); + } + std::string subpath = GetNextToken(lp); + if (subpath == ""){ + ThrowException("sub-file reference with empty path/filename"); + } + + //find the full path of the part + std::string fullpath; + if (pIOHandler->Exists(subpath)){ + //we are lucky, file is full path referenced + fullpath = subpath; + } + else + { + //test the specified directories of the LDraw Library + static std::vector paths{ "parts", "p", "models" }; + for (unsigned int i = 0; i < paths.size(); ++i){ + if (pIOHandler->Exists(_libPath + paths[i] + DS + subpath)){ + fullpath = _libPath + paths[i] + DS + subpath; + break; + } + else if (pIOHandler->Exists(_libPath + ".." + DS+ paths[i] + DS + subpath)) + { + fullpath = _libPath + ".." + DS + paths[i] + DS + subpath; + break; + } + } + } + if (fullpath == ""){ + //we can't find it + ThrowException("Unable to find file '" + subpath + "'"); + } + unsigned int id = loader.AddLoadRequest(fullpath, 0, &loaderParams); + fileIds.push_back(std::pair(id, mat)); + continue; } else if (command == 2 || command == 3 || command == 4){ - //its a line or a triangle or a quad + //it's a line or a triangle or a quad float * params = NULL; //read a colour constant and 2 (line) or 3 (triangle) or 4 (quad) vertices if (!ReadNumFloats(lp, params, 1 + (command * 3))){ ThrowException(Formatter::format("could not read ") << (1 + (command * 3)) <<" command parameter floats from the line '" << line<<"'"); } - unsigned int index = vertices->size(); + unsigned int index = vertices.size(); //TODO colour @params[0] - vertices->push_back(aiVector3D(params[1], params[2], params[3])); - vertices->push_back(aiVector3D(params[4], params[5], params[6])); + vertices.push_back(aiVector3D(params[1], params[2], params[3])); + vertices.push_back(aiVector3D(params[4], params[5], params[6])); aiFace f = aiFace(); f.mNumIndices = command; @@ -113,31 +185,31 @@ void LDrawImporter::InternReadFile(const std::string& pFile, f.mIndices[1] = index + 1; if (command == 3 || command == 4){ - vertices->push_back(aiVector3D(params[7], params[8], params[9])); + vertices.push_back(aiVector3D(params[7], params[8], params[9])); f.mIndices[2] = index + 2; if (command == 3){ - //its a triangle + //it's a triangle primitivesType = primitivesType | aiPrimitiveType_TRIANGLE; } else if (command == 4){ - //its a quad - vertices->push_back(aiVector3D(params[10], params[11], params[12])); + //it's a quad + vertices.push_back(aiVector3D(params[10], params[11], params[12])); f.mIndices[3] = index + 3; primitivesType = primitivesType | aiPrimitiveType_POLYGON; } } else { - //its a line + //it's a line primitivesType = primitivesType | aiPrimitiveType_LINE; - } - faces->push_back(f); + faces.push_back(f); + continue; } else { - //its an optional 'line' or an unknown command, ignore them + //it's an optional 'line' or an unknown command, ignore them continue; } } @@ -147,32 +219,73 @@ void LDrawImporter::InternReadFile(const std::string& pFile, ThrowException("Line not starting with an Command Identifier"); } } + aiScene * master = new aiScene(); //we did read the whole file, now build the scenegraph - pScene->mRootNode = new aiNode(""); - pScene->mRootNode->mTransformation = aiMatrix4x4(); + master->mRootNode = new aiNode(pFile); + master->mRootNode->mTransformation = aiMatrix4x4(); - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - pScene->mFlags = AI_SCENE_FLAGS_INCOMPLETE; + if (vertices.size() && faces.size()) + { + master->mNumMeshes = 1; + master->mMeshes = new aiMesh*[master->mNumMeshes]; + //master->mFlags = AI_SCENE_FLAGS_INCOMPLETE; - aiMesh* mesh = new aiMesh(); - mesh->mNumFaces = faces->size(); - mesh->mFaces = new aiFace[mesh->mNumFaces]; - memcpy(mesh->mFaces, faces->data(), sizeof(aiFace) * mesh->mNumFaces); - mesh->mNumVertices = vertices->size(); - mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - ::memcpy(mesh->mVertices, vertices->data(), sizeof(aiVector3D)* mesh->mNumVertices); - mesh->mPrimitiveTypes = primitivesType; - pScene->mMeshes[0] = mesh; + aiMesh* mesh = new aiMesh(); + mesh->mNumFaces = faces.size(); + mesh->mFaces = new aiFace[mesh->mNumFaces]; + std::copy(faces.begin(), faces.end(), mesh->mFaces); + mesh->mNumVertices = vertices.size(); + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + std::copy(vertices.begin(), vertices.end(), mesh->mVertices); + mesh->mPrimitiveTypes = primitivesType; + master->mMeshes[0] = mesh; - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[pScene->mRootNode->mNumMeshes]; - pScene->mRootNode->mMeshes[0] = 0; - + master->mRootNode->mNumMeshes = 1; + master->mRootNode->mMeshes = new unsigned int[master->mRootNode->mNumMeshes]; + master->mRootNode->mMeshes[0] = 0; + } + + if (fileIds.size() != 0){ + //we did queue some sub files, get them + loader.LoadAll(); + std::vector attatched(fileIds.size()); + for (unsigned int i = 0; i < fileIds.size(); ++i) + { + aiScene* sc = loader.GetImport(fileIds[i].first); + //check for duplicates with diffrent transformation matrix + int duplID = -1; + for (unsigned int j = 0; j < fileIds.size(); j++){ + if (j == i) continue; //don't check ourself for duplicates + if (fileIds[j].first == fileIds[i].first && *fileIds[j].second != *fileIds[i].second){ + //we found a scene with same id but diffrent transformation => true duplicate + duplID = j; + break; + } + } + aiScene * scene; + if (duplID != -1 && duplID < i){ + //duplicate was found and loaded scene was already used + SceneCombiner::CopyScene(&scene, sc); + } + else + { + scene = sc; + } + + scene->mRootNode->mTransformation = *fileIds[i].second; + attatched[i] = AttachmentInfo(scene, master->mRootNode); + } + SceneCombiner::MergeScenes(&pScene, master, attatched, AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY); + } + else + { + SceneCombiner::CopySceneFlat(&pScene, master); + } } -bool LDrawImporter::ReadNumFloats(const char* line, float* & out, unsigned int num){ +bool LDrawImporter::ReadNumFloats(const char* line, float* & out, unsigned int num) +{ out = new float[num]; for (unsigned int i = 0; i < num; ++i){ std::string token = GetNextToken(line); diff --git a/code/LDrawImporter.h b/code/LDrawImporter.h index 847d3d09f..846d0d413 100644 --- a/code/LDrawImporter.h +++ b/code/LDrawImporter.h @@ -8,6 +8,9 @@ #include "ParsingUtils.h" #include "fast_atof.h" #include "TinyFormatter.h" +#include "Importer.h" +#include "GenericProperty.h" +#include "SceneCombiner.h" namespace Assimp{ @@ -22,13 +25,16 @@ namespace Assimp{ bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; - protected: // ------------------------------------------------------------------- const aiImporterDesc* GetInfo() const; // ------------------------------------------------------------------- + void SetupProperties(const Importer* pImp); + + // ------------------------------------------------------------------- + protected: void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); @@ -46,6 +52,8 @@ namespace Assimp{ throw DeadlyImportError("LDraw: " + Message); } + std::string _libPath = ""; + }; //end of class LDrawImporter } // end of namespace Assimp diff --git a/include/assimp/config.h b/include/assimp/config.h index 8683cc385..d78d57c15 100644 --- a/include/assimp/config.h +++ b/include/assimp/config.h @@ -843,4 +843,15 @@ enum aiComponent #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION" +// --------------------------------------------------------------------------- +/** @brief LDraw Importer uses this Path to search for parts and subparts +* +* LDraw files mostly only refer to the official parts from the LDraw Official +* Parts Library. If the model is not located in the librarys root or 'model' +* folder, you can specify here the absolute path to the libs root folder +*
+* Property type: String. Default value: . +*/ +#define AI_CONFIG_IMPORT_LDRAW_LIB_PATH "IMPORT_LDRAW_LIB_PATH" + #endif // !! AI_CONFIG_H_INC