vrshoot

annotate libs/assimp/XGLLoader.cpp @ 0:b2f14e535253

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