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