123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- /*
- ---------------------------------------------------------------------------
- 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 Implementation of the STL importer class */
- // internal headers
- #include "NFFLoader.h"
- #include "MaterialSystem.h"
- #include "ParsingUtils.h"
- #include "StandardShapes.h"
- #include "fast_atof.h"
- // public assimp headers
- #include "../include/IOStream.h"
- #include "../include/IOSystem.h"
- #include "../include/aiScene.h"
- #include "../include/aiAssert.h"
- #include "../include/DefaultLogger.h"
- // boost headers
- #include <boost/scoped_ptr.hpp>
- using namespace Assimp;
- // ------------------------------------------------------------------------------------------------
- // Constructor to be privately used by Importer
- NFFImporter::NFFImporter()
- {
- }
- // ------------------------------------------------------------------------------------------------
- // Destructor, private as well
- NFFImporter::~NFFImporter()
- {
- }
- // ------------------------------------------------------------------------------------------------
- // Returns whether the class can handle the format of the given file.
- bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
- {
- // simple check of file extension is enough for the moment
- std::string::size_type pos = pFile.find_last_of('.');
- // no file extension - can't read
- if( pos == std::string::npos)return false;
- std::string extension = pFile.substr( pos);
- return !(extension.length() != 4 || extension[0] != '.' ||
- extension[1] != 'n' && extension[1] != 'N' ||
- extension[2] != 'f' && extension[2] != 'F' ||
- extension[3] != 'f' && extension[3] != 'F');
- }
- // ------------------------------------------------------------------------------------------------
- bool GetNextLine(const char*& buffer, char out[4096])
- {
- char* _out = out;
- char* const end = _out+4096;
- while (!IsLineEnd( *buffer ) && _out < end)
- *_out++ = *buffer++;
- *_out = '\0';
- if ('\0' == *buffer)return false;
- while (IsLineEnd( *buffer ))++buffer;
- return true;
- }
- // ------------------------------------------------------------------------------------------------
- #define AI_NFF_PARSE_FLOAT(f) \
- SkipSpaces(&sz); \
- sz = fast_atof_move(sz, f);
- // ------------------------------------------------------------------------------------------------
- #define AI_NFF_PARSE_TRIPLE(v) \
- AI_NFF_PARSE_FLOAT(v.x) \
- AI_NFF_PARSE_FLOAT(v.y) \
- AI_NFF_PARSE_FLOAT(v.z)
- // ------------------------------------------------------------------------------------------------
- // Imports the given file into the given scene structure.
- void NFFImporter::InternReadFile( const std::string& pFile,
- aiScene* pScene, IOSystem* pIOHandler)
- {
- boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
- // Check whether we can read from the file
- if( file.get() == NULL)
- throw new ImportErrorException( "Failed to open NFF file " + pFile + ".");
- unsigned int m = (unsigned int)file->FileSize();
- // allocate storage and copy the contents of the file to a memory buffer
- // (terminate it with zero)
- std::vector<char> mBuffer2(m+1);
- file->Read(&mBuffer2[0],m,1);
- const char* buffer = &mBuffer2[0];
- mBuffer2[m] = '\0';
- // mesh arrays - separate here to make the handling of
- // the pointers below easier.
- std::vector<MeshInfo> meshes;
- std::vector<MeshInfo> meshesWithNormals;
- std::vector<MeshInfo> meshesLocked;
- MeshInfo* currentMeshWithNormals = NULL;
- MeshInfo* currentMesh = NULL;
- ShadingInfo s; // current material info
- char line[4096];
- const char* sz;
- unsigned int sphere = 0,cylinder = 0,cone = 0,numNamed = 0;
- while (GetNextLine(buffer,line))
- {
- if ('p' == line[0])
- {
- MeshInfo* out = NULL;
- // 'pp' - polygon patch primitive
- if ('p' == line[1])
- {
- if (meshesWithNormals.empty())
- {
- meshesWithNormals.push_back(MeshInfo(true));
- currentMeshWithNormals = &meshesWithNormals.back();
- }
-
- sz = &line[2];out = currentMeshWithNormals;
- }
- // 'p' - polygon primitive
- else
- {
- if (meshes.empty())
- {
- meshes.push_back(MeshInfo(false));
- currentMesh = &meshes.back();
- }
- sz = &line[1];out = currentMesh;
- }
- SkipSpaces(sz,&sz);
- m = strtol10(sz);
- out->faces.push_back(m);
- for (unsigned int n = 0; n < m;++n)
- {
- if(!GetNextLine(buffer,line))
- {
- DefaultLogger::get()->error("NFF: Unexpected EOF was encountered");
- break;
- }
- aiVector3D v; sz = &line[0];
- AI_NFF_PARSE_TRIPLE(v);
- out->vertices.push_back(v);
- if (&meshesWithNormals.back() == out)
- {
- AI_NFF_PARSE_TRIPLE(v);
- out->normals.push_back(v);
- }
- }
- }
- // 'f' - shading information block
- else if ('f' == line[0] && IsSpace(line[1]))
- {
- SkipSpaces(&line[1],&sz);
- // read just the RGB colors, the rest is ignored for the moment
- sz = fast_atof_move(sz, s.color.r);
- SkipSpaces(&sz);
- sz = fast_atof_move(sz, s.color.g);
- SkipSpaces(&sz);
- sz = fast_atof_move(sz, s.color.b);
- // check whether we have this material already -
- // although we have the RRM-Step, this is necessary here.
- // otherwise we would generate hundreds of small meshes
- // with just a few faces - this is surely never wanted.
- currentMesh = currentMeshWithNormals = NULL;
- for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
- it != end;++it)
- {
- if ((*it).bLocked)continue;
- if ((*it).shader == s)
- {
- if ((*it).bHasNormals)currentMeshWithNormals = &(*it);
- else currentMesh = &(*it);
- }
- }
- if (!currentMesh)
- {
- meshes.push_back(MeshInfo(false));
- currentMesh = &meshes.back();
- currentMesh->shader = s;
- }
- if (!currentMeshWithNormals)
- {
- meshesWithNormals.push_back(MeshInfo(true));
- currentMeshWithNormals = &meshesWithNormals.back();
- currentMeshWithNormals->shader = s;
- }
- }
- // 's' - sphere
- else if ('s' == line[0] && IsSpace(line[1]))
- {
- meshesLocked.push_back(MeshInfo(false,true));
- MeshInfo& currentMesh = meshesLocked.back();
- currentMesh.shader = s;
- sz = &line[1];
- aiVector3D center; float radius;
- AI_NFF_PARSE_TRIPLE(center);
- AI_NFF_PARSE_FLOAT(radius);
- currentMesh.center = center;
- // generate the sphere - it consists of simple triangles
- StandardShapes::MakeSphere(aiVector3D(), radius, 500.0f, currentMesh.vertices);
- currentMesh.faces.resize(currentMesh.vertices.size(),3);
- // generate a name for the mesh
- ::sprintf(currentMesh.name,"sphere_%i",sphere++);
- }
- // 'c' - cone
- else if ('c' == line[0] && IsSpace(line[1]))
- {
- meshesLocked.push_back(MeshInfo(false,true));
- MeshInfo& currentMesh = meshes.back();
- currentMesh.shader = s;
- sz = &line[1];
- aiVector3D center1, center2; float radius1, radius2;
- AI_NFF_PARSE_TRIPLE(center1);
- AI_NFF_PARSE_FLOAT(radius1);
- AI_NFF_PARSE_TRIPLE(center2);
- AI_NFF_PARSE_FLOAT(radius2);
- // compute the center point of the cone/cylinder
- center2 = (center2-center1)/2.f;
- currentMesh.center = center1+center2;
- center1 = -center2;
- // generate the cone - it consists of simple triangles
- StandardShapes::MakeCone(center1, radius1, center2, radius2, 500.0f, currentMesh.vertices);
- currentMesh.faces.resize(currentMesh.vertices.size(),3);
- // generate a name for the mesh
- if (radius1 != radius2)
- ::sprintf(currentMesh.name,"cone_%i",cone++);
- else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
- }
- // '#' - comment
- else if ('#' == line[0])
- {
- const char* sz;SkipSpaces(&line[1],&sz);
- if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
- }
- }
- // copy all arrays into one large
- meshes.reserve(meshes.size()+meshesLocked.size()+meshesWithNormals.size());
- meshes.insert(meshes.end(),meshesLocked.begin(),meshesLocked.end());
- meshes.insert(meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end());
- // now generate output meshes. first find out how many meshes we'll need
- std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
- for (;it != end;++it)
- {
- if (!(*it).faces.empty())
- {
- ++pScene->mNumMeshes;
- if ((*it).name[0])++numNamed;
- }
- }
- // generate a dummy root node - assign all unnamed elements such
- // as polygons and polygon patches to the root node and generate
- // sub nodes for named objects such as spheres and cones.
- aiNode* const root = new aiNode();
- root->mName.Set("<NFF_Root>");
- root->mNumChildren = numNamed;
- root->mNumMeshes = pScene->mNumMeshes-numNamed;
- aiNode** ppcChildren;
- unsigned int* pMeshes;
- if (root->mNumMeshes)
- pMeshes = root->mMeshes = new unsigned int[root->mNumMeshes];
- if (root->mNumChildren)
- ppcChildren = root->mChildren = new aiNode*[root->mNumChildren];
- if (!pScene->mNumMeshes)throw new ImportErrorException("NFF: No meshes loaded");
- pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
- pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
- for (it = meshes.begin(), m = 0; it != end;++it)
- {
- if ((*it).faces.empty())continue;
- const MeshInfo& src = *it;
- aiMesh* const mesh = pScene->mMeshes[m] = new aiMesh();
- mesh->mNumVertices = (unsigned int)src.vertices.size();
- mesh->mNumFaces = (unsigned int)src.faces.size();
- // generate sub nodes for named meshes
- if (src.name[0])
- {
- aiNode* const node = *ppcChildren = new aiNode();
- node->mParent = root;
- node->mNumMeshes = 1;
- node->mMeshes = new unsigned int[1];
- node->mMeshes[0] = m;
- // setup the transformation matrix of the node
- node->mTransformation.a4 = src.center.x;
- node->mTransformation.b4 = src.center.y;
- node->mTransformation.c4 = src.center.z;
- ++ppcChildren;
- }
- else *pMeshes++ = m;
- // copy vertex positions
- mesh->mVertices = new aiVector3D[mesh->mNumVertices];
- ::memcpy(mesh->mVertices,&src.vertices[0],sizeof(aiVector3D)*mesh->mNumVertices);
- if (src.bHasNormals)
- {
- ai_assert(src.normals.size() == src.vertices.size());
- // copy normal vectors
- mesh->mNormals = new aiVector3D[mesh->mNumVertices];
- ::memcpy(mesh->mNormals,&src.normals[0],sizeof(aiVector3D)*mesh->mNumVertices);
- }
- // generate faces
- unsigned int p = 0;
- aiFace* pFace = mesh->mFaces = new aiFace[mesh->mNumFaces];
- for (std::vector<unsigned int>::const_iterator it2 = src.faces.begin(),
- end2 = src.faces.end();
- it2 != end2;++it2,++pFace)
- {
- pFace->mIndices = new unsigned int [ pFace->mNumIndices = *it2 ];
- for (unsigned int o = 0; o < pFace->mNumIndices;++o)
- pFace->mIndices[o] = p++;
- }
- // generate a material for the mesh
- MaterialHelper* pcMat = (MaterialHelper*)(pScene->
- mMaterials[m++] = new MaterialHelper());
- aiString s;
- s.Set(AI_DEFAULT_MATERIAL_NAME);
- pcMat->AddProperty(&s, AI_MATKEY_NAME);
- pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_DIFFUSE);
- pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_SPECULAR);
- }
- pScene->mRootNode = root;
- }
|