Add loading of recursive referenced files
parent
5cda765c0d
commit
fb1ddb9070
|
@ -44,10 +44,16 @@ bool LDrawImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
const aiImporterDesc* LDrawImporter::GetInfo() const {
|
const aiImporterDesc* LDrawImporter::GetInfo() const
|
||||||
|
{
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
void LDrawImporter::SetupProperties(const Importer* pImp)
|
||||||
|
{
|
||||||
|
_libPath = pImp->GetPropertyString(AI_CONFIG_IMPORT_LDRAW_LIB_PATH, "");
|
||||||
|
}
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
void LDrawImporter::InternReadFile(const std::string& pFile,
|
void LDrawImporter::InternReadFile(const std::string& pFile,
|
||||||
aiScene* pScene, IOSystem* pIOHandler)
|
aiScene* pScene, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
|
@ -65,9 +71,26 @@ void LDrawImporter::InternReadFile(const std::string& pFile,
|
||||||
|
|
||||||
const char * buffer = &vecBuffer[0];
|
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
|
//TODO estimate sizes
|
||||||
std::vector<aiVector3D> * vertices = new std::vector<aiVector3D>();
|
std::vector<aiVector3D> vertices = std::vector<aiVector3D>();
|
||||||
std::vector<aiFace> * faces = new std::vector<aiFace>();
|
std::vector<aiFace> faces = std::vector<aiFace>();
|
||||||
|
std::vector<std::pair<unsigned int, aiMatrix4x4*>> fileIds = std::vector<std::pair<unsigned int, aiMatrix4x4*>>();
|
||||||
|
|
||||||
unsigned int primitivesType = 0;
|
unsigned int primitivesType = 0;
|
||||||
|
|
||||||
|
@ -86,25 +109,74 @@ void LDrawImporter::InternReadFile(const std::string& pFile,
|
||||||
int command = ::atoi(lp);
|
int command = ::atoi(lp);
|
||||||
++lp;
|
++lp;
|
||||||
if (command == 0){
|
if (command == 0){
|
||||||
//its a comment
|
//it's a comment
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (command == 1){
|
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<std::string> 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<unsigned int, aiMatrix4x4*>(id, mat));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (command == 2 || command == 3 || command == 4){
|
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;
|
float * params = NULL;
|
||||||
//read a colour constant and 2 (line) or 3 (triangle) or 4 (quad) vertices
|
//read a colour constant and 2 (line) or 3 (triangle) or 4 (quad) vertices
|
||||||
if (!ReadNumFloats(lp, params, 1 + (command * 3))){
|
if (!ReadNumFloats(lp, params, 1 + (command * 3))){
|
||||||
ThrowException(Formatter::format("could not read ") << (1 + (command * 3)) <<" command parameter floats from the line '" << line<<"'");
|
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]
|
//TODO colour @params[0]
|
||||||
|
|
||||||
vertices->push_back(aiVector3D(params[1], params[2], params[3]));
|
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[4], params[5], params[6]));
|
||||||
|
|
||||||
aiFace f = aiFace();
|
aiFace f = aiFace();
|
||||||
f.mNumIndices = command;
|
f.mNumIndices = command;
|
||||||
|
@ -113,31 +185,31 @@ void LDrawImporter::InternReadFile(const std::string& pFile,
|
||||||
f.mIndices[1] = index + 1;
|
f.mIndices[1] = index + 1;
|
||||||
if (command == 3 || command == 4){
|
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;
|
f.mIndices[2] = index + 2;
|
||||||
|
|
||||||
if (command == 3){
|
if (command == 3){
|
||||||
//its a triangle
|
//it's a triangle
|
||||||
primitivesType = primitivesType | aiPrimitiveType_TRIANGLE;
|
primitivesType = primitivesType | aiPrimitiveType_TRIANGLE;
|
||||||
}
|
}
|
||||||
else if (command == 4){
|
else if (command == 4){
|
||||||
//its a quad
|
//it's a quad
|
||||||
vertices->push_back(aiVector3D(params[10], params[11], params[12]));
|
vertices.push_back(aiVector3D(params[10], params[11], params[12]));
|
||||||
f.mIndices[3] = index + 3;
|
f.mIndices[3] = index + 3;
|
||||||
primitivesType = primitivesType | aiPrimitiveType_POLYGON;
|
primitivesType = primitivesType | aiPrimitiveType_POLYGON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//its a line
|
//it's a line
|
||||||
primitivesType = primitivesType | aiPrimitiveType_LINE;
|
primitivesType = primitivesType | aiPrimitiveType_LINE;
|
||||||
|
|
||||||
}
|
}
|
||||||
faces->push_back(f);
|
faces.push_back(f);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//its an optional 'line' or an unknown command, ignore them
|
//it's an optional 'line' or an unknown command, ignore them
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,32 +219,73 @@ void LDrawImporter::InternReadFile(const std::string& pFile,
|
||||||
ThrowException("Line not starting with an Command Identifier");
|
ThrowException("Line not starting with an Command Identifier");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
aiScene * master = new aiScene();
|
||||||
|
|
||||||
//we did read the whole file, now build the scenegraph
|
//we did read the whole file, now build the scenegraph
|
||||||
pScene->mRootNode = new aiNode("<LDrawRoot>");
|
master->mRootNode = new aiNode(pFile);
|
||||||
pScene->mRootNode->mTransformation = aiMatrix4x4();
|
master->mRootNode->mTransformation = aiMatrix4x4();
|
||||||
|
|
||||||
pScene->mNumMeshes = 1;
|
if (vertices.size() && faces.size())
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
{
|
||||||
pScene->mFlags = AI_SCENE_FLAGS_INCOMPLETE;
|
master->mNumMeshes = 1;
|
||||||
|
master->mMeshes = new aiMesh*[master->mNumMeshes];
|
||||||
|
//master->mFlags = AI_SCENE_FLAGS_INCOMPLETE;
|
||||||
|
|
||||||
aiMesh* mesh = new aiMesh();
|
aiMesh* mesh = new aiMesh();
|
||||||
mesh->mNumFaces = faces->size();
|
mesh->mNumFaces = faces.size();
|
||||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
memcpy(mesh->mFaces, faces->data(), sizeof(aiFace) * mesh->mNumFaces);
|
std::copy(faces.begin(), faces.end(), mesh->mFaces);
|
||||||
mesh->mNumVertices = vertices->size();
|
mesh->mNumVertices = vertices.size();
|
||||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||||
::memcpy(mesh->mVertices, vertices->data(), sizeof(aiVector3D)* mesh->mNumVertices);
|
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
|
||||||
mesh->mPrimitiveTypes = primitivesType;
|
mesh->mPrimitiveTypes = primitivesType;
|
||||||
pScene->mMeshes[0] = mesh;
|
master->mMeshes[0] = mesh;
|
||||||
|
|
||||||
pScene->mRootNode->mNumMeshes = 1;
|
master->mRootNode->mNumMeshes = 1;
|
||||||
pScene->mRootNode->mMeshes = new unsigned int[pScene->mRootNode->mNumMeshes];
|
master->mRootNode->mMeshes = new unsigned int[master->mRootNode->mNumMeshes];
|
||||||
pScene->mRootNode->mMeshes[0] = 0;
|
master->mRootNode->mMeshes[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileIds.size() != 0){
|
||||||
|
//we did queue some sub files, get them
|
||||||
|
loader.LoadAll();
|
||||||
|
std::vector<AttachmentInfo> 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];
|
out = new float[num];
|
||||||
for (unsigned int i = 0; i < num; ++i){
|
for (unsigned int i = 0; i < num; ++i){
|
||||||
std::string token = GetNextToken(line);
|
std::string token = GetNextToken(line);
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#include "ParsingUtils.h"
|
#include "ParsingUtils.h"
|
||||||
#include "fast_atof.h"
|
#include "fast_atof.h"
|
||||||
#include "TinyFormatter.h"
|
#include "TinyFormatter.h"
|
||||||
|
#include "Importer.h"
|
||||||
|
#include "GenericProperty.h"
|
||||||
|
#include "SceneCombiner.h"
|
||||||
|
|
||||||
namespace Assimp{
|
namespace Assimp{
|
||||||
|
|
||||||
|
@ -22,13 +25,16 @@ namespace Assimp{
|
||||||
bool CanRead(const std::string& pFile, IOSystem* pIOHandler,
|
bool CanRead(const std::string& pFile, IOSystem* pIOHandler,
|
||||||
bool checkSig) const;
|
bool checkSig) const;
|
||||||
|
|
||||||
protected:
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
const aiImporterDesc* GetInfo() const;
|
const aiImporterDesc* GetInfo() const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SetupProperties(const Importer* pImp);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
protected:
|
||||||
void InternReadFile(const std::string& pFile, aiScene* pScene,
|
void InternReadFile(const std::string& pFile, aiScene* pScene,
|
||||||
IOSystem* pIOHandler);
|
IOSystem* pIOHandler);
|
||||||
|
|
||||||
|
@ -46,6 +52,8 @@ namespace Assimp{
|
||||||
throw DeadlyImportError("LDraw: " + Message);
|
throw DeadlyImportError("LDraw: " + Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string _libPath = "";
|
||||||
|
|
||||||
}; //end of class LDrawImporter
|
}; //end of class LDrawImporter
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -843,4 +843,15 @@ enum aiComponent
|
||||||
|
|
||||||
#define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION"
|
#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
|
||||||
|
* <br>
|
||||||
|
* Property type: String. Default value: </path/to/model/>.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_IMPORT_LDRAW_LIB_PATH "IMPORT_LDRAW_LIB_PATH"
|
||||||
|
|
||||||
#endif // !! AI_CONFIG_H_INC
|
#endif // !! AI_CONFIG_H_INC
|
||||||
|
|
Loading…
Reference in New Issue