vrshoot

view libs/assimp/PlyLoader.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 PlyLoader.cpp
43 * @brief Implementation of the PLY importer class
44 */
46 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
49 // internal headers
50 #include "PlyLoader.h"
52 using namespace Assimp;
54 static const aiImporterDesc desc = {
55 "Stanford Polygon Library (PLY) Importer",
56 "",
57 "",
58 "",
59 aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
60 0,
61 0,
62 0,
63 0,
64 "ply"
65 };
67 // ------------------------------------------------------------------------------------------------
68 // Constructor to be privately used by Importer
69 PLYImporter::PLYImporter()
70 {}
72 // ------------------------------------------------------------------------------------------------
73 // Destructor, private as well
74 PLYImporter::~PLYImporter()
75 {}
77 // ------------------------------------------------------------------------------------------------
78 // Returns whether the class can handle the format of the given file.
79 bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
80 {
81 const std::string extension = GetExtension(pFile);
83 if (extension == "ply")
84 return true;
85 else if (!extension.length() || checkSig)
86 {
87 if (!pIOHandler)return true;
88 const char* tokens[] = {"ply"};
89 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
90 }
91 return false;
92 }
94 // ------------------------------------------------------------------------------------------------
95 const aiImporterDesc* PLYImporter::GetInfo () const
96 {
97 return &desc;
98 }
100 // ------------------------------------------------------------------------------------------------
101 // Imports the given file into the given scene structure.
102 void PLYImporter::InternReadFile( const std::string& pFile,
103 aiScene* pScene, IOSystem* pIOHandler)
104 {
105 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
107 // Check whether we can read from the file
108 if( file.get() == NULL) {
109 throw DeadlyImportError( "Failed to open PLY file " + pFile + ".");
110 }
112 // allocate storage and copy the contents of the file to a memory buffer
113 std::vector<char> mBuffer2;
114 TextFileToBuffer(file.get(),mBuffer2);
115 mBuffer = (unsigned char*)&mBuffer2[0];
117 // the beginning of the file must be PLY - magic, magic
118 if ((mBuffer[0] != 'P' && mBuffer[0] != 'p') ||
119 (mBuffer[1] != 'L' && mBuffer[1] != 'l') ||
120 (mBuffer[2] != 'Y' && mBuffer[2] != 'y')) {
121 throw DeadlyImportError( "Invalid .ply file: Magic number \'ply\' is no there");
122 }
124 char* szMe = (char*)&this->mBuffer[3];
125 SkipSpacesAndLineEnd(szMe,(const char**)&szMe);
127 // determine the format of the file data
128 PLY::DOM sPlyDom;
129 if (TokenMatch(szMe,"format",6))
130 {
131 if (TokenMatch(szMe,"ascii",5))
132 {
133 SkipLine(szMe,(const char**)&szMe);
134 if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
135 throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#1)");
136 }
137 else if (!::strncmp(szMe,"binary_",7))
138 {
139 bool bIsBE = false;
140 szMe+=7;
142 // binary_little_endian
143 // binary_big_endian
144 #if (defined AI_BUILD_BIG_ENDIAN)
145 if ('l' == *szMe || 'L' == *szMe)bIsBE = true;
146 #else
147 if ('b' == *szMe || 'B' == *szMe)bIsBE = true;
148 #endif // ! AI_BUILD_BIG_ENDIAN
150 // skip the line, parse the rest of the header and build the DOM
151 SkipLine(szMe,(const char**)&szMe);
152 if(!PLY::DOM::ParseInstanceBinary(szMe,&sPlyDom,bIsBE))
153 throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#2)");
154 }
155 else throw DeadlyImportError( "Invalid .ply file: Unknown file format");
156 }
157 else
158 {
159 delete[] this->mBuffer;
160 AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
161 throw DeadlyImportError( "Invalid .ply file: Missing format specification");
162 }
163 this->pcDOM = &sPlyDom;
165 // now load a list of vertices. This must be sucessfull in order to procede
166 std::vector<aiVector3D> avPositions;
167 this->LoadVertices(&avPositions,false);
169 if (avPositions.empty())
170 throw DeadlyImportError( "Invalid .ply file: No vertices found. "
171 "Unable to parse the data format of the PLY file.");
173 // now load a list of normals.
174 std::vector<aiVector3D> avNormals;
175 LoadVertices(&avNormals,true);
177 // load the face list
178 std::vector<PLY::Face> avFaces;
179 LoadFaces(&avFaces);
181 // if no face list is existing we assume that the vertex
182 // list is containing a list of triangles
183 if (avFaces.empty())
184 {
185 if (avPositions.size() < 3)
186 {
187 throw DeadlyImportError( "Invalid .ply file: Not enough "
188 "vertices to build a proper face list. ");
189 }
191 const unsigned int iNum = (unsigned int)avPositions.size() / 3;
192 for (unsigned int i = 0; i< iNum;++i)
193 {
194 PLY::Face sFace;
195 sFace.mIndices.push_back((iNum*3));
196 sFace.mIndices.push_back((iNum*3)+1);
197 sFace.mIndices.push_back((iNum*3)+2);
198 avFaces.push_back(sFace);
199 }
200 }
202 // now load a list of all materials
203 std::vector<aiMaterial*> avMaterials;
204 LoadMaterial(&avMaterials);
206 // now load a list of all vertex color channels
207 std::vector<aiColor4D> avColors;
208 avColors.reserve(avPositions.size());
209 LoadVertexColor(&avColors);
211 // now try to load texture coordinates
212 std::vector<aiVector2D> avTexCoords;
213 avTexCoords.reserve(avPositions.size());
214 LoadTextureCoordinates(&avTexCoords);
216 // now replace the default material in all faces and validate all material indices
217 ReplaceDefaultMaterial(&avFaces,&avMaterials);
219 // now convert this to a list of aiMesh instances
220 std::vector<aiMesh*> avMeshes;
221 avMeshes.reserve(avMaterials.size()+1);
222 ConvertMeshes(&avFaces,&avPositions,&avNormals,
223 &avColors,&avTexCoords,&avMaterials,&avMeshes);
225 if (avMeshes.empty())
226 throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data ");
228 // now generate the output scene object. Fill the material list
229 pScene->mNumMaterials = (unsigned int)avMaterials.size();
230 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
231 for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
232 pScene->mMaterials[i] = avMaterials[i];
234 // fill the mesh list
235 pScene->mNumMeshes = (unsigned int)avMeshes.size();
236 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
237 for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
238 pScene->mMeshes[i] = avMeshes[i];
240 // generate a simple node structure
241 pScene->mRootNode = new aiNode();
242 pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
243 pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
245 for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes;++i)
246 pScene->mRootNode->mMeshes[i] = i;
247 }
249 // ------------------------------------------------------------------------------------------------
250 // Split meshes by material IDs
251 void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
252 const std::vector<aiVector3D>* avPositions,
253 const std::vector<aiVector3D>* avNormals,
254 const std::vector<aiColor4D>* avColors,
255 const std::vector<aiVector2D>* avTexCoords,
256 const std::vector<aiMaterial*>* avMaterials,
257 std::vector<aiMesh*>* avOut)
258 {
259 ai_assert(NULL != avFaces);
260 ai_assert(NULL != avPositions);
261 ai_assert(NULL != avMaterials);
263 // split by materials
264 std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[avMaterials->size()];
266 unsigned int iNum = 0;
267 for (std::vector<PLY::Face>::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum)
268 aiSplit[(*i).iMaterialIndex].push_back(iNum);
270 // now generate submeshes
271 for (unsigned int p = 0; p < avMaterials->size();++p)
272 {
273 if (aiSplit[p].size() != 0)
274 {
275 // allocate the mesh object
276 aiMesh* p_pcOut = new aiMesh();
277 p_pcOut->mMaterialIndex = p;
279 p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
280 p_pcOut->mFaces = new aiFace[aiSplit[p].size()];
282 // at first we need to determine the size of the output vector array
283 unsigned int iNum = 0;
284 for (unsigned int i = 0; i < aiSplit[p].size();++i)
285 {
286 iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size();
287 }
288 p_pcOut->mNumVertices = iNum;
289 p_pcOut->mVertices = new aiVector3D[iNum];
291 if (!avColors->empty())
292 p_pcOut->mColors[0] = new aiColor4D[iNum];
293 if (!avTexCoords->empty())
294 {
295 p_pcOut->mNumUVComponents[0] = 2;
296 p_pcOut->mTextureCoords[0] = new aiVector3D[iNum];
297 }
298 if (!avNormals->empty())
299 p_pcOut->mNormals = new aiVector3D[iNum];
301 // add all faces
302 iNum = 0;
303 unsigned int iVertex = 0;
304 for (std::vector<unsigned int>::const_iterator i = aiSplit[p].begin();
305 i != aiSplit[p].end();++i,++iNum)
306 {
307 p_pcOut->mFaces[iNum].mNumIndices = (unsigned int)(*avFaces)[*i].mIndices.size();
308 p_pcOut->mFaces[iNum].mIndices = new unsigned int[p_pcOut->mFaces[iNum].mNumIndices];
310 // build an unique set of vertices/colors for this face
311 for (unsigned int q = 0; q < p_pcOut->mFaces[iNum].mNumIndices;++q)
312 {
313 p_pcOut->mFaces[iNum].mIndices[q] = iVertex;
314 p_pcOut->mVertices[iVertex] = (*avPositions)[(*avFaces)[*i].mIndices[q]];
316 if (!avColors->empty())
317 p_pcOut->mColors[0][iVertex] = (*avColors)[(*avFaces)[*i].mIndices[q]];
319 if (!avTexCoords->empty())
320 {
321 const aiVector2D& vec = (*avTexCoords)[(*avFaces)[*i].mIndices[q]];
322 p_pcOut->mTextureCoords[0][iVertex].x = vec.x;
323 p_pcOut->mTextureCoords[0][iVertex].y = vec.y;
324 }
326 if (!avNormals->empty())
327 p_pcOut->mNormals[iVertex] = (*avNormals)[(*avFaces)[*i].mIndices[q]];
328 iVertex++;
329 }
331 }
332 // add the mesh to the output list
333 avOut->push_back(p_pcOut);
334 }
335 }
336 delete[] aiSplit; // cleanup
337 }
339 // ------------------------------------------------------------------------------------------------
340 // Generate a default material if none was specified and apply it to all vanilla faces
341 void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
342 std::vector<aiMaterial*>* avMaterials)
343 {
344 bool bNeedDefaultMat = false;
346 for (std::vector<PLY::Face>::iterator i = avFaces->begin();i != avFaces->end();++i) {
347 if (0xFFFFFFFF == (*i).iMaterialIndex) {
348 bNeedDefaultMat = true;
349 (*i).iMaterialIndex = (unsigned int)avMaterials->size();
350 }
351 else if ((*i).iMaterialIndex >= avMaterials->size() ) {
352 // clamp the index
353 (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1;
354 }
355 }
357 if (bNeedDefaultMat) {
358 // generate a default material
359 aiMaterial* pcHelper = new aiMaterial();
361 // fill in a default material
362 int iMode = (int)aiShadingMode_Gouraud;
363 pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
365 aiColor3D clr;
366 clr.b = clr.g = clr.r = 0.6f;
367 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
368 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
370 clr.b = clr.g = clr.r = 0.05f;
371 pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
373 // The face order is absolutely undefined for PLY, so we have to
374 // use two-sided rendering to be sure it's ok.
375 const int two_sided = 1;
376 pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
378 avMaterials->push_back(pcHelper);
379 }
380 }
382 // ------------------------------------------------------------------------------------------------
383 void PLYImporter::LoadTextureCoordinates(std::vector<aiVector2D>* pvOut)
384 {
385 ai_assert(NULL != pvOut);
387 unsigned int aiPositions[2] = {0xFFFFFFFF,0xFFFFFFFF};
388 PLY::EDataType aiTypes[2] = {EDT_Char,EDT_Char};
389 PLY::ElementInstanceList* pcList = NULL;
390 unsigned int cnt = 0;
392 // serach in the DOM for a vertex entry
393 unsigned int _i = 0;
394 for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
395 i != pcDOM->alElements.end();++i,++_i)
396 {
397 if (PLY::EEST_Vertex == (*i).eSemantic)
398 {
399 pcList = &this->pcDOM->alElementData[_i];
401 // now check whether which normal components are available
402 unsigned int _a = 0;
403 for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
404 a != (*i).alProperties.end();++a,++_a)
405 {
406 if ((*a).bIsList)continue;
407 if (PLY::EST_UTextureCoord == (*a).Semantic)
408 {
409 cnt++;
410 aiPositions[0] = _a;
411 aiTypes[0] = (*a).eType;
412 }
413 else if (PLY::EST_VTextureCoord == (*a).Semantic)
414 {
415 cnt++;
416 aiPositions[1] = _a;
417 aiTypes[1] = (*a).eType;
418 }
419 }
420 }
421 }
422 // check whether we have a valid source for the texture coordinates data
423 if (NULL != pcList && 0 != cnt)
424 {
425 pvOut->reserve(pcList->alInstances.size());
426 for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
427 i != pcList->alInstances.end();++i)
428 {
429 // convert the vertices to sp floats
430 aiVector2D vOut;
432 if (0xFFFFFFFF != aiPositions[0])
433 {
434 vOut.x = PLY::PropertyInstance::ConvertTo<float>(
435 (*i).alProperties[aiPositions[0]].avList.front(),aiTypes[0]);
436 }
438 if (0xFFFFFFFF != aiPositions[1])
439 {
440 vOut.y = PLY::PropertyInstance::ConvertTo<float>(
441 (*i).alProperties[aiPositions[1]].avList.front(),aiTypes[1]);
442 }
443 // and add them to our nice list
444 pvOut->push_back(vOut);
445 }
446 }
447 }
449 // ------------------------------------------------------------------------------------------------
450 // Try to extract vertices from the PLY DOM
451 void PLYImporter::LoadVertices(std::vector<aiVector3D>* pvOut, bool p_bNormals)
452 {
453 ai_assert(NULL != pvOut);
455 unsigned int aiPositions[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
456 PLY::EDataType aiTypes[3] = {EDT_Char,EDT_Char,EDT_Char};
457 PLY::ElementInstanceList* pcList = NULL;
458 unsigned int cnt = 0;
460 // serach in the DOM for a vertex entry
461 unsigned int _i = 0;
462 for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
463 i != pcDOM->alElements.end();++i,++_i)
464 {
465 if (PLY::EEST_Vertex == (*i).eSemantic)
466 {
467 pcList = &pcDOM->alElementData[_i];
469 // load normal vectors?
470 if (p_bNormals)
471 {
472 // now check whether which normal components are available
473 unsigned int _a = 0;
474 for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
475 a != (*i).alProperties.end();++a,++_a)
476 {
477 if ((*a).bIsList)continue;
478 if (PLY::EST_XNormal == (*a).Semantic)
479 {
480 cnt++;
481 aiPositions[0] = _a;
482 aiTypes[0] = (*a).eType;
483 }
484 else if (PLY::EST_YNormal == (*a).Semantic)
485 {
486 cnt++;
487 aiPositions[1] = _a;
488 aiTypes[1] = (*a).eType;
489 }
490 else if (PLY::EST_ZNormal == (*a).Semantic)
491 {
492 cnt++;
493 aiPositions[2] = _a;
494 aiTypes[2] = (*a).eType;
495 }
496 }
497 }
498 // load vertex coordinates
499 else
500 {
501 // now check whether which coordinate sets are available
502 unsigned int _a = 0;
503 for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
504 a != (*i).alProperties.end();++a,++_a)
505 {
506 if ((*a).bIsList)continue;
507 if (PLY::EST_XCoord == (*a).Semantic)
508 {
509 cnt++;
510 aiPositions[0] = _a;
511 aiTypes[0] = (*a).eType;
512 }
513 else if (PLY::EST_YCoord == (*a).Semantic)
514 {
515 cnt++;
516 aiPositions[1] = _a;
517 aiTypes[1] = (*a).eType;
518 }
519 else if (PLY::EST_ZCoord == (*a).Semantic)
520 {
521 cnt++;
522 aiPositions[2] = _a;
523 aiTypes[2] = (*a).eType;
524 }
525 if (3 == cnt)break;
526 }
527 }
528 break;
529 }
530 }
531 // check whether we have a valid source for the vertex data
532 if (NULL != pcList && 0 != cnt)
533 {
534 pvOut->reserve(pcList->alInstances.size());
535 for (std::vector<ElementInstance>::const_iterator
536 i = pcList->alInstances.begin();
537 i != pcList->alInstances.end();++i)
538 {
539 // convert the vertices to sp floats
540 aiVector3D vOut;
542 if (0xFFFFFFFF != aiPositions[0])
543 {
544 vOut.x = PLY::PropertyInstance::ConvertTo<float>(
545 (*i).alProperties[aiPositions[0]].avList.front(),aiTypes[0]);
546 }
548 if (0xFFFFFFFF != aiPositions[1])
549 {
550 vOut.y = PLY::PropertyInstance::ConvertTo<float>(
551 (*i).alProperties[aiPositions[1]].avList.front(),aiTypes[1]);
552 }
554 if (0xFFFFFFFF != aiPositions[2])
555 {
556 vOut.z = PLY::PropertyInstance::ConvertTo<float>(
557 (*i).alProperties[aiPositions[2]].avList.front(),aiTypes[2]);
558 }
560 // and add them to our nice list
561 pvOut->push_back(vOut);
562 }
563 }
564 }
566 // ------------------------------------------------------------------------------------------------
567 // Convert a color component to [0...1]
568 float PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val,
569 PLY::EDataType eType)
570 {
571 switch (eType)
572 {
573 case EDT_Float:
574 return val.fFloat;
575 case EDT_Double:
576 return (float)val.fDouble;
578 case EDT_UChar:
579 return (float)val.iUInt / (float)0xFF;
580 case EDT_Char:
581 return (float)(val.iInt+(0xFF/2)) / (float)0xFF;
582 case EDT_UShort:
583 return (float)val.iUInt / (float)0xFFFF;
584 case EDT_Short:
585 return (float)(val.iInt+(0xFFFF/2)) / (float)0xFFFF;
586 case EDT_UInt:
587 return (float)val.iUInt / (float)0xFFFF;
588 case EDT_Int:
589 return ((float)val.iInt / (float)0xFF) + 0.5f;
590 default: ;
591 };
592 return 0.0f;
593 }
595 // ------------------------------------------------------------------------------------------------
596 // Try to extract proper vertex colors from the PLY DOM
597 void PLYImporter::LoadVertexColor(std::vector<aiColor4D>* pvOut)
598 {
599 ai_assert(NULL != pvOut);
601 unsigned int aiPositions[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
602 PLY::EDataType aiTypes[4] = {EDT_Char, EDT_Char, EDT_Char, EDT_Char}; // silencing gcc
603 unsigned int cnt = 0;
604 PLY::ElementInstanceList* pcList = NULL;
606 // serach in the DOM for a vertex entry
607 unsigned int _i = 0;
608 for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
609 i != pcDOM->alElements.end();++i,++_i)
610 {
611 if (PLY::EEST_Vertex == (*i).eSemantic)
612 {
613 pcList = &this->pcDOM->alElementData[_i];
615 // now check whether which coordinate sets are available
616 unsigned int _a = 0;
617 for (std::vector<PLY::Property>::const_iterator
618 a = (*i).alProperties.begin();
619 a != (*i).alProperties.end();++a,++_a)
620 {
621 if ((*a).bIsList)continue;
622 if (PLY::EST_Red == (*a).Semantic)
623 {
624 cnt++;
625 aiPositions[0] = _a;
626 aiTypes[0] = (*a).eType;
627 }
628 else if (PLY::EST_Green == (*a).Semantic)
629 {
630 cnt++;
631 aiPositions[1] = _a;
632 aiTypes[1] = (*a).eType;
633 }
634 else if (PLY::EST_Blue == (*a).Semantic)
635 {
636 cnt++;
637 aiPositions[2] = _a;
638 aiTypes[2] = (*a).eType;
639 }
640 else if (PLY::EST_Alpha == (*a).Semantic)
641 {
642 cnt++;
643 aiPositions[3] = _a;
644 aiTypes[3] = (*a).eType;
645 }
646 if (4 == cnt)break;
647 }
648 break;
649 }
650 }
651 // check whether we have a valid source for the vertex data
652 if (NULL != pcList && 0 != cnt)
653 {
654 pvOut->reserve(pcList->alInstances.size());
655 for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
656 i != pcList->alInstances.end();++i)
657 {
658 // convert the vertices to sp floats
659 aiColor4D vOut;
661 if (0xFFFFFFFF != aiPositions[0])
662 {
663 vOut.r = NormalizeColorValue((*i).alProperties[
664 aiPositions[0]].avList.front(),aiTypes[0]);
665 }
667 if (0xFFFFFFFF != aiPositions[1])
668 {
669 vOut.g = NormalizeColorValue((*i).alProperties[
670 aiPositions[1]].avList.front(),aiTypes[1]);
671 }
673 if (0xFFFFFFFF != aiPositions[2])
674 {
675 vOut.b = NormalizeColorValue((*i).alProperties[
676 aiPositions[2]].avList.front(),aiTypes[2]);
677 }
679 // assume 1.0 for the alpha channel ifit is not set
680 if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0f;
681 else
682 {
683 vOut.a = NormalizeColorValue((*i).alProperties[
684 aiPositions[3]].avList.front(),aiTypes[3]);
685 }
687 // and add them to our nice list
688 pvOut->push_back(vOut);
689 }
690 }
691 }
693 // ------------------------------------------------------------------------------------------------
694 // Try to extract proper faces from the PLY DOM
695 void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
696 {
697 ai_assert(NULL != pvOut);
699 PLY::ElementInstanceList* pcList = NULL;
700 bool bOne = false;
702 // index of the vertex index list
703 unsigned int iProperty = 0xFFFFFFFF;
704 PLY::EDataType eType = EDT_Char;
705 bool bIsTristrip = false;
707 // index of the material index property
708 unsigned int iMaterialIndex = 0xFFFFFFFF;
709 PLY::EDataType eType2 = EDT_Char;
711 // serach in the DOM for a face entry
712 unsigned int _i = 0;
713 for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
714 i != pcDOM->alElements.end();++i,++_i)
715 {
716 // face = unique number of vertex indices
717 if (PLY::EEST_Face == (*i).eSemantic)
718 {
719 pcList = &pcDOM->alElementData[_i];
720 unsigned int _a = 0;
721 for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
722 a != (*i).alProperties.end();++a,++_a)
723 {
724 if (PLY::EST_VertexIndex == (*a).Semantic)
725 {
726 // must be a dynamic list!
727 if (!(*a).bIsList)continue;
728 iProperty = _a;
729 bOne = true;
730 eType = (*a).eType;
731 }
732 else if (PLY::EST_MaterialIndex == (*a).Semantic)
733 {
734 if ((*a).bIsList)continue;
735 iMaterialIndex = _a;
736 bOne = true;
737 eType2 = (*a).eType;
738 }
739 }
740 break;
741 }
742 // triangle strip
743 // TODO: triangle strip and material index support???
744 else if (PLY::EEST_TriStrip == (*i).eSemantic)
745 {
746 // find a list property in this ...
747 pcList = &this->pcDOM->alElementData[_i];
748 unsigned int _a = 0;
749 for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
750 a != (*i).alProperties.end();++a,++_a)
751 {
752 // must be a dynamic list!
753 if (!(*a).bIsList)continue;
754 iProperty = _a;
755 bOne = true;
756 bIsTristrip = true;
757 eType = (*a).eType;
758 break;
759 }
760 break;
761 }
762 }
763 // check whether we have at least one per-face information set
764 if (pcList && bOne)
765 {
766 if (!bIsTristrip)
767 {
768 pvOut->reserve(pcList->alInstances.size());
769 for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
770 i != pcList->alInstances.end();++i)
771 {
772 PLY::Face sFace;
774 // parse the list of vertex indices
775 if (0xFFFFFFFF != iProperty)
776 {
777 const unsigned int iNum = (unsigned int)(*i).alProperties[iProperty].avList.size();
778 sFace.mIndices.resize(iNum);
780 std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
781 (*i).alProperties[iProperty].avList.begin();
783 for (unsigned int a = 0; a < iNum;++a,++p)
784 {
785 sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p,eType);
786 }
787 }
789 // parse the material index
790 if (0xFFFFFFFF != iMaterialIndex)
791 {
792 sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo<unsigned int>(
793 (*i).alProperties[iMaterialIndex].avList.front(),eType2);
794 }
795 pvOut->push_back(sFace);
796 }
797 }
798 else // triangle strips
799 {
800 // normally we have only one triangle strip instance where
801 // a value of -1 indicates a restart of the strip
802 bool flip = false;
803 for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
804 const std::vector<PLY::PropertyInstance::ValueUnion>& quak = (*i).alProperties[iProperty].avList;
805 pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u));
807 int aiTable[2] = {-1,-1};
808 for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin();a != quak.end();++a) {
809 const int p = PLY::PropertyInstance::ConvertTo<int>(*a,eType);
811 if (-1 == p) {
812 // restart the strip ...
813 aiTable[0] = aiTable[1] = -1;
814 flip = false;
815 continue;
816 }
817 if (-1 == aiTable[0]) {
818 aiTable[0] = p;
819 continue;
820 }
821 if (-1 == aiTable[1]) {
822 aiTable[1] = p;
823 continue;
824 }
826 pvOut->push_back(PLY::Face());
827 PLY::Face& sFace = pvOut->back();
828 sFace.mIndices[0] = aiTable[0];
829 sFace.mIndices[1] = aiTable[1];
830 sFace.mIndices[2] = p;
831 if ((flip = !flip)) {
832 std::swap(sFace.mIndices[0],sFace.mIndices[1]);
833 }
835 aiTable[0] = aiTable[1];
836 aiTable[1] = p;
837 }
838 }
839 }
840 }
841 }
843 // ------------------------------------------------------------------------------------------------
844 // Get a RGBA color in [0...1] range
845 void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
846 unsigned int aiPositions[4],
847 PLY::EDataType aiTypes[4],
848 aiColor4D* clrOut)
849 {
850 ai_assert(NULL != clrOut);
852 if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
853 else
854 {
855 clrOut->r = NormalizeColorValue(avList[
856 aiPositions[0]].avList.front(),aiTypes[0]);
857 }
859 if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
860 else
861 {
862 clrOut->g = NormalizeColorValue(avList[
863 aiPositions[1]].avList.front(),aiTypes[1]);
864 }
866 if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
867 else
868 {
869 clrOut->b = NormalizeColorValue(avList[
870 aiPositions[2]].avList.front(),aiTypes[2]);
871 }
873 // assume 1.0 for the alpha channel ifit is not set
874 if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
875 else
876 {
877 clrOut->a = NormalizeColorValue(avList[
878 aiPositions[3]].avList.front(),aiTypes[3]);
879 }
880 }
882 // ------------------------------------------------------------------------------------------------
883 // Extract a material from the PLY DOM
884 void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
885 {
886 ai_assert(NULL != pvOut);
888 // diffuse[4], specular[4], ambient[4]
889 // rgba order
890 unsigned int aaiPositions[3][4] = {
892 {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
893 {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
894 {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
895 };
897 PLY::EDataType aaiTypes[3][4] = {
898 {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
899 {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
900 {EDT_Char,EDT_Char,EDT_Char,EDT_Char}
901 };
902 PLY::ElementInstanceList* pcList = NULL;
904 unsigned int iPhong = 0xFFFFFFFF;
905 PLY::EDataType ePhong = EDT_Char;
907 unsigned int iOpacity = 0xFFFFFFFF;
908 PLY::EDataType eOpacity = EDT_Char;
910 // serach in the DOM for a vertex entry
911 unsigned int _i = 0;
912 for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
913 i != this->pcDOM->alElements.end();++i,++_i)
914 {
915 if (PLY::EEST_Material == (*i).eSemantic)
916 {
917 pcList = &this->pcDOM->alElementData[_i];
919 // now check whether which coordinate sets are available
920 unsigned int _a = 0;
921 for (std::vector<PLY::Property>::const_iterator
922 a = (*i).alProperties.begin();
923 a != (*i).alProperties.end();++a,++_a)
924 {
925 if ((*a).bIsList)continue;
927 // pohng specularity -----------------------------------
928 if (PLY::EST_PhongPower == (*a).Semantic)
929 {
930 iPhong = _a;
931 ePhong = (*a).eType;
932 }
934 // general opacity -----------------------------------
935 if (PLY::EST_Opacity == (*a).Semantic)
936 {
937 iOpacity = _a;
938 eOpacity = (*a).eType;
939 }
941 // diffuse color channels -----------------------------------
942 if (PLY::EST_DiffuseRed == (*a).Semantic)
943 {
944 aaiPositions[0][0] = _a;
945 aaiTypes[0][0] = (*a).eType;
946 }
947 else if (PLY::EST_DiffuseGreen == (*a).Semantic)
948 {
949 aaiPositions[0][1] = _a;
950 aaiTypes[0][1] = (*a).eType;
951 }
952 else if (PLY::EST_DiffuseBlue == (*a).Semantic)
953 {
954 aaiPositions[0][2] = _a;
955 aaiTypes[0][2] = (*a).eType;
956 }
957 else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
958 {
959 aaiPositions[0][3] = _a;
960 aaiTypes[0][3] = (*a).eType;
961 }
962 // specular color channels -----------------------------------
963 else if (PLY::EST_SpecularRed == (*a).Semantic)
964 {
965 aaiPositions[1][0] = _a;
966 aaiTypes[1][0] = (*a).eType;
967 }
968 else if (PLY::EST_SpecularGreen == (*a).Semantic)
969 {
970 aaiPositions[1][1] = _a;
971 aaiTypes[1][1] = (*a).eType;
972 }
973 else if (PLY::EST_SpecularBlue == (*a).Semantic)
974 {
975 aaiPositions[1][2] = _a;
976 aaiTypes[1][2] = (*a).eType;
977 }
978 else if (PLY::EST_SpecularAlpha == (*a).Semantic)
979 {
980 aaiPositions[1][3] = _a;
981 aaiTypes[1][3] = (*a).eType;
982 }
983 // ambient color channels -----------------------------------
984 else if (PLY::EST_AmbientRed == (*a).Semantic)
985 {
986 aaiPositions[2][0] = _a;
987 aaiTypes[2][0] = (*a).eType;
988 }
989 else if (PLY::EST_AmbientGreen == (*a).Semantic)
990 {
991 aaiPositions[2][1] = _a;
992 aaiTypes[2][1] = (*a).eType;
993 }
994 else if (PLY::EST_AmbientBlue == (*a).Semantic)
995 {
996 aaiPositions[2][2] = _a;
997 aaiTypes[2][2] = (*a).eType;
998 }
999 else if (PLY::EST_AmbientAlpha == (*a).Semantic)
1001 aaiPositions[2][3] = _a;
1002 aaiTypes[2][3] = (*a).eType;
1005 break;
1008 // check whether we have a valid source for the material data
1009 if (NULL != pcList) {
1010 for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
1011 aiColor4D clrOut;
1012 aiMaterial* pcHelper = new aiMaterial();
1014 // build the diffuse material color
1015 GetMaterialColor((*i).alProperties,aaiPositions[0],aaiTypes[0],&clrOut);
1016 pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE);
1018 // build the specular material color
1019 GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut);
1020 pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_SPECULAR);
1022 // build the ambient material color
1023 GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut);
1024 pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_AMBIENT);
1026 // handle phong power and shading mode
1027 int iMode;
1028 if (0xFFFFFFFF != iPhong) {
1029 float fSpec = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),ePhong);
1031 // if shininess is 0 (and the pow() calculation would therefore always
1032 // become 1, not depending on the angle), use gouraud lighting
1033 if (fSpec) {
1034 // scale this with 15 ... hopefully this is correct
1035 fSpec *= 15;
1036 pcHelper->AddProperty<float>(&fSpec, 1, AI_MATKEY_SHININESS);
1038 iMode = (int)aiShadingMode_Phong;
1040 else iMode = (int)aiShadingMode_Gouraud;
1042 else iMode = (int)aiShadingMode_Gouraud;
1043 pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
1045 // handle opacity
1046 if (0xFFFFFFFF != iOpacity) {
1047 float fOpacity = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),eOpacity);
1048 pcHelper->AddProperty<float>(&fOpacity, 1, AI_MATKEY_OPACITY);
1051 // The face order is absolutely undefined for PLY, so we have to
1052 // use two-sided rendering to be sure it's ok.
1053 const int two_sided = 1;
1054 pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
1056 // add the newly created material instance to the list
1057 pvOut->push_back(pcHelper);
1062 #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER