vrshoot

annotate libs/assimp/BlenderLoader.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 All rights reserved.
nuclear@0 8
nuclear@0 9 Redistribution and use of this software in source and binary forms,
nuclear@0 10 with or without modification, are permitted provided that the
nuclear@0 11 following conditions are met:
nuclear@0 12
nuclear@0 13 * Redistributions of source code must retain the above
nuclear@0 14 copyright notice, this list of conditions and the
nuclear@0 15 following disclaimer.
nuclear@0 16
nuclear@0 17 * Redistributions in binary form must reproduce the above
nuclear@0 18 copyright notice, this list of conditions and the
nuclear@0 19 following disclaimer in the documentation and/or other
nuclear@0 20 materials provided with the distribution.
nuclear@0 21
nuclear@0 22 * Neither the name of the assimp team, nor the names of its
nuclear@0 23 contributors may be used to endorse or promote products
nuclear@0 24 derived from this software without specific prior
nuclear@0 25 written permission of the assimp team.
nuclear@0 26
nuclear@0 27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 28 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 30 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 31 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 32 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 33 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 34 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 35 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 37 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 38
nuclear@0 39 ----------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file BlenderLoader.cpp
nuclear@0 43 * @brief Implementation of the Blender3D importer class.
nuclear@0 44 */
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46
nuclear@0 47 //#define ASSIMP_BUILD_NO_COMPRESSED_BLEND
nuclear@0 48 // Uncomment this to disable support for (gzip)compressed .BLEND files
nuclear@0 49
nuclear@0 50 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
nuclear@0 51
nuclear@0 52 #include "BlenderIntermediate.h"
nuclear@0 53 #include "BlenderModifier.h"
nuclear@0 54
nuclear@0 55 #include "StreamReader.h"
nuclear@0 56 #include "MemoryIOWrapper.h"
nuclear@0 57
nuclear@0 58 // zlib is needed for compressed blend files
nuclear@0 59 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
nuclear@0 60 # ifdef ASSIMP_BUILD_NO_OWN_ZLIB
nuclear@0 61 # include <zlib.h>
nuclear@0 62 # else
nuclear@0 63 # include "../contrib/zlib/zlib.h"
nuclear@0 64 # endif
nuclear@0 65 #endif
nuclear@0 66
nuclear@0 67 namespace Assimp {
nuclear@0 68 template<> const std::string LogFunctions<BlenderImporter>::log_prefix = "BLEND: ";
nuclear@0 69 }
nuclear@0 70
nuclear@0 71 using namespace Assimp;
nuclear@0 72 using namespace Assimp::Blender;
nuclear@0 73 using namespace Assimp::Formatter;
nuclear@0 74
nuclear@0 75 static const aiImporterDesc blenderDesc = {
nuclear@0 76 "Blender 3D Importer \nhttp://www.blender3d.org",
nuclear@0 77 "",
nuclear@0 78 "",
nuclear@0 79 "No animation support yet",
nuclear@0 80 aiImporterFlags_SupportBinaryFlavour,
nuclear@0 81 0,
nuclear@0 82 0,
nuclear@0 83 2,
nuclear@0 84 50,
nuclear@0 85 "blend"
nuclear@0 86 };
nuclear@0 87
nuclear@0 88
nuclear@0 89 // ------------------------------------------------------------------------------------------------
nuclear@0 90 // Constructor to be privately used by Importer
nuclear@0 91 BlenderImporter::BlenderImporter()
nuclear@0 92 : modifier_cache(new BlenderModifierShowcase())
nuclear@0 93 {}
nuclear@0 94
nuclear@0 95 // ------------------------------------------------------------------------------------------------
nuclear@0 96 // Destructor, private as well
nuclear@0 97 BlenderImporter::~BlenderImporter()
nuclear@0 98 {
nuclear@0 99 delete modifier_cache;
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 // ------------------------------------------------------------------------------------------------
nuclear@0 103 // Returns whether the class can handle the format of the given file.
nuclear@0 104 bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 105 {
nuclear@0 106 const std::string& extension = GetExtension(pFile);
nuclear@0 107 if (extension == "blend") {
nuclear@0 108 return true;
nuclear@0 109 }
nuclear@0 110
nuclear@0 111 else if ((!extension.length() || checkSig) && pIOHandler) {
nuclear@0 112 // note: this won't catch compressed files
nuclear@0 113 const char* tokens[] = {"BLENDER"};
nuclear@0 114 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
nuclear@0 115 }
nuclear@0 116 return false;
nuclear@0 117 }
nuclear@0 118
nuclear@0 119 // ------------------------------------------------------------------------------------------------
nuclear@0 120 // List all extensions handled by this loader
nuclear@0 121 void BlenderImporter::GetExtensionList(std::set<std::string>& app)
nuclear@0 122 {
nuclear@0 123 app.insert("blend");
nuclear@0 124 }
nuclear@0 125
nuclear@0 126 // ------------------------------------------------------------------------------------------------
nuclear@0 127 // Loader registry entry
nuclear@0 128 const aiImporterDesc* BlenderImporter::GetInfo () const
nuclear@0 129 {
nuclear@0 130 return &blenderDesc;
nuclear@0 131 }
nuclear@0 132
nuclear@0 133 // ------------------------------------------------------------------------------------------------
nuclear@0 134 // Setup configuration properties for the loader
nuclear@0 135 void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
nuclear@0 136 {
nuclear@0 137 // nothing to be done for the moment
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 struct free_it
nuclear@0 141 {
nuclear@0 142 free_it(void* free) : free(free) {}
nuclear@0 143 ~free_it() {
nuclear@0 144 ::free(this->free);
nuclear@0 145 }
nuclear@0 146
nuclear@0 147 void* free;
nuclear@0 148 };
nuclear@0 149
nuclear@0 150 // ------------------------------------------------------------------------------------------------
nuclear@0 151 // Imports the given file into the given scene structure.
nuclear@0 152 void BlenderImporter::InternReadFile( const std::string& pFile,
nuclear@0 153 aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 154 {
nuclear@0 155 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
nuclear@0 156 Bytef* dest = NULL;
nuclear@0 157 free_it free_it_really(dest);
nuclear@0 158 #endif
nuclear@0 159
nuclear@0 160 FileDatabase file;
nuclear@0 161 boost::shared_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
nuclear@0 162 if (!stream) {
nuclear@0 163 ThrowException("Could not open file for reading");
nuclear@0 164 }
nuclear@0 165
nuclear@0 166 char magic[8] = {0};
nuclear@0 167 stream->Read(magic,7,1);
nuclear@0 168 if (strcmp(magic,"BLENDER")) {
nuclear@0 169 // Check for presence of the gzip header. If yes, assume it is a
nuclear@0 170 // compressed blend file and try uncompressing it, else fail. This is to
nuclear@0 171 // avoid uncompressing random files which our loader might end up with.
nuclear@0 172 #ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
nuclear@0 173 ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
nuclear@0 174 #else
nuclear@0 175
nuclear@0 176 if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
nuclear@0 177 ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
nuclear@0 178 }
nuclear@0 179
nuclear@0 180 LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
nuclear@0 181 if (magic[2] != 8) {
nuclear@0 182 ThrowException("Unsupported GZIP compression method");
nuclear@0 183 }
nuclear@0 184
nuclear@0 185 // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
nuclear@0 186 stream->Seek(0L,aiOrigin_SET);
nuclear@0 187 boost::shared_ptr<StreamReaderLE> reader = boost::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
nuclear@0 188
nuclear@0 189 // build a zlib stream
nuclear@0 190 z_stream zstream;
nuclear@0 191 zstream.opaque = Z_NULL;
nuclear@0 192 zstream.zalloc = Z_NULL;
nuclear@0 193 zstream.zfree = Z_NULL;
nuclear@0 194 zstream.data_type = Z_BINARY;
nuclear@0 195
nuclear@0 196 // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
nuclear@0 197 inflateInit2(&zstream, 16+MAX_WBITS);
nuclear@0 198
nuclear@0 199 zstream.next_in = reinterpret_cast<Bytef*>( reader->GetPtr() );
nuclear@0 200 zstream.avail_in = reader->GetRemainingSize();
nuclear@0 201
nuclear@0 202 size_t total = 0l;
nuclear@0 203
nuclear@0 204 // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
nuclear@0 205 #define MYBLOCK 1024
nuclear@0 206 Bytef block[MYBLOCK];
nuclear@0 207 int ret;
nuclear@0 208 do {
nuclear@0 209 zstream.avail_out = MYBLOCK;
nuclear@0 210 zstream.next_out = block;
nuclear@0 211 ret = inflate(&zstream, Z_NO_FLUSH);
nuclear@0 212
nuclear@0 213 if (ret != Z_STREAM_END && ret != Z_OK) {
nuclear@0 214 ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
nuclear@0 215 }
nuclear@0 216 const size_t have = MYBLOCK - zstream.avail_out;
nuclear@0 217 total += have;
nuclear@0 218 dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
nuclear@0 219 memcpy(dest + total - have,block,have);
nuclear@0 220 }
nuclear@0 221 while (ret != Z_STREAM_END);
nuclear@0 222
nuclear@0 223 // terminate zlib
nuclear@0 224 inflateEnd(&zstream);
nuclear@0 225
nuclear@0 226 // replace the input stream with a memory stream
nuclear@0 227 stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
nuclear@0 228
nuclear@0 229 // .. and retry
nuclear@0 230 stream->Read(magic,7,1);
nuclear@0 231 if (strcmp(magic,"BLENDER")) {
nuclear@0 232 ThrowException("Found no BLENDER magic word in decompressed GZIP file");
nuclear@0 233 }
nuclear@0 234 #endif
nuclear@0 235 }
nuclear@0 236
nuclear@0 237 file.i64bit = (stream->Read(magic,1,1),magic[0]=='-');
nuclear@0 238 file.little = (stream->Read(magic,1,1),magic[0]=='v');
nuclear@0 239
nuclear@0 240 stream->Read(magic,3,1);
nuclear@0 241 magic[3] = '\0';
nuclear@0 242
nuclear@0 243 LogInfo((format(),"Blender version is ",magic[0],".",magic+1,
nuclear@0 244 " (64bit: ",file.i64bit?"true":"false",
nuclear@0 245 ", little endian: ",file.little?"true":"false",")"
nuclear@0 246 ));
nuclear@0 247
nuclear@0 248 ParseBlendFile(file,stream);
nuclear@0 249
nuclear@0 250 Scene scene;
nuclear@0 251 ExtractScene(scene,file);
nuclear@0 252
nuclear@0 253 ConvertBlendFile(pScene,scene,file);
nuclear@0 254 }
nuclear@0 255
nuclear@0 256 // ------------------------------------------------------------------------------------------------
nuclear@0 257 void BlenderImporter::ParseBlendFile(FileDatabase& out, boost::shared_ptr<IOStream> stream)
nuclear@0 258 {
nuclear@0 259 out.reader = boost::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream,out.little));
nuclear@0 260
nuclear@0 261 DNAParser dna_reader(out);
nuclear@0 262 const DNA* dna = NULL;
nuclear@0 263
nuclear@0 264 out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks
nuclear@0 265 SectionParser parser(*out.reader.get(),out.i64bit);
nuclear@0 266
nuclear@0 267 // first parse the file in search for the DNA and insert all other sections into the database
nuclear@0 268 while ((parser.Next(),1)) {
nuclear@0 269 const FileBlockHead& head = parser.GetCurrent();
nuclear@0 270
nuclear@0 271 if (head.id == "ENDB") {
nuclear@0 272 break; // only valid end of the file
nuclear@0 273 }
nuclear@0 274 else if (head.id == "DNA1") {
nuclear@0 275 dna_reader.Parse();
nuclear@0 276 dna = &dna_reader.GetDNA();
nuclear@0 277 continue;
nuclear@0 278 }
nuclear@0 279
nuclear@0 280 out.entries.push_back(head);
nuclear@0 281 }
nuclear@0 282 }
nuclear@0 283 if (!dna) {
nuclear@0 284 ThrowException("SDNA not found");
nuclear@0 285 }
nuclear@0 286
nuclear@0 287 std::sort(out.entries.begin(),out.entries.end());
nuclear@0 288 }
nuclear@0 289
nuclear@0 290 // ------------------------------------------------------------------------------------------------
nuclear@0 291 void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
nuclear@0 292 {
nuclear@0 293 const FileBlockHead* block = NULL;
nuclear@0 294 std::map<std::string,size_t>::const_iterator it = file.dna.indices.find("Scene");
nuclear@0 295 if (it == file.dna.indices.end()) {
nuclear@0 296 ThrowException("There is no `Scene` structure record");
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 const Structure& ss = file.dna.structures[(*it).second];
nuclear@0 300
nuclear@0 301 // we need a scene somewhere to start with.
nuclear@0 302 for_each(const FileBlockHead& bl,file.entries) {
nuclear@0 303
nuclear@0 304 // Fix: using the DNA index is more reliable to locate scenes
nuclear@0 305 //if (bl.id == "SC") {
nuclear@0 306
nuclear@0 307 if (bl.dna_index == (*it).second) {
nuclear@0 308 block = &bl;
nuclear@0 309 break;
nuclear@0 310 }
nuclear@0 311 }
nuclear@0 312
nuclear@0 313 if (!block) {
nuclear@0 314 ThrowException("There is not a single `Scene` record to load");
nuclear@0 315 }
nuclear@0 316
nuclear@0 317 file.reader->SetCurrentPos(block->start);
nuclear@0 318 ss.Convert(out,file);
nuclear@0 319
nuclear@0 320 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
nuclear@0 321 DefaultLogger::get()->info((format(),
nuclear@0 322 "(Stats) Fields read: " ,file.stats().fields_read,
nuclear@0 323 ", pointers resolved: " ,file.stats().pointers_resolved,
nuclear@0 324 ", cache hits: " ,file.stats().cache_hits,
nuclear@0 325 ", cached objects: " ,file.stats().cached_objects
nuclear@0 326 ));
nuclear@0 327 #endif
nuclear@0 328 }
nuclear@0 329
nuclear@0 330 // ------------------------------------------------------------------------------------------------
nuclear@0 331 void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileDatabase& file)
nuclear@0 332 {
nuclear@0 333 ConversionData conv(file);
nuclear@0 334
nuclear@0 335 // FIXME it must be possible to take the hierarchy directly from
nuclear@0 336 // the file. This is terrible. Here, we're first looking for
nuclear@0 337 // all objects which don't have parent objects at all -
nuclear@0 338 std::deque<const Object*> no_parents;
nuclear@0 339 for (boost::shared_ptr<Base> cur = boost::static_pointer_cast<Base> ( in.base.first ); cur; cur = cur->next) {
nuclear@0 340 if (cur->object) {
nuclear@0 341 if(!cur->object->parent) {
nuclear@0 342 no_parents.push_back(cur->object.get());
nuclear@0 343 }
nuclear@0 344 else conv.objects.insert(cur->object.get());
nuclear@0 345 }
nuclear@0 346 }
nuclear@0 347 for (boost::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
nuclear@0 348 if (cur->object) {
nuclear@0 349 if(cur->object->parent) {
nuclear@0 350 conv.objects.insert(cur->object.get());
nuclear@0 351 }
nuclear@0 352 }
nuclear@0 353 }
nuclear@0 354
nuclear@0 355 if (no_parents.empty()) {
nuclear@0 356 ThrowException("Expected at least one object with no parent");
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 aiNode* root = out->mRootNode = new aiNode("<BlenderRoot>");
nuclear@0 360
nuclear@0 361 root->mNumChildren = static_cast<unsigned int>(no_parents.size());
nuclear@0 362 root->mChildren = new aiNode*[root->mNumChildren]();
nuclear@0 363 for (unsigned int i = 0; i < root->mNumChildren; ++i) {
nuclear@0 364 root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
nuclear@0 365 root->mChildren[i]->mParent = root;
nuclear@0 366 }
nuclear@0 367
nuclear@0 368 BuildMaterials(conv);
nuclear@0 369
nuclear@0 370 if (conv.meshes->size()) {
nuclear@0 371 out->mMeshes = new aiMesh*[out->mNumMeshes = static_cast<unsigned int>( conv.meshes->size() )];
nuclear@0 372 std::copy(conv.meshes->begin(),conv.meshes->end(),out->mMeshes);
nuclear@0 373 conv.meshes.dismiss();
nuclear@0 374 }
nuclear@0 375
nuclear@0 376 if (conv.lights->size()) {
nuclear@0 377 out->mLights = new aiLight*[out->mNumLights = static_cast<unsigned int>( conv.lights->size() )];
nuclear@0 378 std::copy(conv.lights->begin(),conv.lights->end(),out->mLights);
nuclear@0 379 conv.lights.dismiss();
nuclear@0 380 }
nuclear@0 381
nuclear@0 382 if (conv.cameras->size()) {
nuclear@0 383 out->mCameras = new aiCamera*[out->mNumCameras = static_cast<unsigned int>( conv.cameras->size() )];
nuclear@0 384 std::copy(conv.cameras->begin(),conv.cameras->end(),out->mCameras);
nuclear@0 385 conv.cameras.dismiss();
nuclear@0 386 }
nuclear@0 387
nuclear@0 388 if (conv.materials->size()) {
nuclear@0 389 out->mMaterials = new aiMaterial*[out->mNumMaterials = static_cast<unsigned int>( conv.materials->size() )];
nuclear@0 390 std::copy(conv.materials->begin(),conv.materials->end(),out->mMaterials);
nuclear@0 391 conv.materials.dismiss();
nuclear@0 392 }
nuclear@0 393
nuclear@0 394 if (conv.textures->size()) {
nuclear@0 395 out->mTextures = new aiTexture*[out->mNumTextures = static_cast<unsigned int>( conv.textures->size() )];
nuclear@0 396 std::copy(conv.textures->begin(),conv.textures->end(),out->mTextures);
nuclear@0 397 conv.textures.dismiss();
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 // acknowledge that the scene might come out incomplete
nuclear@0 401 // by Assimps definition of `complete`: blender scenes
nuclear@0 402 // can consist of thousands of cameras or lights with
nuclear@0 403 // not a single mesh between them.
nuclear@0 404 if (!out->mNumMeshes) {
nuclear@0 405 out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
nuclear@0 406 }
nuclear@0 407 }
nuclear@0 408
nuclear@0 409 // ------------------------------------------------------------------------------------------------
nuclear@0 410 void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const MTex* tex, const Image* img, ConversionData& conv_data)
nuclear@0 411 {
nuclear@0 412 (void)mat; (void)tex; (void)conv_data;
nuclear@0 413 aiString name;
nuclear@0 414
nuclear@0 415 // check if the file contents are bundled with the BLEND file
nuclear@0 416 if (img->packedfile) {
nuclear@0 417 name.data[0] = '*';
nuclear@0 418 name.length = 1+ ASSIMP_itoa10(name.data+1,MAXLEN-1,conv_data.textures->size());
nuclear@0 419
nuclear@0 420 conv_data.textures->push_back(new aiTexture());
nuclear@0 421 aiTexture* tex = conv_data.textures->back();
nuclear@0 422
nuclear@0 423 // usually 'img->name' will be the original file name of the embedded textures,
nuclear@0 424 // so we can extract the file extension from it.
nuclear@0 425 const size_t nlen = strlen( img->name );
nuclear@0 426 const char* s = img->name+nlen, *e = s;
nuclear@0 427
nuclear@0 428 while (s >= img->name && *s != '.')--s;
nuclear@0 429
nuclear@0 430 tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
nuclear@0 431 tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
nuclear@0 432 tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
nuclear@0 433 tex->achFormatHint[3] = '\0';
nuclear@0 434
nuclear@0 435 // tex->mHeight = 0;
nuclear@0 436 tex->mWidth = img->packedfile->size;
nuclear@0 437 uint8_t* ch = new uint8_t[tex->mWidth];
nuclear@0 438
nuclear@0 439 conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
nuclear@0 440 conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth);
nuclear@0 441
nuclear@0 442 tex->pcData = reinterpret_cast<aiTexel*>(ch);
nuclear@0 443
nuclear@0 444 LogInfo("Reading embedded texture, original file was "+std::string(img->name));
nuclear@0 445 }
nuclear@0 446 else {
nuclear@0 447 name = aiString( img->name );
nuclear@0 448 }
nuclear@0 449 out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(
nuclear@0 450 conv_data.next_texture[aiTextureType_DIFFUSE]++)
nuclear@0 451 );
nuclear@0 452 }
nuclear@0 453
nuclear@0 454 // ------------------------------------------------------------------------------------------------
nuclear@0 455 void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
nuclear@0 456 {
nuclear@0 457 (void)mat; (void)tex; (void)conv_data;
nuclear@0 458
nuclear@0 459 aiString name;
nuclear@0 460 name.length = sprintf(name.data, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++,
nuclear@0 461 GetTextureTypeDisplayString(tex->tex->type)
nuclear@0 462 );
nuclear@0 463 out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(
nuclear@0 464 conv_data.next_texture[aiTextureType_DIFFUSE]++)
nuclear@0 465 );
nuclear@0 466 }
nuclear@0 467
nuclear@0 468 // ------------------------------------------------------------------------------------------------
nuclear@0 469 void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
nuclear@0 470 {
nuclear@0 471 const Tex* rtex = tex->tex.get();
nuclear@0 472 if(!rtex || !rtex->type) {
nuclear@0 473 return;
nuclear@0 474 }
nuclear@0 475
nuclear@0 476 // We can't support most of the texture types because they're mostly procedural.
nuclear@0 477 // These are substituted by a dummy texture.
nuclear@0 478 const char* dispnam = "";
nuclear@0 479 switch( rtex->type )
nuclear@0 480 {
nuclear@0 481 // these are listed in blender's UI
nuclear@0 482 case Tex::Type_CLOUDS :
nuclear@0 483 case Tex::Type_WOOD :
nuclear@0 484 case Tex::Type_MARBLE :
nuclear@0 485 case Tex::Type_MAGIC :
nuclear@0 486 case Tex::Type_BLEND :
nuclear@0 487 case Tex::Type_STUCCI :
nuclear@0 488 case Tex::Type_NOISE :
nuclear@0 489 case Tex::Type_PLUGIN :
nuclear@0 490 case Tex::Type_MUSGRAVE :
nuclear@0 491 case Tex::Type_VORONOI :
nuclear@0 492 case Tex::Type_DISTNOISE :
nuclear@0 493 case Tex::Type_ENVMAP :
nuclear@0 494
nuclear@0 495 // these do no appear in the UI, why?
nuclear@0 496 case Tex::Type_POINTDENSITY :
nuclear@0 497 case Tex::Type_VOXELDATA :
nuclear@0 498
nuclear@0 499 LogWarn(std::string("Encountered a texture with an unsupported type: ")+dispnam);
nuclear@0 500 AddSentinelTexture(out, mat, tex, conv_data);
nuclear@0 501 break;
nuclear@0 502
nuclear@0 503 case Tex::Type_IMAGE :
nuclear@0 504 if (!rtex->ima) {
nuclear@0 505 LogError("A texture claims to be an Image, but no image reference is given");
nuclear@0 506 break;
nuclear@0 507 }
nuclear@0 508 ResolveImage(out, mat, tex, rtex->ima.get(),conv_data);
nuclear@0 509 break;
nuclear@0 510
nuclear@0 511 default:
nuclear@0 512 ai_assert(false);
nuclear@0 513 };
nuclear@0 514 }
nuclear@0 515
nuclear@0 516 // ------------------------------------------------------------------------------------------------
nuclear@0 517 void BlenderImporter::BuildMaterials(ConversionData& conv_data)
nuclear@0 518 {
nuclear@0 519 conv_data.materials->reserve(conv_data.materials_raw.size());
nuclear@0 520
nuclear@0 521 // add a default material if necessary
nuclear@0 522 unsigned int index = static_cast<unsigned int>( -1 );
nuclear@0 523 for_each( aiMesh* mesh, conv_data.meshes.get() ) {
nuclear@0 524 if (mesh->mMaterialIndex == static_cast<unsigned int>( -1 )) {
nuclear@0 525
nuclear@0 526 if (index == static_cast<unsigned int>( -1 )) {
nuclear@0 527
nuclear@0 528 // ok, we need to add a dedicated default material for some poor material-less meshes
nuclear@0 529 boost::shared_ptr<Material> p(new Material());
nuclear@0 530 strcpy( p->id.name+2, AI_DEFAULT_MATERIAL_NAME );
nuclear@0 531
nuclear@0 532 p->r = p->g = p->b = 0.6f;
nuclear@0 533 p->specr = p->specg = p->specb = 0.6f;
nuclear@0 534 p->ambr = p->ambg = p->ambb = 0.0f;
nuclear@0 535 p->mirr = p->mirg = p->mirb = 0.0f;
nuclear@0 536 p->emit = 0.f;
nuclear@0 537 p->alpha = 0.f;
nuclear@0 538
nuclear@0 539 // XXX add more / or add default c'tor to Material
nuclear@0 540
nuclear@0 541 index = static_cast<unsigned int>( conv_data.materials_raw.size() );
nuclear@0 542 conv_data.materials_raw.push_back(p);
nuclear@0 543
nuclear@0 544 LogInfo("Adding default material ...");
nuclear@0 545 }
nuclear@0 546 mesh->mMaterialIndex = index;
nuclear@0 547 }
nuclear@0 548 }
nuclear@0 549
nuclear@0 550 for_each(boost::shared_ptr<Material> mat, conv_data.materials_raw) {
nuclear@0 551
nuclear@0 552 // reset per material global counters
nuclear@0 553 for (size_t i = 0; i < sizeof(conv_data.next_texture)/sizeof(conv_data.next_texture[0]);++i) {
nuclear@0 554 conv_data.next_texture[i] = 0 ;
nuclear@0 555 }
nuclear@0 556
nuclear@0 557 aiMaterial* mout = new aiMaterial();
nuclear@0 558 conv_data.materials->push_back(mout);
nuclear@0 559
nuclear@0 560 // set material name
nuclear@0 561 aiString name = aiString(mat->id.name+2); // skip over the name prefix 'MA'
nuclear@0 562 mout->AddProperty(&name,AI_MATKEY_NAME);
nuclear@0 563
nuclear@0 564
nuclear@0 565 // basic material colors
nuclear@0 566 aiColor3D col(mat->r,mat->g,mat->b);
nuclear@0 567 if (mat->r || mat->g || mat->b ) {
nuclear@0 568
nuclear@0 569 // Usually, zero diffuse color means no diffuse color at all in the equation.
nuclear@0 570 // So we omit this member to express this intent.
nuclear@0 571 mout->AddProperty(&col,1,AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 572
nuclear@0 573 if (mat->emit) {
nuclear@0 574 aiColor3D emit_col(mat->emit * mat->r, mat->emit * mat->g, mat->emit * mat->b) ;
nuclear@0 575 mout->AddProperty(&emit_col, 1, AI_MATKEY_COLOR_EMISSIVE) ;
nuclear@0 576 }
nuclear@0 577 }
nuclear@0 578
nuclear@0 579 col = aiColor3D(mat->specr,mat->specg,mat->specb);
nuclear@0 580 mout->AddProperty(&col,1,AI_MATKEY_COLOR_SPECULAR);
nuclear@0 581
nuclear@0 582 // is hardness/shininess set?
nuclear@0 583 if( mat->har ) {
nuclear@0 584 const float har = mat->har;
nuclear@0 585 mout->AddProperty(&har,1,AI_MATKEY_SHININESS);
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 col = aiColor3D(mat->ambr,mat->ambg,mat->ambb);
nuclear@0 589 mout->AddProperty(&col,1,AI_MATKEY_COLOR_AMBIENT);
nuclear@0 590
nuclear@0 591 col = aiColor3D(mat->mirr,mat->mirg,mat->mirb);
nuclear@0 592 mout->AddProperty(&col,1,AI_MATKEY_COLOR_REFLECTIVE);
nuclear@0 593
nuclear@0 594 for(size_t i = 0; i < sizeof(mat->mtex) / sizeof(mat->mtex[0]); ++i) {
nuclear@0 595 if (!mat->mtex[i]) {
nuclear@0 596 continue;
nuclear@0 597 }
nuclear@0 598
nuclear@0 599 ResolveTexture(mout,mat.get(),mat->mtex[i].get(),conv_data);
nuclear@0 600 }
nuclear@0 601 }
nuclear@0 602 }
nuclear@0 603
nuclear@0 604 // ------------------------------------------------------------------------------------------------
nuclear@0 605 void BlenderImporter::CheckActualType(const ElemBase* dt, const char* check)
nuclear@0 606 {
nuclear@0 607 ai_assert(dt);
nuclear@0 608 if (strcmp(dt->dna_type,check)) {
nuclear@0 609 ThrowException((format(),
nuclear@0 610 "Expected object at ",std::hex,dt," to be of type `",check,
nuclear@0 611 "`, but it claims to be a `",dt->dna_type,"`instead"
nuclear@0 612 ));
nuclear@0 613 }
nuclear@0 614 }
nuclear@0 615
nuclear@0 616 // ------------------------------------------------------------------------------------------------
nuclear@0 617 void BlenderImporter::NotSupportedObjectType(const Object* obj, const char* type)
nuclear@0 618 {
nuclear@0 619 LogWarn((format(), "Object `",obj->id.name,"` - type is unsupported: `",type, "`, skipping" ));
nuclear@0 620 }
nuclear@0 621
nuclear@0 622 // ------------------------------------------------------------------------------------------------
nuclear@0 623 void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, const Mesh* mesh,
nuclear@0 624 ConversionData& conv_data, TempArray<std::vector,aiMesh>& temp
nuclear@0 625 )
nuclear@0 626 {
nuclear@0 627 typedef std::pair<const int,size_t> MyPair;
nuclear@0 628 if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
nuclear@0 629 return;
nuclear@0 630 }
nuclear@0 631
nuclear@0 632 // some sanity checks
nuclear@0 633 if (static_cast<size_t> ( mesh->totface ) > mesh->mface.size() ){
nuclear@0 634 ThrowException("Number of faces is larger than the corresponding array");
nuclear@0 635 }
nuclear@0 636
nuclear@0 637 if (static_cast<size_t> ( mesh->totvert ) > mesh->mvert.size()) {
nuclear@0 638 ThrowException("Number of vertices is larger than the corresponding array");
nuclear@0 639 }
nuclear@0 640
nuclear@0 641 if (static_cast<size_t> ( mesh->totloop ) > mesh->mloop.size()) {
nuclear@0 642 ThrowException("Number of vertices is larger than the corresponding array");
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 // collect per-submesh numbers
nuclear@0 646 std::map<int,size_t> per_mat;
nuclear@0 647 std::map<int,size_t> per_mat_verts;
nuclear@0 648 for (int i = 0; i < mesh->totface; ++i) {
nuclear@0 649
nuclear@0 650 const MFace& mf = mesh->mface[i];
nuclear@0 651 per_mat[ mf.mat_nr ]++;
nuclear@0 652 per_mat_verts[ mf.mat_nr ] += mf.v4?4:3;
nuclear@0 653 }
nuclear@0 654
nuclear@0 655 for (int i = 0; i < mesh->totpoly; ++i) {
nuclear@0 656 const MPoly& mp = mesh->mpoly[i];
nuclear@0 657 per_mat[ mp.mat_nr ]++;
nuclear@0 658 per_mat_verts[ mp.mat_nr ] += mp.totloop;
nuclear@0 659 }
nuclear@0 660
nuclear@0 661 // ... and allocate the corresponding meshes
nuclear@0 662 const size_t old = temp->size();
nuclear@0 663 temp->reserve(temp->size() + per_mat.size());
nuclear@0 664
nuclear@0 665 std::map<size_t,size_t> mat_num_to_mesh_idx;
nuclear@0 666 for_each(MyPair& it, per_mat) {
nuclear@0 667
nuclear@0 668 mat_num_to_mesh_idx[it.first] = temp->size();
nuclear@0 669 temp->push_back(new aiMesh());
nuclear@0 670
nuclear@0 671 aiMesh* out = temp->back();
nuclear@0 672 out->mVertices = new aiVector3D[per_mat_verts[it.first]];
nuclear@0 673 out->mNormals = new aiVector3D[per_mat_verts[it.first]];
nuclear@0 674
nuclear@0 675 //out->mNumFaces = 0
nuclear@0 676 //out->mNumVertices = 0
nuclear@0 677 out->mFaces = new aiFace[it.second]();
nuclear@0 678
nuclear@0 679 // all submeshes created from this mesh are named equally. this allows
nuclear@0 680 // curious users to recover the original adjacency.
nuclear@0 681 out->mName = aiString(mesh->id.name+2);
nuclear@0 682 // skip over the name prefix 'ME'
nuclear@0 683
nuclear@0 684 // resolve the material reference and add this material to the set of
nuclear@0 685 // output materials. The (temporary) material index is the index
nuclear@0 686 // of the material entry within the list of resolved materials.
nuclear@0 687 if (mesh->mat) {
nuclear@0 688
nuclear@0 689 if (static_cast<size_t> ( it.first ) >= mesh->mat.size() ) {
nuclear@0 690 ThrowException("Material index is out of range");
nuclear@0 691 }
nuclear@0 692
nuclear@0 693 boost::shared_ptr<Material> mat = mesh->mat[it.first];
nuclear@0 694 const std::deque< boost::shared_ptr<Material> >::iterator has = std::find(
nuclear@0 695 conv_data.materials_raw.begin(),
nuclear@0 696 conv_data.materials_raw.end(),mat
nuclear@0 697 );
nuclear@0 698
nuclear@0 699 if (has != conv_data.materials_raw.end()) {
nuclear@0 700 out->mMaterialIndex = static_cast<unsigned int>( std::distance(conv_data.materials_raw.begin(),has));
nuclear@0 701 }
nuclear@0 702 else {
nuclear@0 703 out->mMaterialIndex = static_cast<unsigned int>( conv_data.materials_raw.size() );
nuclear@0 704 conv_data.materials_raw.push_back(mat);
nuclear@0 705 }
nuclear@0 706 }
nuclear@0 707 else out->mMaterialIndex = static_cast<unsigned int>( -1 );
nuclear@0 708 }
nuclear@0 709
nuclear@0 710 for (int i = 0; i < mesh->totface; ++i) {
nuclear@0 711
nuclear@0 712 const MFace& mf = mesh->mface[i];
nuclear@0 713
nuclear@0 714 aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
nuclear@0 715 aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 716
nuclear@0 717 f.mIndices = new unsigned int[ f.mNumIndices = mf.v4?4:3 ];
nuclear@0 718 aiVector3D* vo = out->mVertices + out->mNumVertices;
nuclear@0 719 aiVector3D* vn = out->mNormals + out->mNumVertices;
nuclear@0 720
nuclear@0 721 // XXX we can't fold this easily, because we are restricted
nuclear@0 722 // to the member names from the BLEND file (v1,v2,v3,v4)
nuclear@0 723 // which are assigned by the genblenddna.py script and
nuclear@0 724 // cannot be changed without breaking the entire
nuclear@0 725 // import process.
nuclear@0 726
nuclear@0 727 if (mf.v1 >= mesh->totvert) {
nuclear@0 728 ThrowException("Vertex index v1 out of range");
nuclear@0 729 }
nuclear@0 730 const MVert* v = &mesh->mvert[mf.v1];
nuclear@0 731 vo->x = v->co[0];
nuclear@0 732 vo->y = v->co[1];
nuclear@0 733 vo->z = v->co[2];
nuclear@0 734 vn->x = v->no[0];
nuclear@0 735 vn->y = v->no[1];
nuclear@0 736 vn->z = v->no[2];
nuclear@0 737 f.mIndices[0] = out->mNumVertices++;
nuclear@0 738 ++vo;
nuclear@0 739 ++vn;
nuclear@0 740
nuclear@0 741 // if (f.mNumIndices >= 2) {
nuclear@0 742 if (mf.v2 >= mesh->totvert) {
nuclear@0 743 ThrowException("Vertex index v2 out of range");
nuclear@0 744 }
nuclear@0 745 v = &mesh->mvert[mf.v2];
nuclear@0 746 vo->x = v->co[0];
nuclear@0 747 vo->y = v->co[1];
nuclear@0 748 vo->z = v->co[2];
nuclear@0 749 vn->x = v->no[0];
nuclear@0 750 vn->y = v->no[1];
nuclear@0 751 vn->z = v->no[2];
nuclear@0 752 f.mIndices[1] = out->mNumVertices++;
nuclear@0 753 ++vo;
nuclear@0 754 ++vn;
nuclear@0 755
nuclear@0 756 if (mf.v3 >= mesh->totvert) {
nuclear@0 757 ThrowException("Vertex index v3 out of range");
nuclear@0 758 }
nuclear@0 759 // if (f.mNumIndices >= 3) {
nuclear@0 760 v = &mesh->mvert[mf.v3];
nuclear@0 761 vo->x = v->co[0];
nuclear@0 762 vo->y = v->co[1];
nuclear@0 763 vo->z = v->co[2];
nuclear@0 764 vn->x = v->no[0];
nuclear@0 765 vn->y = v->no[1];
nuclear@0 766 vn->z = v->no[2];
nuclear@0 767 f.mIndices[2] = out->mNumVertices++;
nuclear@0 768 ++vo;
nuclear@0 769 ++vn;
nuclear@0 770
nuclear@0 771 if (mf.v4 >= mesh->totvert) {
nuclear@0 772 ThrowException("Vertex index v4 out of range");
nuclear@0 773 }
nuclear@0 774 // if (f.mNumIndices >= 4) {
nuclear@0 775 if (mf.v4) {
nuclear@0 776 v = &mesh->mvert[mf.v4];
nuclear@0 777 vo->x = v->co[0];
nuclear@0 778 vo->y = v->co[1];
nuclear@0 779 vo->z = v->co[2];
nuclear@0 780 vn->x = v->no[0];
nuclear@0 781 vn->y = v->no[1];
nuclear@0 782 vn->z = v->no[2];
nuclear@0 783 f.mIndices[3] = out->mNumVertices++;
nuclear@0 784 ++vo;
nuclear@0 785 ++vn;
nuclear@0 786
nuclear@0 787 out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
nuclear@0 788 }
nuclear@0 789 else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
nuclear@0 790
nuclear@0 791 // }
nuclear@0 792 // }
nuclear@0 793 // }
nuclear@0 794 }
nuclear@0 795
nuclear@0 796 for (int i = 0; i < mesh->totpoly; ++i) {
nuclear@0 797
nuclear@0 798 const MPoly& mf = mesh->mpoly[i];
nuclear@0 799
nuclear@0 800 aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
nuclear@0 801 aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 802
nuclear@0 803 f.mIndices = new unsigned int[ f.mNumIndices = mf.totloop ];
nuclear@0 804 aiVector3D* vo = out->mVertices + out->mNumVertices;
nuclear@0 805 aiVector3D* vn = out->mNormals + out->mNumVertices;
nuclear@0 806
nuclear@0 807 // XXX we can't fold this easily, because we are restricted
nuclear@0 808 // to the member names from the BLEND file (v1,v2,v3,v4)
nuclear@0 809 // which are assigned by the genblenddna.py script and
nuclear@0 810 // cannot be changed without breaking the entire
nuclear@0 811 // import process.
nuclear@0 812 for (int j = 0;j < mf.totloop; ++j)
nuclear@0 813 {
nuclear@0 814 const MLoop& loop = mesh->mloop[mf.loopstart + j];
nuclear@0 815
nuclear@0 816 if (loop.v >= mesh->totvert) {
nuclear@0 817 ThrowException("Vertex index out of range");
nuclear@0 818 }
nuclear@0 819
nuclear@0 820 const MVert& v = mesh->mvert[loop.v];
nuclear@0 821
nuclear@0 822 vo->x = v.co[0];
nuclear@0 823 vo->y = v.co[1];
nuclear@0 824 vo->z = v.co[2];
nuclear@0 825 vn->x = v.no[0];
nuclear@0 826 vn->y = v.no[1];
nuclear@0 827 vn->z = v.no[2];
nuclear@0 828 f.mIndices[j] = out->mNumVertices++;
nuclear@0 829
nuclear@0 830 ++vo;
nuclear@0 831 ++vn;
nuclear@0 832
nuclear@0 833 }
nuclear@0 834 if (mf.totloop == 3)
nuclear@0 835 {
nuclear@0 836 out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
nuclear@0 837 }
nuclear@0 838 else
nuclear@0 839 {
nuclear@0 840 out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
nuclear@0 841 }
nuclear@0 842 }
nuclear@0 843
nuclear@0 844 // collect texture coordinates, they're stored in a separate per-face buffer
nuclear@0 845 if (mesh->mtface || mesh->mloopuv) {
nuclear@0 846 if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
nuclear@0 847 ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
nuclear@0 848 }
nuclear@0 849 for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
nuclear@0 850 ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
nuclear@0 851
nuclear@0 852 (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
nuclear@0 853 (*it)->mNumFaces = (*it)->mNumVertices = 0;
nuclear@0 854 }
nuclear@0 855
nuclear@0 856 for (int i = 0; i < mesh->totface; ++i) {
nuclear@0 857 const MTFace* v = &mesh->mtface[i];
nuclear@0 858
nuclear@0 859 aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
nuclear@0 860 const aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 861
nuclear@0 862 aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
nuclear@0 863 for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
nuclear@0 864 vo->x = v->uv[i][0];
nuclear@0 865 vo->y = v->uv[i][1];
nuclear@0 866 }
nuclear@0 867 }
nuclear@0 868
nuclear@0 869 for (int i = 0; i < mesh->totpoly; ++i) {
nuclear@0 870 const MPoly& v = mesh->mpoly[i];
nuclear@0 871 aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
nuclear@0 872 const aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 873
nuclear@0 874 aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
nuclear@0 875 for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
nuclear@0 876 const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
nuclear@0 877 vo->x = uv.uv[0];
nuclear@0 878 vo->y = uv.uv[1];
nuclear@0 879 }
nuclear@0 880
nuclear@0 881 }
nuclear@0 882 }
nuclear@0 883
nuclear@0 884 // collect texture coordinates, old-style (marked as deprecated in current blender sources)
nuclear@0 885 if (mesh->tface) {
nuclear@0 886 if (mesh->totface > static_cast<int> ( mesh->tface.size())) {
nuclear@0 887 ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
nuclear@0 888 }
nuclear@0 889 for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
nuclear@0 890 ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
nuclear@0 891
nuclear@0 892 (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
nuclear@0 893 (*it)->mNumFaces = (*it)->mNumVertices = 0;
nuclear@0 894 }
nuclear@0 895
nuclear@0 896 for (int i = 0; i < mesh->totface; ++i) {
nuclear@0 897 const TFace* v = &mesh->tface[i];
nuclear@0 898
nuclear@0 899 aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
nuclear@0 900 const aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 901
nuclear@0 902 aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
nuclear@0 903 for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
nuclear@0 904 vo->x = v->uv[i][0];
nuclear@0 905 vo->y = v->uv[i][1];
nuclear@0 906 }
nuclear@0 907 }
nuclear@0 908 }
nuclear@0 909
nuclear@0 910 // collect vertex colors, stored separately as well
nuclear@0 911 if (mesh->mcol || mesh->mloopcol) {
nuclear@0 912 if (mesh->totface > static_cast<int> ( (mesh->mcol.size()/4)) ) {
nuclear@0 913 ThrowException("Number of faces is larger than the corresponding color face array");
nuclear@0 914 }
nuclear@0 915 for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
nuclear@0 916 ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
nuclear@0 917
nuclear@0 918 (*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
nuclear@0 919 (*it)->mNumFaces = (*it)->mNumVertices = 0;
nuclear@0 920 }
nuclear@0 921
nuclear@0 922 for (int i = 0; i < mesh->totface; ++i) {
nuclear@0 923
nuclear@0 924 aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
nuclear@0 925 const aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 926
nuclear@0 927 aiColor4D* vo = &out->mColors[0][out->mNumVertices];
nuclear@0 928 for (unsigned int n = 0; n < f.mNumIndices; ++n, ++vo,++out->mNumVertices) {
nuclear@0 929 const MCol* col = &mesh->mcol[(i<<2)+n];
nuclear@0 930
nuclear@0 931 vo->r = col->r;
nuclear@0 932 vo->g = col->g;
nuclear@0 933 vo->b = col->b;
nuclear@0 934 vo->a = col->a;
nuclear@0 935 }
nuclear@0 936 for (unsigned int n = f.mNumIndices; n < 4; ++n);
nuclear@0 937 }
nuclear@0 938
nuclear@0 939 for (int i = 0; i < mesh->totpoly; ++i) {
nuclear@0 940 const MPoly& v = mesh->mpoly[i];
nuclear@0 941 aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
nuclear@0 942 const aiFace& f = out->mFaces[out->mNumFaces++];
nuclear@0 943
nuclear@0 944 aiColor4D* vo = &out->mColors[0][out->mNumVertices];
nuclear@0 945 for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
nuclear@0 946 const MLoopCol& col = mesh->mloopcol[v.loopstart + j];
nuclear@0 947 vo->r = col.r;
nuclear@0 948 vo->g = col.g;
nuclear@0 949 vo->b = col.b;
nuclear@0 950 vo->a = col.a;
nuclear@0 951 }
nuclear@0 952
nuclear@0 953 }
nuclear@0 954
nuclear@0 955 }
nuclear@0 956
nuclear@0 957 return;
nuclear@0 958 }
nuclear@0 959
nuclear@0 960 // ------------------------------------------------------------------------------------------------
nuclear@0 961 aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* /*obj*/, const Camera* /*mesh*/, ConversionData& /*conv_data*/)
nuclear@0 962 {
nuclear@0 963 ScopeGuard<aiCamera> out(new aiCamera());
nuclear@0 964
nuclear@0 965 return NULL ; //out.dismiss();
nuclear@0 966 }
nuclear@0 967
nuclear@0 968 // ------------------------------------------------------------------------------------------------
nuclear@0 969 aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* /*obj*/, const Lamp* /*mesh*/, ConversionData& /*conv_data*/)
nuclear@0 970 {
nuclear@0 971 ScopeGuard<aiLight> out(new aiLight());
nuclear@0 972
nuclear@0 973 return NULL ; //out.dismiss();
nuclear@0 974 }
nuclear@0 975
nuclear@0 976 // ------------------------------------------------------------------------------------------------
nuclear@0 977 aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform)
nuclear@0 978 {
nuclear@0 979 std::deque<const Object*> children;
nuclear@0 980 for(std::set<const Object*>::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) {
nuclear@0 981 const Object* object = *it;
nuclear@0 982 if (object->parent == obj) {
nuclear@0 983 children.push_back(object);
nuclear@0 984
nuclear@0 985 conv_data.objects.erase(it++);
nuclear@0 986 continue;
nuclear@0 987 }
nuclear@0 988 ++it;
nuclear@0 989 }
nuclear@0 990
nuclear@0 991 ScopeGuard<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB'
nuclear@0 992 if (obj->data) {
nuclear@0 993 switch (obj->type)
nuclear@0 994 {
nuclear@0 995 case Object :: Type_EMPTY:
nuclear@0 996 break; // do nothing
nuclear@0 997
nuclear@0 998
nuclear@0 999 // supported object types
nuclear@0 1000 case Object :: Type_MESH: {
nuclear@0 1001 const size_t old = conv_data.meshes->size();
nuclear@0 1002
nuclear@0 1003 CheckActualType(obj->data.get(),"Mesh");
nuclear@0 1004 ConvertMesh(in,obj,static_cast<const Mesh*>(obj->data.get()),conv_data,conv_data.meshes);
nuclear@0 1005
nuclear@0 1006 if (conv_data.meshes->size() > old) {
nuclear@0 1007 node->mMeshes = new unsigned int[node->mNumMeshes = static_cast<unsigned int>(conv_data.meshes->size()-old)];
nuclear@0 1008 for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
nuclear@0 1009 node->mMeshes[i] = i + old;
nuclear@0 1010 }
nuclear@0 1011 }}
nuclear@0 1012 break;
nuclear@0 1013 case Object :: Type_LAMP: {
nuclear@0 1014 CheckActualType(obj->data.get(),"Lamp");
nuclear@0 1015 aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>(
nuclear@0 1016 obj->data.get()),conv_data);
nuclear@0 1017
nuclear@0 1018 if (mesh) {
nuclear@0 1019 conv_data.lights->push_back(mesh);
nuclear@0 1020 }}
nuclear@0 1021 break;
nuclear@0 1022 case Object :: Type_CAMERA: {
nuclear@0 1023 CheckActualType(obj->data.get(),"Camera");
nuclear@0 1024 aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>(
nuclear@0 1025 obj->data.get()),conv_data);
nuclear@0 1026
nuclear@0 1027 if (mesh) {
nuclear@0 1028 conv_data.cameras->push_back(mesh);
nuclear@0 1029 }}
nuclear@0 1030 break;
nuclear@0 1031
nuclear@0 1032
nuclear@0 1033 // unsupported object types / log, but do not break
nuclear@0 1034 case Object :: Type_CURVE:
nuclear@0 1035 NotSupportedObjectType(obj,"Curve");
nuclear@0 1036 break;
nuclear@0 1037 case Object :: Type_SURF:
nuclear@0 1038 NotSupportedObjectType(obj,"Surface");
nuclear@0 1039 break;
nuclear@0 1040 case Object :: Type_FONT:
nuclear@0 1041 NotSupportedObjectType(obj,"Font");
nuclear@0 1042 break;
nuclear@0 1043 case Object :: Type_MBALL:
nuclear@0 1044 NotSupportedObjectType(obj,"MetaBall");
nuclear@0 1045 break;
nuclear@0 1046 case Object :: Type_WAVE:
nuclear@0 1047 NotSupportedObjectType(obj,"Wave");
nuclear@0 1048 break;
nuclear@0 1049 case Object :: Type_LATTICE:
nuclear@0 1050 NotSupportedObjectType(obj,"Lattice");
nuclear@0 1051 break;
nuclear@0 1052
nuclear@0 1053 // invalid or unknown type
nuclear@0 1054 default:
nuclear@0 1055 break;
nuclear@0 1056 }
nuclear@0 1057 }
nuclear@0 1058
nuclear@0 1059 for(unsigned int x = 0; x < 4; ++x) {
nuclear@0 1060 for(unsigned int y = 0; y < 4; ++y) {
nuclear@0 1061 node->mTransformation[y][x] = obj->obmat[x][y];
nuclear@0 1062 }
nuclear@0 1063 }
nuclear@0 1064
nuclear@0 1065 aiMatrix4x4 m = parentTransform;
nuclear@0 1066 m = m.Inverse();
nuclear@0 1067
nuclear@0 1068 node->mTransformation = m*node->mTransformation;
nuclear@0 1069
nuclear@0 1070 if (children.size()) {
nuclear@0 1071 node->mNumChildren = static_cast<unsigned int>(children.size());
nuclear@0 1072 aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
nuclear@0 1073 for_each (const Object* nobj,children) {
nuclear@0 1074 *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
nuclear@0 1075 (*nd++)->mParent = node;
nuclear@0 1076 }
nuclear@0 1077 }
nuclear@0 1078
nuclear@0 1079 // apply modifiers
nuclear@0 1080 modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
nuclear@0 1081
nuclear@0 1082 return node.dismiss();
nuclear@0 1083 }
nuclear@0 1084
nuclear@0 1085
nuclear@0 1086 #endif