vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/BlenderLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,1086 @@ 1.4 + 1.5 +/* 1.6 +Open Asset Import Library (assimp) 1.7 +---------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 +All rights reserved. 1.11 + 1.12 +Redistribution and use of this software in source and binary forms, 1.13 +with or without modification, are permitted provided that the 1.14 +following conditions are met: 1.15 + 1.16 +* Redistributions of source code must retain the above 1.17 + copyright notice, this list of conditions and the 1.18 + following disclaimer. 1.19 + 1.20 +* Redistributions in binary form must reproduce the above 1.21 + copyright notice, this list of conditions and the 1.22 + following disclaimer in the documentation and/or other 1.23 + materials provided with the distribution. 1.24 + 1.25 +* Neither the name of the assimp team, nor the names of its 1.26 + contributors may be used to endorse or promote products 1.27 + derived from this software without specific prior 1.28 + written permission of the assimp team. 1.29 + 1.30 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.31 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.32 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.33 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.34 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.35 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.36 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.37 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.38 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.39 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.40 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.41 + 1.42 +---------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file BlenderLoader.cpp 1.46 + * @brief Implementation of the Blender3D importer class. 1.47 + */ 1.48 +#include "AssimpPCH.h" 1.49 + 1.50 +//#define ASSIMP_BUILD_NO_COMPRESSED_BLEND 1.51 +// Uncomment this to disable support for (gzip)compressed .BLEND files 1.52 + 1.53 +#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER 1.54 + 1.55 +#include "BlenderIntermediate.h" 1.56 +#include "BlenderModifier.h" 1.57 + 1.58 +#include "StreamReader.h" 1.59 +#include "MemoryIOWrapper.h" 1.60 + 1.61 +// zlib is needed for compressed blend files 1.62 +#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND 1.63 +# ifdef ASSIMP_BUILD_NO_OWN_ZLIB 1.64 +# include <zlib.h> 1.65 +# else 1.66 +# include "../contrib/zlib/zlib.h" 1.67 +# endif 1.68 +#endif 1.69 + 1.70 +namespace Assimp { 1.71 + template<> const std::string LogFunctions<BlenderImporter>::log_prefix = "BLEND: "; 1.72 +} 1.73 + 1.74 +using namespace Assimp; 1.75 +using namespace Assimp::Blender; 1.76 +using namespace Assimp::Formatter; 1.77 + 1.78 +static const aiImporterDesc blenderDesc = { 1.79 + "Blender 3D Importer \nhttp://www.blender3d.org", 1.80 + "", 1.81 + "", 1.82 + "No animation support yet", 1.83 + aiImporterFlags_SupportBinaryFlavour, 1.84 + 0, 1.85 + 0, 1.86 + 2, 1.87 + 50, 1.88 + "blend" 1.89 +}; 1.90 + 1.91 + 1.92 +// ------------------------------------------------------------------------------------------------ 1.93 +// Constructor to be privately used by Importer 1.94 +BlenderImporter::BlenderImporter() 1.95 +: modifier_cache(new BlenderModifierShowcase()) 1.96 +{} 1.97 + 1.98 +// ------------------------------------------------------------------------------------------------ 1.99 +// Destructor, private as well 1.100 +BlenderImporter::~BlenderImporter() 1.101 +{ 1.102 + delete modifier_cache; 1.103 +} 1.104 + 1.105 +// ------------------------------------------------------------------------------------------------ 1.106 +// Returns whether the class can handle the format of the given file. 1.107 +bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.108 +{ 1.109 + const std::string& extension = GetExtension(pFile); 1.110 + if (extension == "blend") { 1.111 + return true; 1.112 + } 1.113 + 1.114 + else if ((!extension.length() || checkSig) && pIOHandler) { 1.115 + // note: this won't catch compressed files 1.116 + const char* tokens[] = {"BLENDER"}; 1.117 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); 1.118 + } 1.119 + return false; 1.120 +} 1.121 + 1.122 +// ------------------------------------------------------------------------------------------------ 1.123 +// List all extensions handled by this loader 1.124 +void BlenderImporter::GetExtensionList(std::set<std::string>& app) 1.125 +{ 1.126 + app.insert("blend"); 1.127 +} 1.128 + 1.129 +// ------------------------------------------------------------------------------------------------ 1.130 +// Loader registry entry 1.131 +const aiImporterDesc* BlenderImporter::GetInfo () const 1.132 +{ 1.133 + return &blenderDesc; 1.134 +} 1.135 + 1.136 +// ------------------------------------------------------------------------------------------------ 1.137 +// Setup configuration properties for the loader 1.138 +void BlenderImporter::SetupProperties(const Importer* /*pImp*/) 1.139 +{ 1.140 + // nothing to be done for the moment 1.141 +} 1.142 + 1.143 +struct free_it 1.144 +{ 1.145 + free_it(void* free) : free(free) {} 1.146 + ~free_it() { 1.147 + ::free(this->free); 1.148 + } 1.149 + 1.150 + void* free; 1.151 +}; 1.152 + 1.153 +// ------------------------------------------------------------------------------------------------ 1.154 +// Imports the given file into the given scene structure. 1.155 +void BlenderImporter::InternReadFile( const std::string& pFile, 1.156 + aiScene* pScene, IOSystem* pIOHandler) 1.157 +{ 1.158 +#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND 1.159 + Bytef* dest = NULL; 1.160 + free_it free_it_really(dest); 1.161 +#endif 1.162 + 1.163 + FileDatabase file; 1.164 + boost::shared_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb")); 1.165 + if (!stream) { 1.166 + ThrowException("Could not open file for reading"); 1.167 + } 1.168 + 1.169 + char magic[8] = {0}; 1.170 + stream->Read(magic,7,1); 1.171 + if (strcmp(magic,"BLENDER")) { 1.172 + // Check for presence of the gzip header. If yes, assume it is a 1.173 + // compressed blend file and try uncompressing it, else fail. This is to 1.174 + // avoid uncompressing random files which our loader might end up with. 1.175 +#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND 1.176 + ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"); 1.177 +#else 1.178 + 1.179 + if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) { 1.180 + ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either"); 1.181 + } 1.182 + 1.183 + LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file"); 1.184 + if (magic[2] != 8) { 1.185 + ThrowException("Unsupported GZIP compression method"); 1.186 + } 1.187 + 1.188 + // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer 1.189 + stream->Seek(0L,aiOrigin_SET); 1.190 + boost::shared_ptr<StreamReaderLE> reader = boost::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream)); 1.191 + 1.192 + // build a zlib stream 1.193 + z_stream zstream; 1.194 + zstream.opaque = Z_NULL; 1.195 + zstream.zalloc = Z_NULL; 1.196 + zstream.zfree = Z_NULL; 1.197 + zstream.data_type = Z_BINARY; 1.198 + 1.199 + // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib 1.200 + inflateInit2(&zstream, 16+MAX_WBITS); 1.201 + 1.202 + zstream.next_in = reinterpret_cast<Bytef*>( reader->GetPtr() ); 1.203 + zstream.avail_in = reader->GetRemainingSize(); 1.204 + 1.205 + size_t total = 0l; 1.206 + 1.207 + // and decompress the data .... do 1k chunks in the hope that we won't kill the stack 1.208 +#define MYBLOCK 1024 1.209 + Bytef block[MYBLOCK]; 1.210 + int ret; 1.211 + do { 1.212 + zstream.avail_out = MYBLOCK; 1.213 + zstream.next_out = block; 1.214 + ret = inflate(&zstream, Z_NO_FLUSH); 1.215 + 1.216 + if (ret != Z_STREAM_END && ret != Z_OK) { 1.217 + ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file"); 1.218 + } 1.219 + const size_t have = MYBLOCK - zstream.avail_out; 1.220 + total += have; 1.221 + dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); 1.222 + memcpy(dest + total - have,block,have); 1.223 + } 1.224 + while (ret != Z_STREAM_END); 1.225 + 1.226 + // terminate zlib 1.227 + inflateEnd(&zstream); 1.228 + 1.229 + // replace the input stream with a memory stream 1.230 + stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); 1.231 + 1.232 + // .. and retry 1.233 + stream->Read(magic,7,1); 1.234 + if (strcmp(magic,"BLENDER")) { 1.235 + ThrowException("Found no BLENDER magic word in decompressed GZIP file"); 1.236 + } 1.237 +#endif 1.238 + } 1.239 + 1.240 + file.i64bit = (stream->Read(magic,1,1),magic[0]=='-'); 1.241 + file.little = (stream->Read(magic,1,1),magic[0]=='v'); 1.242 + 1.243 + stream->Read(magic,3,1); 1.244 + magic[3] = '\0'; 1.245 + 1.246 + LogInfo((format(),"Blender version is ",magic[0],".",magic+1, 1.247 + " (64bit: ",file.i64bit?"true":"false", 1.248 + ", little endian: ",file.little?"true":"false",")" 1.249 + )); 1.250 + 1.251 + ParseBlendFile(file,stream); 1.252 + 1.253 + Scene scene; 1.254 + ExtractScene(scene,file); 1.255 + 1.256 + ConvertBlendFile(pScene,scene,file); 1.257 +} 1.258 + 1.259 +// ------------------------------------------------------------------------------------------------ 1.260 +void BlenderImporter::ParseBlendFile(FileDatabase& out, boost::shared_ptr<IOStream> stream) 1.261 +{ 1.262 + out.reader = boost::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream,out.little)); 1.263 + 1.264 + DNAParser dna_reader(out); 1.265 + const DNA* dna = NULL; 1.266 + 1.267 + out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks 1.268 + SectionParser parser(*out.reader.get(),out.i64bit); 1.269 + 1.270 + // first parse the file in search for the DNA and insert all other sections into the database 1.271 + while ((parser.Next(),1)) { 1.272 + const FileBlockHead& head = parser.GetCurrent(); 1.273 + 1.274 + if (head.id == "ENDB") { 1.275 + break; // only valid end of the file 1.276 + } 1.277 + else if (head.id == "DNA1") { 1.278 + dna_reader.Parse(); 1.279 + dna = &dna_reader.GetDNA(); 1.280 + continue; 1.281 + } 1.282 + 1.283 + out.entries.push_back(head); 1.284 + } 1.285 + } 1.286 + if (!dna) { 1.287 + ThrowException("SDNA not found"); 1.288 + } 1.289 + 1.290 + std::sort(out.entries.begin(),out.entries.end()); 1.291 +} 1.292 + 1.293 +// ------------------------------------------------------------------------------------------------ 1.294 +void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file) 1.295 +{ 1.296 + const FileBlockHead* block = NULL; 1.297 + std::map<std::string,size_t>::const_iterator it = file.dna.indices.find("Scene"); 1.298 + if (it == file.dna.indices.end()) { 1.299 + ThrowException("There is no `Scene` structure record"); 1.300 + } 1.301 + 1.302 + const Structure& ss = file.dna.structures[(*it).second]; 1.303 + 1.304 + // we need a scene somewhere to start with. 1.305 + for_each(const FileBlockHead& bl,file.entries) { 1.306 + 1.307 + // Fix: using the DNA index is more reliable to locate scenes 1.308 + //if (bl.id == "SC") { 1.309 + 1.310 + if (bl.dna_index == (*it).second) { 1.311 + block = &bl; 1.312 + break; 1.313 + } 1.314 + } 1.315 + 1.316 + if (!block) { 1.317 + ThrowException("There is not a single `Scene` record to load"); 1.318 + } 1.319 + 1.320 + file.reader->SetCurrentPos(block->start); 1.321 + ss.Convert(out,file); 1.322 + 1.323 +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS 1.324 + DefaultLogger::get()->info((format(), 1.325 + "(Stats) Fields read: " ,file.stats().fields_read, 1.326 + ", pointers resolved: " ,file.stats().pointers_resolved, 1.327 + ", cache hits: " ,file.stats().cache_hits, 1.328 + ", cached objects: " ,file.stats().cached_objects 1.329 + )); 1.330 +#endif 1.331 +} 1.332 + 1.333 +// ------------------------------------------------------------------------------------------------ 1.334 +void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileDatabase& file) 1.335 +{ 1.336 + ConversionData conv(file); 1.337 + 1.338 + // FIXME it must be possible to take the hierarchy directly from 1.339 + // the file. This is terrible. Here, we're first looking for 1.340 + // all objects which don't have parent objects at all - 1.341 + std::deque<const Object*> no_parents; 1.342 + for (boost::shared_ptr<Base> cur = boost::static_pointer_cast<Base> ( in.base.first ); cur; cur = cur->next) { 1.343 + if (cur->object) { 1.344 + if(!cur->object->parent) { 1.345 + no_parents.push_back(cur->object.get()); 1.346 + } 1.347 + else conv.objects.insert(cur->object.get()); 1.348 + } 1.349 + } 1.350 + for (boost::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) { 1.351 + if (cur->object) { 1.352 + if(cur->object->parent) { 1.353 + conv.objects.insert(cur->object.get()); 1.354 + } 1.355 + } 1.356 + } 1.357 + 1.358 + if (no_parents.empty()) { 1.359 + ThrowException("Expected at least one object with no parent"); 1.360 + } 1.361 + 1.362 + aiNode* root = out->mRootNode = new aiNode("<BlenderRoot>"); 1.363 + 1.364 + root->mNumChildren = static_cast<unsigned int>(no_parents.size()); 1.365 + root->mChildren = new aiNode*[root->mNumChildren](); 1.366 + for (unsigned int i = 0; i < root->mNumChildren; ++i) { 1.367 + root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4()); 1.368 + root->mChildren[i]->mParent = root; 1.369 + } 1.370 + 1.371 + BuildMaterials(conv); 1.372 + 1.373 + if (conv.meshes->size()) { 1.374 + out->mMeshes = new aiMesh*[out->mNumMeshes = static_cast<unsigned int>( conv.meshes->size() )]; 1.375 + std::copy(conv.meshes->begin(),conv.meshes->end(),out->mMeshes); 1.376 + conv.meshes.dismiss(); 1.377 + } 1.378 + 1.379 + if (conv.lights->size()) { 1.380 + out->mLights = new aiLight*[out->mNumLights = static_cast<unsigned int>( conv.lights->size() )]; 1.381 + std::copy(conv.lights->begin(),conv.lights->end(),out->mLights); 1.382 + conv.lights.dismiss(); 1.383 + } 1.384 + 1.385 + if (conv.cameras->size()) { 1.386 + out->mCameras = new aiCamera*[out->mNumCameras = static_cast<unsigned int>( conv.cameras->size() )]; 1.387 + std::copy(conv.cameras->begin(),conv.cameras->end(),out->mCameras); 1.388 + conv.cameras.dismiss(); 1.389 + } 1.390 + 1.391 + if (conv.materials->size()) { 1.392 + out->mMaterials = new aiMaterial*[out->mNumMaterials = static_cast<unsigned int>( conv.materials->size() )]; 1.393 + std::copy(conv.materials->begin(),conv.materials->end(),out->mMaterials); 1.394 + conv.materials.dismiss(); 1.395 + } 1.396 + 1.397 + if (conv.textures->size()) { 1.398 + out->mTextures = new aiTexture*[out->mNumTextures = static_cast<unsigned int>( conv.textures->size() )]; 1.399 + std::copy(conv.textures->begin(),conv.textures->end(),out->mTextures); 1.400 + conv.textures.dismiss(); 1.401 + } 1.402 + 1.403 + // acknowledge that the scene might come out incomplete 1.404 + // by Assimps definition of `complete`: blender scenes 1.405 + // can consist of thousands of cameras or lights with 1.406 + // not a single mesh between them. 1.407 + if (!out->mNumMeshes) { 1.408 + out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; 1.409 + } 1.410 +} 1.411 + 1.412 +// ------------------------------------------------------------------------------------------------ 1.413 +void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const MTex* tex, const Image* img, ConversionData& conv_data) 1.414 +{ 1.415 + (void)mat; (void)tex; (void)conv_data; 1.416 + aiString name; 1.417 + 1.418 + // check if the file contents are bundled with the BLEND file 1.419 + if (img->packedfile) { 1.420 + name.data[0] = '*'; 1.421 + name.length = 1+ ASSIMP_itoa10(name.data+1,MAXLEN-1,conv_data.textures->size()); 1.422 + 1.423 + conv_data.textures->push_back(new aiTexture()); 1.424 + aiTexture* tex = conv_data.textures->back(); 1.425 + 1.426 + // usually 'img->name' will be the original file name of the embedded textures, 1.427 + // so we can extract the file extension from it. 1.428 + const size_t nlen = strlen( img->name ); 1.429 + const char* s = img->name+nlen, *e = s; 1.430 + 1.431 + while (s >= img->name && *s != '.')--s; 1.432 + 1.433 + tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] ); 1.434 + tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] ); 1.435 + tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] ); 1.436 + tex->achFormatHint[3] = '\0'; 1.437 + 1.438 + // tex->mHeight = 0; 1.439 + tex->mWidth = img->packedfile->size; 1.440 + uint8_t* ch = new uint8_t[tex->mWidth]; 1.441 + 1.442 + conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val)); 1.443 + conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth); 1.444 + 1.445 + tex->pcData = reinterpret_cast<aiTexel*>(ch); 1.446 + 1.447 + LogInfo("Reading embedded texture, original file was "+std::string(img->name)); 1.448 + } 1.449 + else { 1.450 + name = aiString( img->name ); 1.451 + } 1.452 + out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE( 1.453 + conv_data.next_texture[aiTextureType_DIFFUSE]++) 1.454 + ); 1.455 +} 1.456 + 1.457 +// ------------------------------------------------------------------------------------------------ 1.458 +void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data) 1.459 +{ 1.460 + (void)mat; (void)tex; (void)conv_data; 1.461 + 1.462 + aiString name; 1.463 + name.length = sprintf(name.data, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++, 1.464 + GetTextureTypeDisplayString(tex->tex->type) 1.465 + ); 1.466 + out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE( 1.467 + conv_data.next_texture[aiTextureType_DIFFUSE]++) 1.468 + ); 1.469 +} 1.470 + 1.471 +// ------------------------------------------------------------------------------------------------ 1.472 +void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data) 1.473 +{ 1.474 + const Tex* rtex = tex->tex.get(); 1.475 + if(!rtex || !rtex->type) { 1.476 + return; 1.477 + } 1.478 + 1.479 + // We can't support most of the texture types because they're mostly procedural. 1.480 + // These are substituted by a dummy texture. 1.481 + const char* dispnam = ""; 1.482 + switch( rtex->type ) 1.483 + { 1.484 + // these are listed in blender's UI 1.485 + case Tex::Type_CLOUDS : 1.486 + case Tex::Type_WOOD : 1.487 + case Tex::Type_MARBLE : 1.488 + case Tex::Type_MAGIC : 1.489 + case Tex::Type_BLEND : 1.490 + case Tex::Type_STUCCI : 1.491 + case Tex::Type_NOISE : 1.492 + case Tex::Type_PLUGIN : 1.493 + case Tex::Type_MUSGRAVE : 1.494 + case Tex::Type_VORONOI : 1.495 + case Tex::Type_DISTNOISE : 1.496 + case Tex::Type_ENVMAP : 1.497 + 1.498 + // these do no appear in the UI, why? 1.499 + case Tex::Type_POINTDENSITY : 1.500 + case Tex::Type_VOXELDATA : 1.501 + 1.502 + LogWarn(std::string("Encountered a texture with an unsupported type: ")+dispnam); 1.503 + AddSentinelTexture(out, mat, tex, conv_data); 1.504 + break; 1.505 + 1.506 + case Tex::Type_IMAGE : 1.507 + if (!rtex->ima) { 1.508 + LogError("A texture claims to be an Image, but no image reference is given"); 1.509 + break; 1.510 + } 1.511 + ResolveImage(out, mat, tex, rtex->ima.get(),conv_data); 1.512 + break; 1.513 + 1.514 + default: 1.515 + ai_assert(false); 1.516 + }; 1.517 +} 1.518 + 1.519 +// ------------------------------------------------------------------------------------------------ 1.520 +void BlenderImporter::BuildMaterials(ConversionData& conv_data) 1.521 +{ 1.522 + conv_data.materials->reserve(conv_data.materials_raw.size()); 1.523 + 1.524 + // add a default material if necessary 1.525 + unsigned int index = static_cast<unsigned int>( -1 ); 1.526 + for_each( aiMesh* mesh, conv_data.meshes.get() ) { 1.527 + if (mesh->mMaterialIndex == static_cast<unsigned int>( -1 )) { 1.528 + 1.529 + if (index == static_cast<unsigned int>( -1 )) { 1.530 + 1.531 + // ok, we need to add a dedicated default material for some poor material-less meshes 1.532 + boost::shared_ptr<Material> p(new Material()); 1.533 + strcpy( p->id.name+2, AI_DEFAULT_MATERIAL_NAME ); 1.534 + 1.535 + p->r = p->g = p->b = 0.6f; 1.536 + p->specr = p->specg = p->specb = 0.6f; 1.537 + p->ambr = p->ambg = p->ambb = 0.0f; 1.538 + p->mirr = p->mirg = p->mirb = 0.0f; 1.539 + p->emit = 0.f; 1.540 + p->alpha = 0.f; 1.541 + 1.542 + // XXX add more / or add default c'tor to Material 1.543 + 1.544 + index = static_cast<unsigned int>( conv_data.materials_raw.size() ); 1.545 + conv_data.materials_raw.push_back(p); 1.546 + 1.547 + LogInfo("Adding default material ..."); 1.548 + } 1.549 + mesh->mMaterialIndex = index; 1.550 + } 1.551 + } 1.552 + 1.553 + for_each(boost::shared_ptr<Material> mat, conv_data.materials_raw) { 1.554 + 1.555 + // reset per material global counters 1.556 + for (size_t i = 0; i < sizeof(conv_data.next_texture)/sizeof(conv_data.next_texture[0]);++i) { 1.557 + conv_data.next_texture[i] = 0 ; 1.558 + } 1.559 + 1.560 + aiMaterial* mout = new aiMaterial(); 1.561 + conv_data.materials->push_back(mout); 1.562 + 1.563 + // set material name 1.564 + aiString name = aiString(mat->id.name+2); // skip over the name prefix 'MA' 1.565 + mout->AddProperty(&name,AI_MATKEY_NAME); 1.566 + 1.567 + 1.568 + // basic material colors 1.569 + aiColor3D col(mat->r,mat->g,mat->b); 1.570 + if (mat->r || mat->g || mat->b ) { 1.571 + 1.572 + // Usually, zero diffuse color means no diffuse color at all in the equation. 1.573 + // So we omit this member to express this intent. 1.574 + mout->AddProperty(&col,1,AI_MATKEY_COLOR_DIFFUSE); 1.575 + 1.576 + if (mat->emit) { 1.577 + aiColor3D emit_col(mat->emit * mat->r, mat->emit * mat->g, mat->emit * mat->b) ; 1.578 + mout->AddProperty(&emit_col, 1, AI_MATKEY_COLOR_EMISSIVE) ; 1.579 + } 1.580 + } 1.581 + 1.582 + col = aiColor3D(mat->specr,mat->specg,mat->specb); 1.583 + mout->AddProperty(&col,1,AI_MATKEY_COLOR_SPECULAR); 1.584 + 1.585 + // is hardness/shininess set? 1.586 + if( mat->har ) { 1.587 + const float har = mat->har; 1.588 + mout->AddProperty(&har,1,AI_MATKEY_SHININESS); 1.589 + } 1.590 + 1.591 + col = aiColor3D(mat->ambr,mat->ambg,mat->ambb); 1.592 + mout->AddProperty(&col,1,AI_MATKEY_COLOR_AMBIENT); 1.593 + 1.594 + col = aiColor3D(mat->mirr,mat->mirg,mat->mirb); 1.595 + mout->AddProperty(&col,1,AI_MATKEY_COLOR_REFLECTIVE); 1.596 + 1.597 + for(size_t i = 0; i < sizeof(mat->mtex) / sizeof(mat->mtex[0]); ++i) { 1.598 + if (!mat->mtex[i]) { 1.599 + continue; 1.600 + } 1.601 + 1.602 + ResolveTexture(mout,mat.get(),mat->mtex[i].get(),conv_data); 1.603 + } 1.604 + } 1.605 +} 1.606 + 1.607 +// ------------------------------------------------------------------------------------------------ 1.608 +void BlenderImporter::CheckActualType(const ElemBase* dt, const char* check) 1.609 +{ 1.610 + ai_assert(dt); 1.611 + if (strcmp(dt->dna_type,check)) { 1.612 + ThrowException((format(), 1.613 + "Expected object at ",std::hex,dt," to be of type `",check, 1.614 + "`, but it claims to be a `",dt->dna_type,"`instead" 1.615 + )); 1.616 + } 1.617 +} 1.618 + 1.619 +// ------------------------------------------------------------------------------------------------ 1.620 +void BlenderImporter::NotSupportedObjectType(const Object* obj, const char* type) 1.621 +{ 1.622 + LogWarn((format(), "Object `",obj->id.name,"` - type is unsupported: `",type, "`, skipping" )); 1.623 +} 1.624 + 1.625 +// ------------------------------------------------------------------------------------------------ 1.626 +void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, const Mesh* mesh, 1.627 + ConversionData& conv_data, TempArray<std::vector,aiMesh>& temp 1.628 + ) 1.629 +{ 1.630 + typedef std::pair<const int,size_t> MyPair; 1.631 + if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) { 1.632 + return; 1.633 + } 1.634 + 1.635 + // some sanity checks 1.636 + if (static_cast<size_t> ( mesh->totface ) > mesh->mface.size() ){ 1.637 + ThrowException("Number of faces is larger than the corresponding array"); 1.638 + } 1.639 + 1.640 + if (static_cast<size_t> ( mesh->totvert ) > mesh->mvert.size()) { 1.641 + ThrowException("Number of vertices is larger than the corresponding array"); 1.642 + } 1.643 + 1.644 + if (static_cast<size_t> ( mesh->totloop ) > mesh->mloop.size()) { 1.645 + ThrowException("Number of vertices is larger than the corresponding array"); 1.646 + } 1.647 + 1.648 + // collect per-submesh numbers 1.649 + std::map<int,size_t> per_mat; 1.650 + std::map<int,size_t> per_mat_verts; 1.651 + for (int i = 0; i < mesh->totface; ++i) { 1.652 + 1.653 + const MFace& mf = mesh->mface[i]; 1.654 + per_mat[ mf.mat_nr ]++; 1.655 + per_mat_verts[ mf.mat_nr ] += mf.v4?4:3; 1.656 + } 1.657 + 1.658 + for (int i = 0; i < mesh->totpoly; ++i) { 1.659 + const MPoly& mp = mesh->mpoly[i]; 1.660 + per_mat[ mp.mat_nr ]++; 1.661 + per_mat_verts[ mp.mat_nr ] += mp.totloop; 1.662 + } 1.663 + 1.664 + // ... and allocate the corresponding meshes 1.665 + const size_t old = temp->size(); 1.666 + temp->reserve(temp->size() + per_mat.size()); 1.667 + 1.668 + std::map<size_t,size_t> mat_num_to_mesh_idx; 1.669 + for_each(MyPair& it, per_mat) { 1.670 + 1.671 + mat_num_to_mesh_idx[it.first] = temp->size(); 1.672 + temp->push_back(new aiMesh()); 1.673 + 1.674 + aiMesh* out = temp->back(); 1.675 + out->mVertices = new aiVector3D[per_mat_verts[it.first]]; 1.676 + out->mNormals = new aiVector3D[per_mat_verts[it.first]]; 1.677 + 1.678 + //out->mNumFaces = 0 1.679 + //out->mNumVertices = 0 1.680 + out->mFaces = new aiFace[it.second](); 1.681 + 1.682 + // all submeshes created from this mesh are named equally. this allows 1.683 + // curious users to recover the original adjacency. 1.684 + out->mName = aiString(mesh->id.name+2); 1.685 + // skip over the name prefix 'ME' 1.686 + 1.687 + // resolve the material reference and add this material to the set of 1.688 + // output materials. The (temporary) material index is the index 1.689 + // of the material entry within the list of resolved materials. 1.690 + if (mesh->mat) { 1.691 + 1.692 + if (static_cast<size_t> ( it.first ) >= mesh->mat.size() ) { 1.693 + ThrowException("Material index is out of range"); 1.694 + } 1.695 + 1.696 + boost::shared_ptr<Material> mat = mesh->mat[it.first]; 1.697 + const std::deque< boost::shared_ptr<Material> >::iterator has = std::find( 1.698 + conv_data.materials_raw.begin(), 1.699 + conv_data.materials_raw.end(),mat 1.700 + ); 1.701 + 1.702 + if (has != conv_data.materials_raw.end()) { 1.703 + out->mMaterialIndex = static_cast<unsigned int>( std::distance(conv_data.materials_raw.begin(),has)); 1.704 + } 1.705 + else { 1.706 + out->mMaterialIndex = static_cast<unsigned int>( conv_data.materials_raw.size() ); 1.707 + conv_data.materials_raw.push_back(mat); 1.708 + } 1.709 + } 1.710 + else out->mMaterialIndex = static_cast<unsigned int>( -1 ); 1.711 + } 1.712 + 1.713 + for (int i = 0; i < mesh->totface; ++i) { 1.714 + 1.715 + const MFace& mf = mesh->mface[i]; 1.716 + 1.717 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ]; 1.718 + aiFace& f = out->mFaces[out->mNumFaces++]; 1.719 + 1.720 + f.mIndices = new unsigned int[ f.mNumIndices = mf.v4?4:3 ]; 1.721 + aiVector3D* vo = out->mVertices + out->mNumVertices; 1.722 + aiVector3D* vn = out->mNormals + out->mNumVertices; 1.723 + 1.724 + // XXX we can't fold this easily, because we are restricted 1.725 + // to the member names from the BLEND file (v1,v2,v3,v4) 1.726 + // which are assigned by the genblenddna.py script and 1.727 + // cannot be changed without breaking the entire 1.728 + // import process. 1.729 + 1.730 + if (mf.v1 >= mesh->totvert) { 1.731 + ThrowException("Vertex index v1 out of range"); 1.732 + } 1.733 + const MVert* v = &mesh->mvert[mf.v1]; 1.734 + vo->x = v->co[0]; 1.735 + vo->y = v->co[1]; 1.736 + vo->z = v->co[2]; 1.737 + vn->x = v->no[0]; 1.738 + vn->y = v->no[1]; 1.739 + vn->z = v->no[2]; 1.740 + f.mIndices[0] = out->mNumVertices++; 1.741 + ++vo; 1.742 + ++vn; 1.743 + 1.744 + // if (f.mNumIndices >= 2) { 1.745 + if (mf.v2 >= mesh->totvert) { 1.746 + ThrowException("Vertex index v2 out of range"); 1.747 + } 1.748 + v = &mesh->mvert[mf.v2]; 1.749 + vo->x = v->co[0]; 1.750 + vo->y = v->co[1]; 1.751 + vo->z = v->co[2]; 1.752 + vn->x = v->no[0]; 1.753 + vn->y = v->no[1]; 1.754 + vn->z = v->no[2]; 1.755 + f.mIndices[1] = out->mNumVertices++; 1.756 + ++vo; 1.757 + ++vn; 1.758 + 1.759 + if (mf.v3 >= mesh->totvert) { 1.760 + ThrowException("Vertex index v3 out of range"); 1.761 + } 1.762 + // if (f.mNumIndices >= 3) { 1.763 + v = &mesh->mvert[mf.v3]; 1.764 + vo->x = v->co[0]; 1.765 + vo->y = v->co[1]; 1.766 + vo->z = v->co[2]; 1.767 + vn->x = v->no[0]; 1.768 + vn->y = v->no[1]; 1.769 + vn->z = v->no[2]; 1.770 + f.mIndices[2] = out->mNumVertices++; 1.771 + ++vo; 1.772 + ++vn; 1.773 + 1.774 + if (mf.v4 >= mesh->totvert) { 1.775 + ThrowException("Vertex index v4 out of range"); 1.776 + } 1.777 + // if (f.mNumIndices >= 4) { 1.778 + if (mf.v4) { 1.779 + v = &mesh->mvert[mf.v4]; 1.780 + vo->x = v->co[0]; 1.781 + vo->y = v->co[1]; 1.782 + vo->z = v->co[2]; 1.783 + vn->x = v->no[0]; 1.784 + vn->y = v->no[1]; 1.785 + vn->z = v->no[2]; 1.786 + f.mIndices[3] = out->mNumVertices++; 1.787 + ++vo; 1.788 + ++vn; 1.789 + 1.790 + out->mPrimitiveTypes |= aiPrimitiveType_POLYGON; 1.791 + } 1.792 + else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; 1.793 + 1.794 + // } 1.795 + // } 1.796 + // } 1.797 + } 1.798 + 1.799 + for (int i = 0; i < mesh->totpoly; ++i) { 1.800 + 1.801 + const MPoly& mf = mesh->mpoly[i]; 1.802 + 1.803 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ]; 1.804 + aiFace& f = out->mFaces[out->mNumFaces++]; 1.805 + 1.806 + f.mIndices = new unsigned int[ f.mNumIndices = mf.totloop ]; 1.807 + aiVector3D* vo = out->mVertices + out->mNumVertices; 1.808 + aiVector3D* vn = out->mNormals + out->mNumVertices; 1.809 + 1.810 + // XXX we can't fold this easily, because we are restricted 1.811 + // to the member names from the BLEND file (v1,v2,v3,v4) 1.812 + // which are assigned by the genblenddna.py script and 1.813 + // cannot be changed without breaking the entire 1.814 + // import process. 1.815 + for (int j = 0;j < mf.totloop; ++j) 1.816 + { 1.817 + const MLoop& loop = mesh->mloop[mf.loopstart + j]; 1.818 + 1.819 + if (loop.v >= mesh->totvert) { 1.820 + ThrowException("Vertex index out of range"); 1.821 + } 1.822 + 1.823 + const MVert& v = mesh->mvert[loop.v]; 1.824 + 1.825 + vo->x = v.co[0]; 1.826 + vo->y = v.co[1]; 1.827 + vo->z = v.co[2]; 1.828 + vn->x = v.no[0]; 1.829 + vn->y = v.no[1]; 1.830 + vn->z = v.no[2]; 1.831 + f.mIndices[j] = out->mNumVertices++; 1.832 + 1.833 + ++vo; 1.834 + ++vn; 1.835 + 1.836 + } 1.837 + if (mf.totloop == 3) 1.838 + { 1.839 + out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; 1.840 + } 1.841 + else 1.842 + { 1.843 + out->mPrimitiveTypes |= aiPrimitiveType_POLYGON; 1.844 + } 1.845 + } 1.846 + 1.847 + // collect texture coordinates, they're stored in a separate per-face buffer 1.848 + if (mesh->mtface || mesh->mloopuv) { 1.849 + if (mesh->totface > static_cast<int> ( mesh->mtface.size())) { 1.850 + ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)"); 1.851 + } 1.852 + for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) { 1.853 + ai_assert((*it)->mNumVertices && (*it)->mNumFaces); 1.854 + 1.855 + (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices]; 1.856 + (*it)->mNumFaces = (*it)->mNumVertices = 0; 1.857 + } 1.858 + 1.859 + for (int i = 0; i < mesh->totface; ++i) { 1.860 + const MTFace* v = &mesh->mtface[i]; 1.861 + 1.862 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ]; 1.863 + const aiFace& f = out->mFaces[out->mNumFaces++]; 1.864 + 1.865 + aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; 1.866 + for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) { 1.867 + vo->x = v->uv[i][0]; 1.868 + vo->y = v->uv[i][1]; 1.869 + } 1.870 + } 1.871 + 1.872 + for (int i = 0; i < mesh->totpoly; ++i) { 1.873 + const MPoly& v = mesh->mpoly[i]; 1.874 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ]; 1.875 + const aiFace& f = out->mFaces[out->mNumFaces++]; 1.876 + 1.877 + aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; 1.878 + for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) { 1.879 + const MLoopUV& uv = mesh->mloopuv[v.loopstart + j]; 1.880 + vo->x = uv.uv[0]; 1.881 + vo->y = uv.uv[1]; 1.882 + } 1.883 + 1.884 + } 1.885 + } 1.886 + 1.887 + // collect texture coordinates, old-style (marked as deprecated in current blender sources) 1.888 + if (mesh->tface) { 1.889 + if (mesh->totface > static_cast<int> ( mesh->tface.size())) { 1.890 + ThrowException("Number of faces is larger than the corresponding UV face array (#2)"); 1.891 + } 1.892 + for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) { 1.893 + ai_assert((*it)->mNumVertices && (*it)->mNumFaces); 1.894 + 1.895 + (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices]; 1.896 + (*it)->mNumFaces = (*it)->mNumVertices = 0; 1.897 + } 1.898 + 1.899 + for (int i = 0; i < mesh->totface; ++i) { 1.900 + const TFace* v = &mesh->tface[i]; 1.901 + 1.902 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ]; 1.903 + const aiFace& f = out->mFaces[out->mNumFaces++]; 1.904 + 1.905 + aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; 1.906 + for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) { 1.907 + vo->x = v->uv[i][0]; 1.908 + vo->y = v->uv[i][1]; 1.909 + } 1.910 + } 1.911 + } 1.912 + 1.913 + // collect vertex colors, stored separately as well 1.914 + if (mesh->mcol || mesh->mloopcol) { 1.915 + if (mesh->totface > static_cast<int> ( (mesh->mcol.size()/4)) ) { 1.916 + ThrowException("Number of faces is larger than the corresponding color face array"); 1.917 + } 1.918 + for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) { 1.919 + ai_assert((*it)->mNumVertices && (*it)->mNumFaces); 1.920 + 1.921 + (*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices]; 1.922 + (*it)->mNumFaces = (*it)->mNumVertices = 0; 1.923 + } 1.924 + 1.925 + for (int i = 0; i < mesh->totface; ++i) { 1.926 + 1.927 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ]; 1.928 + const aiFace& f = out->mFaces[out->mNumFaces++]; 1.929 + 1.930 + aiColor4D* vo = &out->mColors[0][out->mNumVertices]; 1.931 + for (unsigned int n = 0; n < f.mNumIndices; ++n, ++vo,++out->mNumVertices) { 1.932 + const MCol* col = &mesh->mcol[(i<<2)+n]; 1.933 + 1.934 + vo->r = col->r; 1.935 + vo->g = col->g; 1.936 + vo->b = col->b; 1.937 + vo->a = col->a; 1.938 + } 1.939 + for (unsigned int n = f.mNumIndices; n < 4; ++n); 1.940 + } 1.941 + 1.942 + for (int i = 0; i < mesh->totpoly; ++i) { 1.943 + const MPoly& v = mesh->mpoly[i]; 1.944 + aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ]; 1.945 + const aiFace& f = out->mFaces[out->mNumFaces++]; 1.946 + 1.947 + aiColor4D* vo = &out->mColors[0][out->mNumVertices]; 1.948 + for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) { 1.949 + const MLoopCol& col = mesh->mloopcol[v.loopstart + j]; 1.950 + vo->r = col.r; 1.951 + vo->g = col.g; 1.952 + vo->b = col.b; 1.953 + vo->a = col.a; 1.954 + } 1.955 + 1.956 + } 1.957 + 1.958 + } 1.959 + 1.960 + return; 1.961 +} 1.962 + 1.963 +// ------------------------------------------------------------------------------------------------ 1.964 +aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* /*obj*/, const Camera* /*mesh*/, ConversionData& /*conv_data*/) 1.965 +{ 1.966 + ScopeGuard<aiCamera> out(new aiCamera()); 1.967 + 1.968 + return NULL ; //out.dismiss(); 1.969 +} 1.970 + 1.971 +// ------------------------------------------------------------------------------------------------ 1.972 +aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* /*obj*/, const Lamp* /*mesh*/, ConversionData& /*conv_data*/) 1.973 +{ 1.974 + ScopeGuard<aiLight> out(new aiLight()); 1.975 + 1.976 + return NULL ; //out.dismiss(); 1.977 +} 1.978 + 1.979 +// ------------------------------------------------------------------------------------------------ 1.980 +aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform) 1.981 +{ 1.982 + std::deque<const Object*> children; 1.983 + for(std::set<const Object*>::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) { 1.984 + const Object* object = *it; 1.985 + if (object->parent == obj) { 1.986 + children.push_back(object); 1.987 + 1.988 + conv_data.objects.erase(it++); 1.989 + continue; 1.990 + } 1.991 + ++it; 1.992 + } 1.993 + 1.994 + ScopeGuard<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB' 1.995 + if (obj->data) { 1.996 + switch (obj->type) 1.997 + { 1.998 + case Object :: Type_EMPTY: 1.999 + break; // do nothing 1.1000 + 1.1001 + 1.1002 + // supported object types 1.1003 + case Object :: Type_MESH: { 1.1004 + const size_t old = conv_data.meshes->size(); 1.1005 + 1.1006 + CheckActualType(obj->data.get(),"Mesh"); 1.1007 + ConvertMesh(in,obj,static_cast<const Mesh*>(obj->data.get()),conv_data,conv_data.meshes); 1.1008 + 1.1009 + if (conv_data.meshes->size() > old) { 1.1010 + node->mMeshes = new unsigned int[node->mNumMeshes = static_cast<unsigned int>(conv_data.meshes->size()-old)]; 1.1011 + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { 1.1012 + node->mMeshes[i] = i + old; 1.1013 + } 1.1014 + }} 1.1015 + break; 1.1016 + case Object :: Type_LAMP: { 1.1017 + CheckActualType(obj->data.get(),"Lamp"); 1.1018 + aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>( 1.1019 + obj->data.get()),conv_data); 1.1020 + 1.1021 + if (mesh) { 1.1022 + conv_data.lights->push_back(mesh); 1.1023 + }} 1.1024 + break; 1.1025 + case Object :: Type_CAMERA: { 1.1026 + CheckActualType(obj->data.get(),"Camera"); 1.1027 + aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>( 1.1028 + obj->data.get()),conv_data); 1.1029 + 1.1030 + if (mesh) { 1.1031 + conv_data.cameras->push_back(mesh); 1.1032 + }} 1.1033 + break; 1.1034 + 1.1035 + 1.1036 + // unsupported object types / log, but do not break 1.1037 + case Object :: Type_CURVE: 1.1038 + NotSupportedObjectType(obj,"Curve"); 1.1039 + break; 1.1040 + case Object :: Type_SURF: 1.1041 + NotSupportedObjectType(obj,"Surface"); 1.1042 + break; 1.1043 + case Object :: Type_FONT: 1.1044 + NotSupportedObjectType(obj,"Font"); 1.1045 + break; 1.1046 + case Object :: Type_MBALL: 1.1047 + NotSupportedObjectType(obj,"MetaBall"); 1.1048 + break; 1.1049 + case Object :: Type_WAVE: 1.1050 + NotSupportedObjectType(obj,"Wave"); 1.1051 + break; 1.1052 + case Object :: Type_LATTICE: 1.1053 + NotSupportedObjectType(obj,"Lattice"); 1.1054 + break; 1.1055 + 1.1056 + // invalid or unknown type 1.1057 + default: 1.1058 + break; 1.1059 + } 1.1060 + } 1.1061 + 1.1062 + for(unsigned int x = 0; x < 4; ++x) { 1.1063 + for(unsigned int y = 0; y < 4; ++y) { 1.1064 + node->mTransformation[y][x] = obj->obmat[x][y]; 1.1065 + } 1.1066 + } 1.1067 + 1.1068 + aiMatrix4x4 m = parentTransform; 1.1069 + m = m.Inverse(); 1.1070 + 1.1071 + node->mTransformation = m*node->mTransformation; 1.1072 + 1.1073 + if (children.size()) { 1.1074 + node->mNumChildren = static_cast<unsigned int>(children.size()); 1.1075 + aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren](); 1.1076 + for_each (const Object* nobj,children) { 1.1077 + *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform); 1.1078 + (*nd++)->mParent = node; 1.1079 + } 1.1080 + } 1.1081 + 1.1082 + // apply modifiers 1.1083 + modifier_cache->ApplyModifiers(*node,conv_data,in,*obj); 1.1084 + 1.1085 + return node.dismiss(); 1.1086 +} 1.1087 + 1.1088 + 1.1089 +#endif