1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2012, assimp team
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41
42 /** @file OFFLoader.cpp
43 * @brief Implementation of the OFF importer class
44 */
45
46 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_OFF_IMPORTER
48
49 // internal headers
50 #include "OFFLoader.h"
51 #include "ParsingUtils.h"
52 #include "fast_atof.h"
53
54
55 using namespace Assimp;
56
57 // ------------------------------------------------------------------------------------------------
58 // Constructor to be privately used by Importer
OFFImporter()59 OFFImporter::OFFImporter()
60 {}
61
62 // ------------------------------------------------------------------------------------------------
63 // Destructor, private as well
~OFFImporter()64 OFFImporter::~OFFImporter()
65 {}
66
67 // ------------------------------------------------------------------------------------------------
68 // Returns whether the class can handle the format of the given file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const69 bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
70 {
71 const std::string extension = GetExtension(pFile);
72
73 if (extension == "off")
74 return true;
75 else if (!extension.length() || checkSig)
76 {
77 if (!pIOHandler)return true;
78 const char* tokens[] = {"off"};
79 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
80 }
81 return false;
82 }
83
84 // ------------------------------------------------------------------------------------------------
GetExtensionList(std::set<std::string> & extensions)85 void OFFImporter::GetExtensionList(std::set<std::string>& extensions)
86 {
87 extensions.insert("off");
88 }
89
90 // ------------------------------------------------------------------------------------------------
91 // Imports the given file into the given scene structure.
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)92 void OFFImporter::InternReadFile( const std::string& pFile,
93 aiScene* pScene, IOSystem* pIOHandler)
94 {
95 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
96
97 // Check whether we can read from the file
98 if( file.get() == NULL) {
99 throw DeadlyImportError( "Failed to open OFF file " + pFile + ".");
100 }
101
102 // allocate storage and copy the contents of the file to a memory buffer
103 std::vector<char> mBuffer2;
104 TextFileToBuffer(file.get(),mBuffer2);
105 const char* buffer = &mBuffer2[0];
106
107 char line[4096];
108 GetNextLine(buffer,line);
109 if ('O' == line[0]) {
110 GetNextLine(buffer,line); // skip the 'OFF' line
111 }
112
113 const char* sz = line; SkipSpaces(&sz);
114 const unsigned int numVertices = strtoul10(sz,&sz);SkipSpaces(&sz);
115 const unsigned int numFaces = strtoul10(sz,&sz);
116
117 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
118 aiMesh* mesh = pScene->mMeshes[0] = new aiMesh();
119 aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces];
120
121 std::vector<aiVector3D> tempPositions(numVertices);
122
123 // now read all vertex lines
124 for (unsigned int i = 0; i< numVertices;++i)
125 {
126 if(!GetNextLine(buffer,line))
127 {
128 DefaultLogger::get()->error("OFF: The number of verts in the header is incorrect");
129 break;
130 }
131 aiVector3D& v = tempPositions[i];
132
133 sz = line; SkipSpaces(&sz);
134 sz = fast_atoreal_move<float>(sz,(float&)v.x); SkipSpaces(&sz);
135 sz = fast_atoreal_move<float>(sz,(float&)v.y); SkipSpaces(&sz);
136 fast_atoreal_move<float>(sz,(float&)v.z);
137 }
138
139
140 // First find out how many vertices we'll need
141 const char* old = buffer;
142 for (unsigned int i = 0; i< mesh->mNumFaces;++i)
143 {
144 if(!GetNextLine(buffer,line))
145 {
146 DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect");
147 break;
148 }
149 sz = line;SkipSpaces(&sz);
150 if(!(faces->mNumIndices = strtoul10(sz,&sz)) || faces->mNumIndices > 9)
151 {
152 DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
153 --mesh->mNumFaces;
154 continue;
155 }
156 mesh->mNumVertices += faces->mNumIndices;
157 ++faces;
158 }
159
160 if (!mesh->mNumVertices)
161 throw DeadlyImportError("OFF: There are no valid faces");
162
163 // allocate storage for the output vertices
164 aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
165
166 // second: now parse all face indices
167 buffer = old;faces = mesh->mFaces;
168 for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
169 {
170 if(!GetNextLine(buffer,line))break;
171
172 unsigned int idx;
173 sz = line;SkipSpaces(&sz);
174 if(!(idx = strtoul10(sz,&sz)) || idx > 9)
175 continue;
176
177 faces->mIndices = new unsigned int [faces->mNumIndices];
178 for (unsigned int m = 0; m < faces->mNumIndices;++m)
179 {
180 SkipSpaces(&sz);
181 if ((idx = strtoul10(sz,&sz)) >= numVertices)
182 {
183 DefaultLogger::get()->error("OFF: Vertex index is out of range");
184 idx = numVertices-1;
185 }
186 faces->mIndices[m] = p++;
187 *verts++ = tempPositions[idx];
188 }
189 ++i;
190 ++faces;
191 }
192
193 // generate the output node graph
194 pScene->mRootNode = new aiNode();
195 pScene->mRootNode->mName.Set("<OFFRoot>");
196 pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes = 1];
197 pScene->mRootNode->mMeshes[0] = 0;
198
199 // generate a default material
200 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = 1];
201 aiMaterial* pcMat = new aiMaterial();
202
203 aiColor4D clr(0.6f,0.6f,0.6f,1.0f);
204 pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
205 pScene->mMaterials[0] = pcMat;
206
207 const int twosided =1;
208 pcMat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED);
209 }
210
211 #endif // !! ASSIMP_BUILD_NO_OFF_IMPORTER
212