vrshoot
view libs/assimp/XGLLoader.cpp @ 1:e7ca128b8713
looks nice :)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Feb 2014 00:35:22 +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 XGL/ZGL importer class */
44 #include "AssimpPCH.h"
45 #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
47 #include "XGLLoader.h"
48 #include "ParsingUtils.h"
49 #include "fast_atof.h"
51 #include "StreamReader.h"
52 #include "MemoryIOWrapper.h"
54 using namespace Assimp;
55 using namespace irr;
56 using namespace irr::io;
59 // zlib is needed for compressed XGL files
60 #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
61 # ifdef ASSIMP_BUILD_NO_OWN_ZLIB
62 # include <zlib.h>
63 # else
64 # include "../contrib/zlib/zlib.h"
65 # endif
66 #endif
69 // scopeguard for a malloc'ed buffer
70 struct free_it
71 {
72 free_it(void* free) : free(free) {}
73 ~free_it() {
74 ::free(this->free);
75 }
77 void* free;
78 };
80 namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
81 template<> const std::string LogFunctions<XGLImporter>::log_prefix = "XGL: ";
83 }
85 static const aiImporterDesc desc = {
86 "XGL Importer",
87 "",
88 "",
89 "",
90 aiImporterFlags_SupportTextFlavour,
91 0,
92 0,
93 0,
94 0,
95 "xgl zgl"
96 };
99 // ------------------------------------------------------------------------------------------------
100 // Constructor to be privately used by Importer
101 XGLImporter::XGLImporter()
102 {}
104 // ------------------------------------------------------------------------------------------------
105 // Destructor, private as well
106 XGLImporter::~XGLImporter()
107 {}
109 // ------------------------------------------------------------------------------------------------
110 // Returns whether the class can handle the format of the given file.
111 bool XGLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
112 {
113 /* NOTE: A simple check for the file extension is not enough
114 * here. XGL and ZGL are ok, but xml is too generic
115 * and might be collada as well. So open the file and
116 * look for typical signal tokens.
117 */
118 const std::string extension = GetExtension(pFile);
120 if (extension == "xgl" || extension == "zgl") {
121 return true;
122 }
123 else if (extension == "xml" || checkSig) {
124 ai_assert(pIOHandler != NULL);
126 const char* tokens[] = {"<world>","<World>","<WORLD>"};
127 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,3);
128 }
129 return false;
130 }
132 // ------------------------------------------------------------------------------------------------
133 // Get a list of all file extensions which are handled by this class
134 const aiImporterDesc* XGLImporter::GetInfo () const
135 {
136 return &desc;
137 }
139 // ------------------------------------------------------------------------------------------------
140 // Imports the given file into the given scene structure.
141 void XGLImporter::InternReadFile( const std::string& pFile,
142 aiScene* pScene, IOSystem* pIOHandler)
143 {
144 #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
145 Bytef* dest = NULL;
146 free_it free_it_really(dest);
147 #endif
149 scene = pScene;
150 boost::shared_ptr<IOStream> stream( pIOHandler->Open( pFile, "rb"));
152 // check whether we can read from the file
153 if( stream.get() == NULL) {
154 throw DeadlyImportError( "Failed to open XGL/ZGL file " + pFile + "");
155 }
157 // see if its compressed, if so uncompress it
158 if (GetExtension(pFile) == "zgl") {
159 #ifdef ASSIMP_BUILD_NO_COMPRESSED_XGL
160 ThrowException("Cannot read ZGL file since Assimp was built without compression support");
161 #else
162 boost::scoped_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));
164 // build a zlib stream
165 z_stream zstream;
166 zstream.opaque = Z_NULL;
167 zstream.zalloc = Z_NULL;
168 zstream.zfree = Z_NULL;
169 zstream.data_type = Z_BINARY;
171 // raw decompression without a zlib or gzip header
172 inflateInit2(&zstream, -MAX_WBITS);
174 // skip two extra bytes, zgl files do carry a crc16 upfront (I think)
175 raw_reader->IncPtr(2);
177 zstream.next_in = reinterpret_cast<Bytef*>( raw_reader->GetPtr() );
178 zstream.avail_in = raw_reader->GetRemainingSize();
180 size_t total = 0l;
182 // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
183 #define MYBLOCK 1024
184 Bytef block[MYBLOCK];
185 int ret;
186 do {
187 zstream.avail_out = MYBLOCK;
188 zstream.next_out = block;
189 ret = inflate(&zstream, Z_NO_FLUSH);
191 if (ret != Z_STREAM_END && ret != Z_OK) {
192 ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .XGL file");
193 }
194 const size_t have = MYBLOCK - zstream.avail_out;
195 total += have;
196 dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
197 memcpy(dest + total - have,block,have);
198 }
199 while (ret != Z_STREAM_END);
201 // terminate zlib
202 inflateEnd(&zstream);
204 // replace the input stream with a memory stream
205 stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
206 #endif
207 }
209 // construct the irrXML parser
210 CIrrXML_IOStreamReader st(stream.get());
211 boost::scoped_ptr<IrrXMLReader> read( createIrrXMLReader((IFileReadCallBack*) &st) );
212 reader = read.get();
214 // parse the XML file
215 TempScope scope;
217 while (ReadElement()) {
218 if (!ASSIMP_stricmp(reader->getNodeName(),"world")) {
219 ReadWorld(scope);
220 }
221 }
224 std::vector<aiMesh*>& meshes = scope.meshes_linear;
225 std::vector<aiMaterial*>& materials = scope.materials_linear;
226 if(!meshes.size() || !materials.size()) {
227 ThrowException("failed to extract data from XGL file, no meshes loaded");
228 }
230 // copy meshes
231 scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
232 scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
233 std::copy(meshes.begin(),meshes.end(),scene->mMeshes);
235 // copy materials
236 scene->mNumMaterials = static_cast<unsigned int>(materials.size());
237 scene->mMaterials = new aiMaterial*[scene->mNumMaterials]();
238 std::copy(materials.begin(),materials.end(),scene->mMaterials);
240 if (scope.light) {
241 scene->mNumLights = 1;
242 scene->mLights = new aiLight*[1];
243 scene->mLights[0] = scope.light;
245 scope.light->mName = scene->mRootNode->mName;
246 }
248 scope.dismiss();
249 }
251 // ------------------------------------------------------------------------------------------------
252 bool XGLImporter::ReadElement()
253 {
254 while(reader->read()) {
255 if (reader->getNodeType() == EXN_ELEMENT) {
256 return true;
257 }
258 }
259 return false;
260 }
262 // ------------------------------------------------------------------------------------------------
263 bool XGLImporter::ReadElementUpToClosing(const char* closetag)
264 {
265 while(reader->read()) {
266 if (reader->getNodeType() == EXN_ELEMENT) {
267 return true;
268 }
269 else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),closetag)) {
270 return false;
271 }
272 }
273 LogError("unexpected EOF, expected closing <" + std::string(closetag) + "> tag");
274 return false;
275 }
277 // ------------------------------------------------------------------------------------------------
278 bool XGLImporter::SkipToText()
279 {
280 while(reader->read()) {
281 if (reader->getNodeType() == EXN_TEXT) {
282 return true;
283 }
284 else if (reader->getNodeType() == EXN_ELEMENT || reader->getNodeType() == EXN_ELEMENT_END) {
285 ThrowException("expected text contents but found another element (or element end)");
286 }
287 }
288 return false;
289 }
291 // ------------------------------------------------------------------------------------------------
292 std::string XGLImporter::GetElementName()
293 {
294 const char* s = reader->getNodeName();
295 size_t len = strlen(s);
297 std::string ret;
298 ret.resize(len);
300 std::transform(s,s+len,ret.begin(),::tolower);
301 return ret;
302 }
304 // ------------------------------------------------------------------------------------------------
305 void XGLImporter::ReadWorld(TempScope& scope)
306 {
307 while (ReadElementUpToClosing("world")) {
308 const std::string& s = GetElementName();
309 // XXX right now we'd skip <lighting> if it comes after
310 // <object> or <mesh>
311 if (s == "lighting") {
312 ReadLighting(scope);
313 }
314 else if (s == "object" || s == "mesh" || s == "mat") {
315 break;
316 }
317 }
320 aiNode* const nd = ReadObject(scope,true,"world");
321 if(!nd) {
322 ThrowException("failure reading <world>");
323 }
324 if(!nd->mName.length) {
325 nd->mName.Set("WORLD");
326 }
328 scene->mRootNode = nd;
329 }
331 // ------------------------------------------------------------------------------------------------
332 void XGLImporter::ReadLighting(TempScope& scope)
333 {
334 while (ReadElementUpToClosing("lighting")) {
335 const std::string& s = GetElementName();
336 if (s == "directionallight") {
337 scope.light = ReadDirectionalLight();
338 }
339 else if (s == "ambient") {
340 LogWarn("ignoring <ambient> tag");
341 }
342 else if (s == "spheremap") {
343 LogWarn("ignoring <spheremap> tag");
344 }
345 }
346 }
348 // ------------------------------------------------------------------------------------------------
349 aiLight* XGLImporter::ReadDirectionalLight()
350 {
351 ScopeGuard<aiLight> l(new aiLight());
352 l->mType = aiLightSource_DIRECTIONAL;
354 while (ReadElementUpToClosing("directionallight")) {
355 const std::string& s = GetElementName();
356 if (s == "direction") {
357 l->mDirection = ReadVec3();
358 }
359 else if (s == "diffuse") {
360 l->mColorDiffuse = ReadCol3();
361 }
362 else if (s == "specular") {
363 l->mColorSpecular = ReadCol3();
364 }
365 }
366 return l.dismiss();
367 }
369 // ------------------------------------------------------------------------------------------------
370 aiNode* XGLImporter::ReadObject(TempScope& scope, bool skipFirst, const char* closetag)
371 {
372 ScopeGuard<aiNode> nd(new aiNode());
373 std::vector<aiNode*> children;
374 std::vector<unsigned int> meshes;
376 try {
377 while (skipFirst || ReadElementUpToClosing(closetag)) {
378 skipFirst = false;
380 const std::string& s = GetElementName();
381 if (s == "mesh") {
382 const size_t prev = scope.meshes_linear.size();
383 if(ReadMesh(scope)) {
384 const size_t newc = scope.meshes_linear.size();
385 for(size_t i = 0; i < newc-prev; ++i) {
386 meshes.push_back(static_cast<unsigned int>(i+prev));
387 }
388 }
389 }
390 else if (s == "mat") {
391 ReadMaterial(scope);
392 }
393 else if (s == "object") {
394 children.push_back(ReadObject(scope));
395 }
396 else if (s == "objectref") {
397 // XXX
398 }
399 else if (s == "meshref") {
400 const unsigned int id = static_cast<unsigned int>( ReadIndexFromText() );
402 std::multimap<unsigned int, aiMesh*>::iterator it = scope.meshes.find(id), end = scope.meshes.end();
403 if (it == end) {
404 ThrowException("<meshref> index out of range");
405 }
407 for(; it != end && (*it).first == id; ++it) {
408 // ok, this is n^2 and should get optimized one day
409 aiMesh* const m = (*it).second;
411 unsigned int i = 0, mcount = static_cast<unsigned int>(scope.meshes_linear.size());
412 for(; i < mcount; ++i) {
413 if (scope.meshes_linear[i] == m) {
414 meshes.push_back(i);
415 break;
416 }
417 }
419 ai_assert(i < mcount);
420 }
421 }
422 else if (s == "transform") {
423 nd->mTransformation = ReadTrafo();
424 }
425 }
427 } catch(...) {
428 BOOST_FOREACH(aiNode* ch, children) {
429 delete ch;
430 }
431 throw;
432 }
434 // link meshes to node
435 nd->mNumMeshes = static_cast<unsigned int>(meshes.size());
436 if (nd->mNumMeshes) {
437 nd->mMeshes = new unsigned int[nd->mNumMeshes]();
438 for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
439 nd->mMeshes[i] = meshes[i];
440 }
441 }
443 // link children to parent
444 nd->mNumChildren = static_cast<unsigned int>(children.size());
445 if (nd->mNumChildren) {
446 nd->mChildren = new aiNode*[nd->mNumChildren]();
447 for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
448 nd->mChildren[i] = children[i];
449 children[i]->mParent = nd;
450 }
451 }
453 return nd.dismiss();
454 }
456 // ------------------------------------------------------------------------------------------------
457 aiMatrix4x4 XGLImporter::ReadTrafo()
458 {
459 aiVector3D forward, up, right, position;
460 float scale = 1.0f;
462 while (ReadElementUpToClosing("transform")) {
463 const std::string& s = GetElementName();
464 if (s == "forward") {
465 forward = ReadVec3();
466 }
467 else if (s == "up") {
468 up = ReadVec3();
469 }
470 else if (s == "position") {
471 position = ReadVec3();
472 }
473 if (s == "scale") {
474 scale = ReadFloat();
475 if(scale < 0.f) {
476 // this is wrong, but we can leave the value and pass it to the caller
477 LogError("found negative scaling in <transform>, ignoring");
478 }
479 }
480 }
482 aiMatrix4x4 m;
483 if(forward.SquareLength() < 1e-4 || up.SquareLength() < 1e-4) {
484 LogError("A direction vector in <transform> is zero, ignoring trafo");
485 return m;
486 }
488 forward.Normalize();
489 up.Normalize();
491 right = forward ^ up;
492 if (fabs(up * forward) > 1e-4) {
493 // this is definitely wrong - a degenerate coordinate space ruins everything
494 // so subtitute identity transform.
495 LogError("<forward> and <up> vectors in <transform> are skewing, ignoring trafo");
496 return m;
497 }
499 right *= scale;
500 up *= scale;
501 forward *= scale;
503 m.a1 = right.x;
504 m.b1 = right.y;
505 m.c1 = right.z;
507 m.a2 = up.x;
508 m.b2 = up.y;
509 m.c2 = up.z;
511 m.a3 = forward.x;
512 m.b3 = forward.y;
513 m.c3 = forward.z;
515 m.a4 = position.x;
516 m.b4 = position.y;
517 m.c4 = position.z;
519 return m;
520 }
522 // ------------------------------------------------------------------------------------------------
523 aiMesh* XGLImporter::ToOutputMesh(const TempMaterialMesh& m)
524 {
525 ScopeGuard<aiMesh> mesh(new aiMesh());
527 mesh->mNumVertices = static_cast<unsigned int>(m.positions.size());
528 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
529 std::copy(m.positions.begin(),m.positions.end(),mesh->mVertices);
531 if(m.normals.size()) {
532 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
533 std::copy(m.normals.begin(),m.normals.end(),mesh->mNormals);
534 }
536 if(m.uvs.size()) {
537 mesh->mNumUVComponents[0] = 2;
538 mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
540 for(unsigned int i = 0; i < mesh->mNumVertices; ++i) {
541 mesh->mTextureCoords[0][i] = aiVector3D(m.uvs[i].x,m.uvs[i].y,0.f);
542 }
543 }
545 mesh->mNumFaces = static_cast<unsigned int>(m.vcounts.size());
546 mesh->mFaces = new aiFace[m.vcounts.size()];
548 unsigned int idx = 0;
549 for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
550 aiFace& f = mesh->mFaces[i];
551 f.mNumIndices = m.vcounts[i];
552 f.mIndices = new unsigned int[f.mNumIndices];
553 for(unsigned int c = 0; c < f.mNumIndices; ++c) {
554 f.mIndices[c] = idx++;
555 }
556 }
558 ai_assert(idx == mesh->mNumVertices);
560 mesh->mPrimitiveTypes = m.pflags;
561 mesh->mMaterialIndex = m.matid;
562 return mesh.dismiss();
563 }
565 // ------------------------------------------------------------------------------------------------
566 bool XGLImporter::ReadMesh(TempScope& scope)
567 {
568 TempMesh t;
570 std::map<unsigned int, TempMaterialMesh> bymat;
571 const unsigned int mesh_id = ReadIDAttr();
573 while (ReadElementUpToClosing("mesh")) {
574 const std::string& s = GetElementName();
576 if (s == "mat") {
577 ReadMaterial(scope);
578 }
579 else if (s == "p") {
580 if (!reader->getAttributeValue("ID")) {
581 LogWarn("no ID attribute on <p>, ignoring");
582 }
583 else {
584 int id = reader->getAttributeValueAsInt("ID");
585 t.points[id] = ReadVec3();
586 }
587 }
588 else if (s == "n") {
589 if (!reader->getAttributeValue("ID")) {
590 LogWarn("no ID attribute on <n>, ignoring");
591 }
592 else {
593 int id = reader->getAttributeValueAsInt("ID");
594 t.normals[id] = ReadVec3();
595 }
596 }
597 else if (s == "tc") {
598 if (!reader->getAttributeValue("ID")) {
599 LogWarn("no ID attribute on <tc>, ignoring");
600 }
601 else {
602 int id = reader->getAttributeValueAsInt("ID");
603 t.uvs[id] = ReadVec2();
604 }
605 }
606 else if (s == "f" || s == "l" || s == "p") {
607 const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1);
609 unsigned int mid = ~0u;
610 TempFace tf[3];
611 bool has[3] = {0};
613 while (ReadElementUpToClosing(s.c_str())) {
614 const std::string& s = GetElementName();
615 if (s == "fv1" || s == "lv1" || s == "pv1") {
616 ReadFaceVertex(t,tf[0]);
617 has[0] = true;
618 }
619 else if (s == "fv2" || s == "lv2") {
620 ReadFaceVertex(t,tf[1]);
621 has[1] = true;
622 }
623 else if (s == "fv3") {
624 ReadFaceVertex(t,tf[2]);
625 has[2] = true;
626 }
627 else if (s == "mat") {
628 if (mid != ~0u) {
629 LogWarn("only one material tag allowed per <f>");
630 }
631 mid = ResolveMaterialRef(scope);
632 }
633 else if (s == "matref") {
634 if (mid != ~0u) {
635 LogWarn("only one material tag allowed per <f>");
636 }
637 mid = ResolveMaterialRef(scope);
638 }
639 }
641 if (mid == ~0u) {
642 ThrowException("missing material index");
643 }
645 bool nor = false;
646 bool uv = false;
647 for(unsigned int i = 0; i < vcount; ++i) {
648 if (!has[i]) {
649 ThrowException("missing face vertex data");
650 }
652 nor = nor || tf[i].has_normal;
653 uv = uv || tf[i].has_uv;
654 }
656 if (mid >= (1<<30)) {
657 LogWarn("material indices exhausted, this may cause errors in the output");
658 }
659 unsigned int meshId = mid | ((nor?1:0)<<31) | ((uv?1:0)<<30);
661 TempMaterialMesh& mesh = bymat[meshId];
662 mesh.matid = mid;
664 for(unsigned int i = 0; i < vcount; ++i) {
665 mesh.positions.push_back(tf[i].pos);
666 if(nor) {
667 mesh.normals.push_back(tf[i].normal);
668 }
669 if(uv) {
670 mesh.uvs.push_back(tf[i].uv);
671 }
673 mesh.pflags |= 1 << (vcount-1);
674 }
676 mesh.vcounts.push_back(vcount);
677 }
678 }
680 // finally extract output meshes and add them to the scope
681 typedef std::pair<unsigned int, TempMaterialMesh> pairt;
682 BOOST_FOREACH(const pairt& p, bymat) {
683 aiMesh* const m = ToOutputMesh(p.second);
684 scope.meshes_linear.push_back(m);
686 // if this is a definition, keep it on the stack
687 if(mesh_id != ~0u) {
688 scope.meshes.insert(std::pair<unsigned int, aiMesh*>(mesh_id,m));
689 }
690 }
692 // no id == not a reference, insert this mesh right *here*
693 return mesh_id == ~0u;
694 }
696 // ----------------------------------------------------------------------------------------------
697 unsigned int XGLImporter::ResolveMaterialRef(TempScope& scope)
698 {
699 const std::string& s = GetElementName();
700 if (s == "mat") {
701 ReadMaterial(scope);
702 return scope.materials_linear.size()-1;
703 }
705 const int id = ReadIndexFromText();
707 std::map<unsigned int, aiMaterial*>::iterator it = scope.materials.find(id), end = scope.materials.end();
708 if (it == end) {
709 ThrowException("<matref> index out of range");
710 }
712 // ok, this is n^2 and should get optimized one day
713 aiMaterial* const m = (*it).second;
715 unsigned int i = 0, mcount = static_cast<unsigned int>(scope.materials_linear.size());
716 for(; i < mcount; ++i) {
717 if (scope.materials_linear[i] == m) {
718 return i;
719 }
720 }
722 ai_assert(false);
723 return 0;
724 }
726 // ------------------------------------------------------------------------------------------------
727 void XGLImporter::ReadMaterial(TempScope& scope)
728 {
729 const unsigned int mat_id = ReadIDAttr();
731 ScopeGuard<aiMaterial> mat(new aiMaterial());
732 while (ReadElementUpToClosing("mat")) {
733 const std::string& s = GetElementName();
734 if (s == "amb") {
735 const aiColor3D c = ReadCol3();
736 mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT);
737 }
738 else if (s == "diff") {
739 const aiColor3D c = ReadCol3();
740 mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
741 }
742 else if (s == "spec") {
743 const aiColor3D c = ReadCol3();
744 mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
745 }
746 else if (s == "emiss") {
747 const aiColor3D c = ReadCol3();
748 mat->AddProperty(&c,1,AI_MATKEY_COLOR_EMISSIVE);
749 }
750 else if (s == "alpha") {
751 const float f = ReadFloat();
752 mat->AddProperty(&f,1,AI_MATKEY_OPACITY);
753 }
754 else if (s == "shine") {
755 const float f = ReadFloat();
756 mat->AddProperty(&f,1,AI_MATKEY_SHININESS);
757 }
758 }
760 scope.materials[mat_id] = mat;
761 scope.materials_linear.push_back(mat.dismiss());
762 }
765 // ----------------------------------------------------------------------------------------------
766 void XGLImporter::ReadFaceVertex(const TempMesh& t, TempFace& out)
767 {
768 const std::string& end = GetElementName();
770 bool havep = false;
771 while (ReadElementUpToClosing(end.c_str())) {
772 const std::string& s = GetElementName();
773 if (s == "pref") {
774 const unsigned int id = ReadIndexFromText();
775 std::map<unsigned int, aiVector3D>::const_iterator it = t.points.find(id);
776 if (it == t.points.end()) {
777 ThrowException("point index out of range");
778 }
780 out.pos = (*it).second;
781 havep = true;
782 }
783 else if (s == "nref") {
784 const unsigned int id = ReadIndexFromText();
785 std::map<unsigned int, aiVector3D>::const_iterator it = t.normals.find(id);
786 if (it == t.normals.end()) {
787 ThrowException("normal index out of range");
788 }
790 out.normal = (*it).second;
791 out.has_normal = true;
792 }
793 else if (s == "tcref") {
794 const unsigned int id = ReadIndexFromText();
795 std::map<unsigned int, aiVector2D>::const_iterator it = t.uvs.find(id);
796 if (it == t.uvs.end()) {
797 ThrowException("uv index out of range");
798 }
800 out.uv = (*it).second;
801 out.has_uv = true;
802 }
803 else if (s == "p") {
804 out.pos = ReadVec3();
805 }
806 else if (s == "n") {
807 out.normal = ReadVec3();
808 }
809 else if (s == "tc") {
810 out.uv = ReadVec2();
811 }
812 }
814 if (!havep) {
815 ThrowException("missing <pref> in <fvN> element");
816 }
817 }
819 // ------------------------------------------------------------------------------------------------
820 unsigned int XGLImporter::ReadIDAttr()
821 {
822 for(int i = 0, e = reader->getAttributeCount(); i < e; ++i) {
824 if(!ASSIMP_stricmp(reader->getAttributeName(i),"id")) {
825 return reader->getAttributeValueAsInt(i);
826 }
827 }
828 return ~0u;
829 }
831 // ------------------------------------------------------------------------------------------------
832 float XGLImporter::ReadFloat()
833 {
834 if(!SkipToText()) {
835 LogError("unexpected EOF reading float element contents");
836 return 0.f;
837 }
838 const char* s = reader->getNodeData(), *se;
840 if(!SkipSpaces(&s)) {
841 LogError("unexpected EOL, failed to parse float");
842 return 0.f;
843 }
845 float t;
846 se = fast_atoreal_move(s,t);
848 if (se == s) {
849 LogError("failed to read float text");
850 return 0.f;
851 }
853 return t;
854 }
856 // ------------------------------------------------------------------------------------------------
857 unsigned int XGLImporter::ReadIndexFromText()
858 {
859 if(!SkipToText()) {
860 LogError("unexpected EOF reading index element contents");
861 return ~0u;
862 }
863 const char* s = reader->getNodeData(), *se;
864 if(!SkipSpaces(&s)) {
865 LogError("unexpected EOL, failed to parse index element");
866 return ~0u;
867 }
869 const unsigned int t = strtoul10(s,&se);
871 if (se == s) {
872 LogError("failed to read index");
873 return ~0u;
874 }
876 return t;
877 }
879 // ------------------------------------------------------------------------------------------------
880 aiVector2D XGLImporter::ReadVec2()
881 {
882 aiVector2D vec;
884 if(!SkipToText()) {
885 LogError("unexpected EOF reading vec2 contents");
886 return vec;
887 }
888 const char* s = reader->getNodeData();
890 for(int i = 0; i < 2; ++i) {
891 if(!SkipSpaces(&s)) {
892 LogError("unexpected EOL, failed to parse vec2");
893 return vec;
894 }
895 vec[i] = fast_atof(&s);
897 SkipSpaces(&s);
898 if (i != 1 && *s != ',') {
899 LogError("expected comma, failed to parse vec2");
900 return vec;
901 }
902 ++s;
903 }
905 return vec;
906 }
908 // ------------------------------------------------------------------------------------------------
909 aiVector3D XGLImporter::ReadVec3()
910 {
911 aiVector3D vec;
913 if(!SkipToText()) {
914 LogError("unexpected EOF reading vec3 contents");
915 return vec;
916 }
917 const char* s = reader->getNodeData();
919 for(int i = 0; i < 3; ++i) {
920 if(!SkipSpaces(&s)) {
921 LogError("unexpected EOL, failed to parse vec3");
922 return vec;
923 }
924 vec[i] = fast_atof(&s);
926 SkipSpaces(&s);
927 if (i != 2 && *s != ',') {
928 LogError("expected comma, failed to parse vec3");
929 return vec;
930 }
931 ++s;
932 }
934 return vec;
935 }
937 // ------------------------------------------------------------------------------------------------
938 aiColor3D XGLImporter::ReadCol3()
939 {
940 const aiVector3D& v = ReadVec3();
941 if (v.x < 0.f || v.x > 1.0f || v.y < 0.f || v.y > 1.0f || v.z < 0.f || v.z > 1.0f) {
942 LogWarn("color values out of range, ignoring");
943 }
944 return aiColor3D(v.x,v.y,v.z);
945 }
947 #endif