1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2016, 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
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 #include <memory>
54 #include <assimp/IOSystem.hpp>
55 #include <assimp/scene.h>
56 #include <assimp/DefaultLogger.hpp>
57
58
59 using namespace Assimp;
60
61 static const aiImporterDesc desc = {
62 "OFF Importer",
63 "",
64 "",
65 "",
66 aiImporterFlags_SupportBinaryFlavour,
67 0,
68 0,
69 0,
70 0,
71 "off"
72 };
73
74 // ------------------------------------------------------------------------------------------------
75 // Constructor to be privately used by Importer
OFFImporter()76 OFFImporter::OFFImporter()
77 {}
78
79 // ------------------------------------------------------------------------------------------------
80 // Destructor, private as well
~OFFImporter()81 OFFImporter::~OFFImporter()
82 {}
83
84 // ------------------------------------------------------------------------------------------------
85 // Returns whether the class can handle the format of the given file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const86 bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
87 {
88 const std::string extension = GetExtension(pFile);
89
90 if (extension == "off")
91 return true;
92 else if (!extension.length() || checkSig)
93 {
94 if (!pIOHandler)return true;
95 const char* tokens[] = {"off"};
96 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
97 }
98 return false;
99 }
100
101 // ------------------------------------------------------------------------------------------------
GetInfo() const102 const aiImporterDesc* OFFImporter::GetInfo () const
103 {
104 return &desc;
105 }
106
107 // ------------------------------------------------------------------------------------------------
108 // Imports the given file into the given scene structure.
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)109 void OFFImporter::InternReadFile( const std::string& pFile,
110 aiScene* pScene, IOSystem* pIOHandler)
111 {
112 std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
113
114 // Check whether we can read from the file
115 if( file.get() == NULL) {
116 throw DeadlyImportError( "Failed to open OFF file " + pFile + ".");
117 }
118
119 // allocate storage and copy the contents of the file to a memory buffer
120 std::vector<char> mBuffer2;
121 TextFileToBuffer(file.get(),mBuffer2);
122 const char* buffer = &mBuffer2[0];
123
124 char line[4096];
125 GetNextLine(buffer,line);
126 if ('O' == line[0]) {
127 GetNextLine(buffer,line); // skip the 'OFF' line
128 }
129
130 const char* sz = line; SkipSpaces(&sz);
131 const unsigned int numVertices = strtoul10(sz,&sz);SkipSpaces(&sz);
132 const unsigned int numFaces = strtoul10(sz,&sz);
133
134 if (!numVertices) {
135 throw DeadlyImportError("OFF: There are no valid vertices");
136 }
137 if (!numFaces) {
138 throw DeadlyImportError("OFF: There are no valid faces");
139 }
140
141 pScene->mNumMeshes = 1;
142 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
143
144 aiMesh* mesh = new aiMesh();
145 pScene->mMeshes[0] = mesh;
146
147 mesh->mNumFaces = numFaces;
148 aiFace* faces = new aiFace [mesh->mNumFaces];
149 mesh->mFaces = faces;
150
151 std::vector<aiVector3D> tempPositions(numVertices);
152
153 // now read all vertex lines
154 for (unsigned int i = 0; i< numVertices;++i)
155 {
156 if(!GetNextLine(buffer,line))
157 {
158 DefaultLogger::get()->error("OFF: The number of verts in the header is incorrect");
159 break;
160 }
161 aiVector3D& v = tempPositions[i];
162
163 sz = line; SkipSpaces(&sz);
164 sz = fast_atoreal_move<float>(sz,(float&)v.x); SkipSpaces(&sz);
165 sz = fast_atoreal_move<float>(sz,(float&)v.y); SkipSpaces(&sz);
166 fast_atoreal_move<float>(sz,(float&)v.z);
167 }
168
169
170 // First find out how many vertices we'll need
171 const char* old = buffer;
172 for (unsigned int i = 0; i< mesh->mNumFaces;++i)
173 {
174 if(!GetNextLine(buffer,line))
175 {
176 DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect");
177 break;
178 }
179 sz = line;SkipSpaces(&sz);
180 faces->mNumIndices = strtoul10(sz,&sz);
181 if(!(faces->mNumIndices) || faces->mNumIndices > 9)
182 {
183 DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
184 --mesh->mNumFaces;
185 continue;
186 }
187 mesh->mNumVertices += faces->mNumIndices;
188 ++faces;
189 }
190
191 if (!mesh->mNumVertices)
192 throw DeadlyImportError("OFF: There are no valid faces");
193
194 // allocate storage for the output vertices
195 std::vector<aiVector3D> verts;
196 verts.reserve(mesh->mNumVertices);
197
198 // second: now parse all face indices
199 buffer = old;
200 faces = mesh->mFaces;
201 for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
202 {
203 if(!GetNextLine(buffer,line))break;
204
205 unsigned int idx;
206 sz = line;SkipSpaces(&sz);
207 idx = strtoul10(sz,&sz);
208 if(!(idx) || idx > 9)
209 continue;
210
211 faces->mIndices = new unsigned int [faces->mNumIndices];
212 for (unsigned int m = 0; m < faces->mNumIndices;++m)
213 {
214 SkipSpaces(&sz);
215 idx = strtoul10(sz,&sz);
216 if ((idx) >= numVertices)
217 {
218 DefaultLogger::get()->error("OFF: Vertex index is out of range");
219 idx = numVertices-1;
220 }
221 faces->mIndices[m] = p++;
222 verts.push_back(tempPositions[idx]);
223 }
224 ++i;
225 ++faces;
226 }
227
228 if (mesh->mNumVertices != verts.size()) {
229 throw DeadlyImportError("OFF: Vertex count mismatch");
230 }
231 mesh->mVertices = new aiVector3D[verts.size()];
232 memcpy(mesh->mVertices, &verts[0], verts.size() * sizeof(aiVector3D));
233 // generate the output node graph
234 pScene->mRootNode = new aiNode();
235 pScene->mRootNode->mName.Set("<OFFRoot>");
236 pScene->mRootNode->mNumMeshes = 1;
237 pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes];
238 pScene->mRootNode->mMeshes[0] = 0;
239
240 // generate a default material
241 pScene->mNumMaterials = 1;
242 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
243 aiMaterial* pcMat = new aiMaterial();
244
245 aiColor4D clr(0.6f,0.6f,0.6f,1.0f);
246 pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
247 pScene->mMaterials[0] = pcMat;
248
249 const int twosided =1;
250 pcMat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED);
251 }
252
253 #endif // !! ASSIMP_BUILD_NO_OFF_IMPORTER
254