diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index 11efbf9e9..57b8a6a58 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -41,6 +41,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the DXF importer class */ #include "DXFLoader.h" +#include "ParsingUtils.h" +#include "fast_atof.h" +#include "MaterialSystem.h" // public ASSIMP headers #include "../include/aiScene.h" @@ -59,7 +62,7 @@ using namespace Assimp; // Constructor to be privately used by Importer DXFImporter::DXFImporter() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ @@ -85,6 +88,32 @@ bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const extension[2] != 'x' && extension[2] != 'X' || extension[3] != 'f' && extension[3] != 'F'); } + +// ------------------------------------------------------------------------------------------------ +bool DXFImporter::GetNextLine() +{ + if(!SkipLine(buffer,&buffer))return false; + if(!SkipSpaces(buffer,&buffer))return GetNextLine(); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool DXFImporter::GetNextToken() +{ + SkipSpaces(buffer,&buffer); + groupCode = strtol10s(buffer,&buffer); + if(!GetNextLine())return false; + + // copy the data line to a separate buffer + char* m = cursor; + while (!IsLineEnd ( *buffer ) && m < (cursor+sizeof(cursor)/sizeof(char))) + *m++ = *buffer++; + + *m = '\0'; + GetNextLine(); + return true; +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void DXFImporter::InternReadFile( const std::string& pFile, @@ -96,5 +125,264 @@ void DXFImporter::InternReadFile( const std::string& pFile, if( file.get() == NULL) throw new ImportErrorException( "Failed to open DXF file " + pFile + ""); - throw new ImportErrorException("DXF: not yet implemented"); + // read the contents of the file in a buffer + unsigned int m = (unsigned int)file->FileSize(); + std::vector buffer2(m+1); + buffer = &buffer2[0]; + file->Read( &buffer2[0], m,1); + buffer2[m] = '\0'; + + mDefaultLayer = NULL; + + // now get all lines of the file + while (GetNextToken()) + { + if (2 == groupCode) + { + // ENTITIES section + if (!::strcmp(cursor,"ENTITIES")) + if (!ParseEntities())break; + + // HEADER section - just to print the file format version + else if (!::strcmp(cursor,"HEADER")) + if (!ParseHeader())break; + + // other sections such as BLOCK - skip them to make + // sure there will be no name conflicts + else + { + bool b = false; + while (GetNextToken()) + { + if (!groupCode && !::strcmp(cursor,"ENDSEC")) + {b = true;break;} + } + if (!b)break; + } + } + // print comment strings + else if (999 == groupCode) + { + DefaultLogger::get()->info(std::string( cursor )); + } + else if (!groupCode && !::strcmp(cursor,"EOF")) + break; + } + + if (mLayers.empty()) + throw new ImportErrorException("DXF: this file contains no 3d data"); + + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes = (unsigned int)mLayers.size()]; + m = 0; + for (std::vector::const_iterator it = mLayers.begin(),end = mLayers.end(); + it != end;++it) + { + // generate the output mesh + aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh(); + const std::vector& vPositions = (*it).vPositions; + + pMesh->mNumFaces = (unsigned int)vPositions.size() / 4u; + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + + aiVector3D* vpOut = pMesh->mVertices = new aiVector3D[vPositions.size()]; + const aiVector3D* vp = &vPositions[0]; + + for (unsigned int i = 0; i < pMesh->mNumFaces;++i) + { + aiFace& face = pMesh->mFaces[i]; + + // check whether we need four indices here + if (vp[3] != vp[2]) + { + face.mNumIndices = 4; + } + else face.mNumIndices = 3; + face.mIndices = new unsigned int[face.mNumIndices]; + + for (unsigned int a = 0; a < face.mNumIndices;++a) + { + *vpOut++ = vp[a]; + face.mIndices[a] = pMesh->mNumVertices++; + } + vp += 4; + } + } + + // generate the output scene graph + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mName.Set(""); + + if (1 == pScene->mNumMeshes) + { + pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ]; + pScene->mRootNode->mMeshes[0] = 0; + } + else + { + pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ]; + for (m = 0; m < pScene->mRootNode->mNumChildren;++m) + { + aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode(); + p->mName.length = ::strlen( mLayers[m].name ); + ::strcpy(p->mName.data, mLayers[m].name); + + p->mMeshes = new unsigned int[p->mNumMeshes = 1]; + p->mMeshes[0] = m; + p->mParent = pScene->mRootNode; + } + } + + // generate a default material + MaterialHelper* pcMat = new MaterialHelper(); + aiString s; + s.Set(AI_DEFAULT_MATERIAL_NAME); + pcMat->AddProperty(&s, AI_MATKEY_NAME); + + aiColor4D clrDiffuse(0.6f,0.6f,0.6f,1.0f); + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); + + clrDiffuse = aiColor4D(1.0f,1.0f,1.0f,1.0f); + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); + + clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f); + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); + + pScene->mNumMaterials = 1; + pScene->mMaterials = new aiMaterial*[1]; + pScene->mMaterials[0] = pcMat; + + // --- everything destructs automatically --- +} + +// ------------------------------------------------------------------------------------------------ +bool DXFImporter::ParseEntities() +{ + while (GetNextToken()) + { + if (!groupCode) + { + while (true) { + if (!::strcmp(cursor,"3DFACE")) + if (!Parse3DFace()) return false; else continue; + break; + }; + if (!::strcmp(cursor,"ENDSEC")) + return true; + } + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool DXFImporter::ParseHeader() +{ + // --- at the moment we don't need any information from the header + while (GetNextToken()) + { + if (!groupCode) + { + if (!::strcmp(cursor,"ENDSEC")) + return true; + } + + // print comment strings + else if (999 == groupCode) + { + DefaultLogger::get()->info(std::string( cursor )); + } + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool DXFImporter::Parse3DFace() +{ + bool ret = false; + LayerInfo* out = NULL; + + aiVector3D vip[4]; // -- vectors are initialized to zero + while (GetNextToken()) + { + switch (groupCode) + { + case 0: ret = true;break; + + // 8 specifies the layer + case 8: + { + for (std::vector::iterator it = mLayers.begin(),end = mLayers.end(); + it != end;++it) + { + if (!::strcmp( (*it).name, cursor )) + { + out = &(*it); + break; + } + } + if (!out) + { + // we don't have this layer yet + mLayers.push_back(LayerInfo()); + out = &mLayers.back(); + ::strcpy(out->name,cursor); + } + break; + } + + // x position of the first corner + case 10: vip[0].x = fast_atof(cursor);break; + + // y position of the first corner + case 20: vip[0].y = -fast_atof(cursor);break; + + // z position of the first corner + case 30: vip[0].z = fast_atof(cursor);break; + + // x position of the second corner + case 11: vip[1].x = fast_atof(cursor);break; + + // y position of the second corner + case 21: vip[1].y = -fast_atof(cursor);break; + + // z position of the second corner + case 31: vip[1].z = fast_atof(cursor);break; + + // x position of the third corner + case 12: vip[2].x = fast_atof(cursor);break; + + // y position of the third corner + case 22: vip[2].y = -fast_atof(cursor);break; + + // z position of the third corner + case 32: vip[2].z = fast_atof(cursor);break; + + // x position of the fourth corner + case 13: vip[3].x = fast_atof(cursor);break; + + // y position of the fourth corner + case 23: vip[3].y = -fast_atof(cursor);break; + + // z position of the fourth corner + case 33: vip[3].z = fast_atof(cursor);break; + }; + if (ret)break; + } + + // use a default layer if necessary + if (!out) + { + if (!mDefaultLayer) + { + mLayers.push_back(LayerInfo()); + mDefaultLayer = &mLayers.back(); + } + out = mDefaultLayer; + } + + // add the faces to the face list for this layer + out->vPositions.push_back(vip[0]); + out->vPositions.push_back(vip[1]); + out->vPositions.push_back(vip[2]); + out->vPositions.push_back(vip[3]); + return ret; } diff --git a/code/DXFLoader.h b/code/DXFLoader.h index 8690b905b..7046b6e6d 100644 --- a/code/DXFLoader.h +++ b/code/DXFLoader.h @@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_DXFLOADER_H_INCLUDED #define AI_DXFLOADER_H_INCLUDED +#include + #include "BaseImporter.h" #include "../include/aiTypes.h" @@ -81,11 +83,69 @@ protected: // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ + * See BaseImporter::InternReadFile() for details + */ void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + // ------------------------------------------------------------------- + /** Get the next line from the file. + * @return false if the end of the file was reached + */ + bool GetNextLine(); + + // ------------------------------------------------------------------- + /** Get the next token (group code + data line) from the file. + * @return false if the end of the file was reached + */ + bool GetNextToken(); + + // ------------------------------------------------------------------- + /** Parses the ENTITIES section in the file + * @return false if the end of the file was reached + */ + bool ParseEntities(); + + // ------------------------------------------------------------------- + /** Parses the HEADER section in the file + * @return false if the end of the file was reached + */ + bool ParseHeader(); + + // ------------------------------------------------------------------- + /** Parses a 3DFACE section in the file + * @return false if the end of the file was reached + */ + bool Parse3DFace(); + +private: + + // points to the next section + const char* buffer; + + // specifies the current group code + int groupCode; + + // contains the current data line + char cursor[4096]; + + // describes a single layer in the DXF file + struct LayerInfo + { + LayerInfo() + { + name[0] = '\0'; + } + + char name[4096]; + + // face buffer - order is x,y,z,w v1,v2,v3 (w is equal to z if unused) + std::vector vPositions; + }; + + // list of all loaded layers + std::vector mLayers; + LayerInfo* mDefaultLayer; }; } // end of namespace Assimp diff --git a/code/Importer.cpp b/code/Importer.cpp index 9f2b30c30..074457d27 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -107,6 +107,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if (!defined AI_BUILD_NO_LWO_IMPORTER) # include "LWOLoader.h" #endif +#if (!defined AI_BUILD_NO_DXF_IMPORTER) +# include "DXFLoader.h" +#endif // PostProcess-Steps @@ -222,6 +225,9 @@ Importer::Importer() : #if (!defined AI_BUILD_NO_LWO_IMPORTER) mImporter.push_back( new LWOImporter()); #endif +#if (!defined AI_BUILD_NO_DXF_IMPORTER) + mImporter.push_back( new DXFImporter()); +#endif // 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 - diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index 5571230c3..8529ff6d4 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -1061,9 +1061,8 @@ bool SMDImporter::ParseFloat(const char* szCurrent, const char** szCurrentOut, float& out) { if(!SkipSpaces(szCurrent,&szCurrent)) - { return false; - } + *szCurrentOut = fast_atof_move(szCurrent,out); return true; } @@ -1073,9 +1072,8 @@ bool SMDImporter::ParseUnsignedInt(const char* szCurrent, const char** szCurrentOut, uint32_t& out) { if(!SkipSpaces(szCurrent,&szCurrent)) - { return false; - } + out = (uint32_t)strtol10(szCurrent,szCurrentOut); return true; } @@ -1085,21 +1083,9 @@ bool SMDImporter::ParseSignedInt(const char* szCurrent, const char** szCurrentOut, int32_t& out) { if(!SkipSpaces(szCurrent,&szCurrent)) - { return false; - } - // handle signs - bool bInv = false; - if ('-' == *szCurrent) - { - ++szCurrent; - bInv = true; - } - else if ('+' == *szCurrent)++szCurrent; - // parse the integer - out = (int32_t)strtol10(szCurrent,szCurrentOut); - if (bInv)out = -out; + out = (int32_t)strtol10s(szCurrent,szCurrentOut); return true; } // ------------------------------------------------------------------------------------------------ diff --git a/code/fast_atof.h b/code/fast_atof.h index bb4b28633..0204c8908 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -58,6 +58,18 @@ inline unsigned int strtol10( const char* in, const char** out=0) return value; } +// ------------------------------------------------------------------------------------ +// signed variant of strtol10 +inline int strtol10s( const char* in, const char** out=0) +{ + bool bNeg = false; + if ('-' == *in){++in;bNeg = true;} + if ('+' == *in)++in; + int value = strtol10(in,out); + if (bNeg)value = -value; + return value; +} + // ------------------------------------------------------------------------------------ // specal version of the function, providing higher accuracy