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