vrshoot

view libs/assimp/STLLoader.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
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:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file Implementation of the STL importer class */
44 #include "AssimpPCH.h"
45 #ifndef ASSIMP_BUILD_NO_STL_IMPORTER
47 // internal headers
48 #include "STLLoader.h"
49 #include "ParsingUtils.h"
50 #include "fast_atof.h"
52 using namespace Assimp;
54 static const aiImporterDesc desc = {
55 "Stereolithography (STL) Importer",
56 "",
57 "",
58 "",
59 aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
60 0,
61 0,
62 0,
63 0,
64 "stl"
65 };
67 // ------------------------------------------------------------------------------------------------
68 // Constructor to be privately used by Importer
69 STLImporter::STLImporter()
70 {}
72 // ------------------------------------------------------------------------------------------------
73 // Destructor, private as well
74 STLImporter::~STLImporter()
75 {}
77 // ------------------------------------------------------------------------------------------------
78 // Returns whether the class can handle the format of the given file.
79 bool STLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
80 {
81 const std::string extension = GetExtension(pFile);
83 if (extension == "stl")
84 return true;
85 else if (!extension.length() || checkSig) {
86 if (!pIOHandler)
87 return true;
88 const char* tokens[] = {"STL","solid"};
89 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2);
90 }
91 return false;
92 }
94 // ------------------------------------------------------------------------------------------------
95 const aiImporterDesc* STLImporter::GetInfo () const
96 {
97 return &desc;
98 }
100 // ------------------------------------------------------------------------------------------------
101 // Imports the given file into the given scene structure.
102 void STLImporter::InternReadFile( const std::string& pFile,
103 aiScene* pScene, IOSystem* pIOHandler)
104 {
105 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
107 // Check whether we can read from the file
108 if( file.get() == NULL) {
109 throw DeadlyImportError( "Failed to open STL file " + pFile + ".");
110 }
112 fileSize = (unsigned int)file->FileSize();
114 // allocate storage and copy the contents of the file to a memory buffer
115 // (terminate it with zero)
116 std::vector<char> mBuffer2;
117 TextFileToBuffer(file.get(),mBuffer2);
119 this->pScene = pScene;
120 this->mBuffer = &mBuffer2[0];
122 // the default vertex color is white
123 clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 1.0f;
125 // allocate one mesh
126 pScene->mNumMeshes = 1;
127 pScene->mMeshes = new aiMesh*[1];
128 aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
129 pMesh->mMaterialIndex = 0;
131 // allocate a single node
132 pScene->mRootNode = new aiNode();
133 pScene->mRootNode->mNumMeshes = 1;
134 pScene->mRootNode->mMeshes = new unsigned int[1];
135 pScene->mRootNode->mMeshes[0] = 0;
137 bool bMatClr = false;
139 // check whether the file starts with 'solid' -
140 // in this case we can simply assume it IS a text file. finished.
141 if (!::strncmp(mBuffer,"solid",5)) {
142 LoadASCIIFile();
143 }
144 else bMatClr = LoadBinaryFile();
146 // now copy faces
147 pMesh->mFaces = new aiFace[pMesh->mNumFaces];
148 for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i) {
150 aiFace& face = pMesh->mFaces[i];
151 face.mIndices = new unsigned int[face.mNumIndices = 3];
152 for (unsigned int o = 0; o < 3;++o,++p) {
153 face.mIndices[o] = p;
154 }
155 }
157 // create a single default material - everything white, as we have vertex colors
158 aiMaterial* pcMat = new aiMaterial();
159 aiString s;
160 s.Set(AI_DEFAULT_MATERIAL_NAME);
161 pcMat->AddProperty(&s, AI_MATKEY_NAME);
163 aiColor4D clrDiffuse(1.0f,1.0f,1.0f,1.0f);
164 if (bMatClr) {
165 clrDiffuse = clrColorDefault;
166 }
167 pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
168 pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
169 clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f);
170 pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
172 pScene->mNumMaterials = 1;
173 pScene->mMaterials = new aiMaterial*[1];
174 pScene->mMaterials[0] = pcMat;
175 }
176 // ------------------------------------------------------------------------------------------------
177 // Read an ASCII STL file
178 void STLImporter::LoadASCIIFile()
179 {
180 aiMesh* pMesh = pScene->mMeshes[0];
182 const char* sz = mBuffer + 5; // skip the "solid"
183 SkipSpaces(&sz);
184 const char* szMe = sz;
185 while (!::IsSpaceOrNewLine(*sz)) {
186 sz++;
187 }
189 size_t temp;
190 // setup the name of the node
191 if ((temp = (size_t)(sz-szMe))) {
193 pScene->mRootNode->mName.length = temp;
194 memcpy(pScene->mRootNode->mName.data,szMe,temp);
195 pScene->mRootNode->mName.data[temp] = '\0';
196 }
197 else pScene->mRootNode->mName.Set("<STL_ASCII>");
199 // try to guess how many vertices we could have
200 // assume we'll need 160 bytes for each face
201 pMesh->mNumVertices = ( pMesh->mNumFaces = std::max(1u,fileSize / 160u )) * 3;
202 pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
203 pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
205 unsigned int curFace = 0, curVertex = 3;
206 for ( ;; )
207 {
208 // go to the next token
209 if(!SkipSpacesAndLineEnd(&sz))
210 {
211 // seems we're finished although there was no end marker
212 DefaultLogger::get()->warn("STL: unexpected EOF. \'endsolid\' keyword was expected");
213 break;
214 }
215 // facet normal -0.13 -0.13 -0.98
216 if (!strncmp(sz,"facet",5) && IsSpaceOrNewLine(*(sz+5))) {
218 if (3 != curVertex) {
219 DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
220 }
221 if (pMesh->mNumFaces == curFace) {
222 ai_assert(pMesh->mNumFaces != 0);
224 // need to resize the arrays, our size estimate was wrong
225 unsigned int iNeededSize = (unsigned int)(sz-mBuffer) / pMesh->mNumFaces;
226 if (iNeededSize <= 160)iNeededSize >>= 1; // prevent endless looping
227 unsigned int add = (unsigned int)((mBuffer+fileSize)-sz) / iNeededSize;
228 add += add >> 3; // add 12.5% as buffer
229 iNeededSize = (pMesh->mNumFaces + add)*3;
230 aiVector3D* pv = new aiVector3D[iNeededSize];
231 memcpy(pv,pMesh->mVertices,pMesh->mNumVertices*sizeof(aiVector3D));
232 delete[] pMesh->mVertices;
233 pMesh->mVertices = pv;
234 pv = new aiVector3D[iNeededSize];
235 memcpy(pv,pMesh->mNormals,pMesh->mNumVertices*sizeof(aiVector3D));
236 delete[] pMesh->mNormals;
237 pMesh->mNormals = pv;
239 pMesh->mNumVertices = iNeededSize;
240 pMesh->mNumFaces += add;
241 }
242 aiVector3D* vn = &pMesh->mNormals[curFace++*3];
244 sz += 6;
245 curVertex = 0;
246 SkipSpaces(&sz);
247 if (strncmp(sz,"normal",6)) {
248 DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
249 }
250 else
251 {
252 sz += 7;
253 SkipSpaces(&sz);
254 sz = fast_atoreal_move<float>(sz, (float&)vn->x );
255 SkipSpaces(&sz);
256 sz = fast_atoreal_move<float>(sz, (float&)vn->y );
257 SkipSpaces(&sz);
258 sz = fast_atoreal_move<float>(sz, (float&)vn->z );
259 *(vn+1) = *vn;
260 *(vn+2) = *vn;
261 }
262 }
263 // vertex 1.50000 1.50000 0.00000
264 else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
265 {
266 if (3 == curVertex) {
267 DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
268 }
269 else
270 {
271 sz += 7;
272 SkipSpaces(&sz);
273 aiVector3D* vn = &pMesh->mVertices[(curFace-1)*3 + curVertex++];
274 sz = fast_atoreal_move<float>(sz, (float&)vn->x );
275 SkipSpaces(&sz);
276 sz = fast_atoreal_move<float>(sz, (float&)vn->y );
277 SkipSpaces(&sz);
278 sz = fast_atoreal_move<float>(sz, (float&)vn->z );
279 }
280 }
281 else if (!::strncmp(sz,"endsolid",8)) {
282 // finished!
283 break;
284 }
285 // else skip the whole identifier
286 else while (!::IsSpaceOrNewLine(*sz)) {
287 ++sz;
288 }
289 }
291 if (!curFace) {
292 pMesh->mNumFaces = 0;
293 throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
294 }
295 pMesh->mNumFaces = curFace;
296 pMesh->mNumVertices = curFace*3;
297 // we are finished!
298 }
300 // ------------------------------------------------------------------------------------------------
301 // Read a binary STL file
302 bool STLImporter::LoadBinaryFile()
303 {
304 // skip the first 80 bytes
305 if (fileSize < 84) {
306 throw DeadlyImportError("STL: file is too small for the header");
307 }
308 bool bIsMaterialise = false;
310 // search for an occurence of "COLOR=" in the header
311 const char* sz2 = (const char*)mBuffer;
312 const char* const szEnd = sz2+80;
313 while (sz2 < szEnd) {
315 if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&
316 'O' == *sz2++ && 'R' == *sz2++ && '=' == *sz2++) {
318 // read the default vertex color for facets
319 bIsMaterialise = true;
320 DefaultLogger::get()->info("STL: Taking code path for Materialise files");
321 clrColorDefault.r = (*sz2++) / 255.0f;
322 clrColorDefault.g = (*sz2++) / 255.0f;
323 clrColorDefault.b = (*sz2++) / 255.0f;
324 clrColorDefault.a = (*sz2++) / 255.0f;
325 break;
326 }
327 }
328 const unsigned char* sz = (const unsigned char*)mBuffer + 80;
330 // now read the number of facets
331 aiMesh* pMesh = pScene->mMeshes[0];
332 pScene->mRootNode->mName.Set("<STL_BINARY>");
334 pMesh->mNumFaces = *((uint32_t*)sz);
335 sz += 4;
337 if (fileSize < 84 + pMesh->mNumFaces*50) {
338 throw DeadlyImportError("STL: file is too small to hold all facets");
339 }
341 if (!pMesh->mNumFaces) {
342 throw DeadlyImportError("STL: file is empty. There are no facets defined");
343 }
345 pMesh->mNumVertices = pMesh->mNumFaces*3;
347 aiVector3D* vp,*vn;
348 vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
349 vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
351 for (unsigned int i = 0; i < pMesh->mNumFaces;++i) {
353 // NOTE: Blender sometimes writes empty normals ... this is not
354 // our fault ... the RemoveInvalidData helper step should fix that
355 *vn = *((aiVector3D*)sz);
356 sz += sizeof(aiVector3D);
357 *(vn+1) = *vn;
358 *(vn+2) = *vn;
359 vn += 3;
361 *vp++ = *((aiVector3D*)sz);
362 sz += sizeof(aiVector3D);
364 *vp++ = *((aiVector3D*)sz);
365 sz += sizeof(aiVector3D);
367 *vp++ = *((aiVector3D*)sz);
368 sz += sizeof(aiVector3D);
370 uint16_t color = *((uint16_t*)sz);
371 sz += 2;
373 if (color & (1 << 15))
374 {
375 // seems we need to take the color
376 if (!pMesh->mColors[0])
377 {
378 pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
379 for (unsigned int i = 0; i <pMesh->mNumVertices;++i)
380 *pMesh->mColors[0]++ = this->clrColorDefault;
381 pMesh->mColors[0] -= pMesh->mNumVertices;
383 DefaultLogger::get()->info("STL: Mesh has vertex colors");
384 }
385 aiColor4D* clr = &pMesh->mColors[0][i*3];
386 clr->a = 1.0f;
387 if (bIsMaterialise) // this is reversed
388 {
389 clr->r = (color & 0x31u) / 31.0f;
390 clr->g = ((color & (0x31u<<5))>>5u) / 31.0f;
391 clr->b = ((color & (0x31u<<10))>>10u) / 31.0f;
392 }
393 else
394 {
395 clr->b = (color & 0x31u) / 31.0f;
396 clr->g = ((color & (0x31u<<5))>>5u) / 31.0f;
397 clr->r = ((color & (0x31u<<10))>>10u) / 31.0f;
398 }
399 // assign the color to all vertices of the face
400 *(clr+1) = *clr;
401 *(clr+2) = *clr;
402 }
403 }
404 if (bIsMaterialise && !pMesh->mColors[0])
405 {
406 // use the color as diffuse material color
407 return true;
408 }
409 return false;
410 }
412 #endif // !! ASSIMP_BUILD_NO_STL_IMPORTER