vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/XGLLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,947 @@ 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 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file Implementation of the XGL/ZGL importer class */ 1.46 + 1.47 +#include "AssimpPCH.h" 1.48 +#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER 1.49 + 1.50 +#include "XGLLoader.h" 1.51 +#include "ParsingUtils.h" 1.52 +#include "fast_atof.h" 1.53 + 1.54 +#include "StreamReader.h" 1.55 +#include "MemoryIOWrapper.h" 1.56 + 1.57 +using namespace Assimp; 1.58 +using namespace irr; 1.59 +using namespace irr::io; 1.60 + 1.61 + 1.62 +// zlib is needed for compressed XGL files 1.63 +#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL 1.64 +# ifdef ASSIMP_BUILD_NO_OWN_ZLIB 1.65 +# include <zlib.h> 1.66 +# else 1.67 +# include "../contrib/zlib/zlib.h" 1.68 +# endif 1.69 +#endif 1.70 + 1.71 + 1.72 +// scopeguard for a malloc'ed buffer 1.73 +struct free_it 1.74 +{ 1.75 + free_it(void* free) : free(free) {} 1.76 + ~free_it() { 1.77 + ::free(this->free); 1.78 + } 1.79 + 1.80 + void* free; 1.81 +}; 1.82 + 1.83 +namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp 1.84 +template<> const std::string LogFunctions<XGLImporter>::log_prefix = "XGL: "; 1.85 + 1.86 +} 1.87 + 1.88 +static const aiImporterDesc desc = { 1.89 + "XGL Importer", 1.90 + "", 1.91 + "", 1.92 + "", 1.93 + aiImporterFlags_SupportTextFlavour, 1.94 + 0, 1.95 + 0, 1.96 + 0, 1.97 + 0, 1.98 + "xgl zgl" 1.99 +}; 1.100 + 1.101 + 1.102 +// ------------------------------------------------------------------------------------------------ 1.103 +// Constructor to be privately used by Importer 1.104 +XGLImporter::XGLImporter() 1.105 +{} 1.106 + 1.107 +// ------------------------------------------------------------------------------------------------ 1.108 +// Destructor, private as well 1.109 +XGLImporter::~XGLImporter() 1.110 +{} 1.111 + 1.112 +// ------------------------------------------------------------------------------------------------ 1.113 +// Returns whether the class can handle the format of the given file. 1.114 +bool XGLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.115 +{ 1.116 + /* NOTE: A simple check for the file extension is not enough 1.117 + * here. XGL and ZGL are ok, but xml is too generic 1.118 + * and might be collada as well. So open the file and 1.119 + * look for typical signal tokens. 1.120 + */ 1.121 + const std::string extension = GetExtension(pFile); 1.122 + 1.123 + if (extension == "xgl" || extension == "zgl") { 1.124 + return true; 1.125 + } 1.126 + else if (extension == "xml" || checkSig) { 1.127 + ai_assert(pIOHandler != NULL); 1.128 + 1.129 + const char* tokens[] = {"<world>","<World>","<WORLD>"}; 1.130 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,3); 1.131 + } 1.132 + return false; 1.133 +} 1.134 + 1.135 +// ------------------------------------------------------------------------------------------------ 1.136 +// Get a list of all file extensions which are handled by this class 1.137 +const aiImporterDesc* XGLImporter::GetInfo () const 1.138 +{ 1.139 + return &desc; 1.140 +} 1.141 + 1.142 +// ------------------------------------------------------------------------------------------------ 1.143 +// Imports the given file into the given scene structure. 1.144 +void XGLImporter::InternReadFile( const std::string& pFile, 1.145 + aiScene* pScene, IOSystem* pIOHandler) 1.146 +{ 1.147 +#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL 1.148 + Bytef* dest = NULL; 1.149 + free_it free_it_really(dest); 1.150 +#endif 1.151 + 1.152 + scene = pScene; 1.153 + boost::shared_ptr<IOStream> stream( pIOHandler->Open( pFile, "rb")); 1.154 + 1.155 + // check whether we can read from the file 1.156 + if( stream.get() == NULL) { 1.157 + throw DeadlyImportError( "Failed to open XGL/ZGL file " + pFile + ""); 1.158 + } 1.159 + 1.160 + // see if its compressed, if so uncompress it 1.161 + if (GetExtension(pFile) == "zgl") { 1.162 +#ifdef ASSIMP_BUILD_NO_COMPRESSED_XGL 1.163 + ThrowException("Cannot read ZGL file since Assimp was built without compression support"); 1.164 +#else 1.165 + boost::scoped_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream)); 1.166 + 1.167 + // build a zlib stream 1.168 + z_stream zstream; 1.169 + zstream.opaque = Z_NULL; 1.170 + zstream.zalloc = Z_NULL; 1.171 + zstream.zfree = Z_NULL; 1.172 + zstream.data_type = Z_BINARY; 1.173 + 1.174 + // raw decompression without a zlib or gzip header 1.175 + inflateInit2(&zstream, -MAX_WBITS); 1.176 + 1.177 + // skip two extra bytes, zgl files do carry a crc16 upfront (I think) 1.178 + raw_reader->IncPtr(2); 1.179 + 1.180 + zstream.next_in = reinterpret_cast<Bytef*>( raw_reader->GetPtr() ); 1.181 + zstream.avail_in = raw_reader->GetRemainingSize(); 1.182 + 1.183 + size_t total = 0l; 1.184 + 1.185 + // and decompress the data .... do 1k chunks in the hope that we won't kill the stack 1.186 + #define MYBLOCK 1024 1.187 + Bytef block[MYBLOCK]; 1.188 + int ret; 1.189 + do { 1.190 + zstream.avail_out = MYBLOCK; 1.191 + zstream.next_out = block; 1.192 + ret = inflate(&zstream, Z_NO_FLUSH); 1.193 + 1.194 + if (ret != Z_STREAM_END && ret != Z_OK) { 1.195 + ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .XGL file"); 1.196 + } 1.197 + const size_t have = MYBLOCK - zstream.avail_out; 1.198 + total += have; 1.199 + dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); 1.200 + memcpy(dest + total - have,block,have); 1.201 + } 1.202 + while (ret != Z_STREAM_END); 1.203 + 1.204 + // terminate zlib 1.205 + inflateEnd(&zstream); 1.206 + 1.207 + // replace the input stream with a memory stream 1.208 + stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); 1.209 +#endif 1.210 + } 1.211 + 1.212 + // construct the irrXML parser 1.213 + CIrrXML_IOStreamReader st(stream.get()); 1.214 + boost::scoped_ptr<IrrXMLReader> read( createIrrXMLReader((IFileReadCallBack*) &st) ); 1.215 + reader = read.get(); 1.216 + 1.217 + // parse the XML file 1.218 + TempScope scope; 1.219 + 1.220 + while (ReadElement()) { 1.221 + if (!ASSIMP_stricmp(reader->getNodeName(),"world")) { 1.222 + ReadWorld(scope); 1.223 + } 1.224 + } 1.225 + 1.226 + 1.227 + std::vector<aiMesh*>& meshes = scope.meshes_linear; 1.228 + std::vector<aiMaterial*>& materials = scope.materials_linear; 1.229 + if(!meshes.size() || !materials.size()) { 1.230 + ThrowException("failed to extract data from XGL file, no meshes loaded"); 1.231 + } 1.232 + 1.233 + // copy meshes 1.234 + scene->mNumMeshes = static_cast<unsigned int>(meshes.size()); 1.235 + scene->mMeshes = new aiMesh*[scene->mNumMeshes](); 1.236 + std::copy(meshes.begin(),meshes.end(),scene->mMeshes); 1.237 + 1.238 + // copy materials 1.239 + scene->mNumMaterials = static_cast<unsigned int>(materials.size()); 1.240 + scene->mMaterials = new aiMaterial*[scene->mNumMaterials](); 1.241 + std::copy(materials.begin(),materials.end(),scene->mMaterials); 1.242 + 1.243 + if (scope.light) { 1.244 + scene->mNumLights = 1; 1.245 + scene->mLights = new aiLight*[1]; 1.246 + scene->mLights[0] = scope.light; 1.247 + 1.248 + scope.light->mName = scene->mRootNode->mName; 1.249 + } 1.250 + 1.251 + scope.dismiss(); 1.252 +} 1.253 + 1.254 +// ------------------------------------------------------------------------------------------------ 1.255 +bool XGLImporter::ReadElement() 1.256 +{ 1.257 + while(reader->read()) { 1.258 + if (reader->getNodeType() == EXN_ELEMENT) { 1.259 + return true; 1.260 + } 1.261 + } 1.262 + return false; 1.263 +} 1.264 + 1.265 +// ------------------------------------------------------------------------------------------------ 1.266 +bool XGLImporter::ReadElementUpToClosing(const char* closetag) 1.267 +{ 1.268 + while(reader->read()) { 1.269 + if (reader->getNodeType() == EXN_ELEMENT) { 1.270 + return true; 1.271 + } 1.272 + else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),closetag)) { 1.273 + return false; 1.274 + } 1.275 + } 1.276 + LogError("unexpected EOF, expected closing <" + std::string(closetag) + "> tag"); 1.277 + return false; 1.278 +} 1.279 + 1.280 +// ------------------------------------------------------------------------------------------------ 1.281 +bool XGLImporter::SkipToText() 1.282 +{ 1.283 + while(reader->read()) { 1.284 + if (reader->getNodeType() == EXN_TEXT) { 1.285 + return true; 1.286 + } 1.287 + else if (reader->getNodeType() == EXN_ELEMENT || reader->getNodeType() == EXN_ELEMENT_END) { 1.288 + ThrowException("expected text contents but found another element (or element end)"); 1.289 + } 1.290 + } 1.291 + return false; 1.292 +} 1.293 + 1.294 +// ------------------------------------------------------------------------------------------------ 1.295 +std::string XGLImporter::GetElementName() 1.296 +{ 1.297 + const char* s = reader->getNodeName(); 1.298 + size_t len = strlen(s); 1.299 + 1.300 + std::string ret; 1.301 + ret.resize(len); 1.302 + 1.303 + std::transform(s,s+len,ret.begin(),::tolower); 1.304 + return ret; 1.305 +} 1.306 + 1.307 +// ------------------------------------------------------------------------------------------------ 1.308 +void XGLImporter::ReadWorld(TempScope& scope) 1.309 +{ 1.310 + while (ReadElementUpToClosing("world")) { 1.311 + const std::string& s = GetElementName(); 1.312 + // XXX right now we'd skip <lighting> if it comes after 1.313 + // <object> or <mesh> 1.314 + if (s == "lighting") { 1.315 + ReadLighting(scope); 1.316 + } 1.317 + else if (s == "object" || s == "mesh" || s == "mat") { 1.318 + break; 1.319 + } 1.320 + } 1.321 + 1.322 + 1.323 + aiNode* const nd = ReadObject(scope,true,"world"); 1.324 + if(!nd) { 1.325 + ThrowException("failure reading <world>"); 1.326 + } 1.327 + if(!nd->mName.length) { 1.328 + nd->mName.Set("WORLD"); 1.329 + } 1.330 + 1.331 + scene->mRootNode = nd; 1.332 +} 1.333 + 1.334 +// ------------------------------------------------------------------------------------------------ 1.335 +void XGLImporter::ReadLighting(TempScope& scope) 1.336 +{ 1.337 + while (ReadElementUpToClosing("lighting")) { 1.338 + const std::string& s = GetElementName(); 1.339 + if (s == "directionallight") { 1.340 + scope.light = ReadDirectionalLight(); 1.341 + } 1.342 + else if (s == "ambient") { 1.343 + LogWarn("ignoring <ambient> tag"); 1.344 + } 1.345 + else if (s == "spheremap") { 1.346 + LogWarn("ignoring <spheremap> tag"); 1.347 + } 1.348 + } 1.349 +} 1.350 + 1.351 +// ------------------------------------------------------------------------------------------------ 1.352 +aiLight* XGLImporter::ReadDirectionalLight() 1.353 +{ 1.354 + ScopeGuard<aiLight> l(new aiLight()); 1.355 + l->mType = aiLightSource_DIRECTIONAL; 1.356 + 1.357 + while (ReadElementUpToClosing("directionallight")) { 1.358 + const std::string& s = GetElementName(); 1.359 + if (s == "direction") { 1.360 + l->mDirection = ReadVec3(); 1.361 + } 1.362 + else if (s == "diffuse") { 1.363 + l->mColorDiffuse = ReadCol3(); 1.364 + } 1.365 + else if (s == "specular") { 1.366 + l->mColorSpecular = ReadCol3(); 1.367 + } 1.368 + } 1.369 + return l.dismiss(); 1.370 +} 1.371 + 1.372 +// ------------------------------------------------------------------------------------------------ 1.373 +aiNode* XGLImporter::ReadObject(TempScope& scope, bool skipFirst, const char* closetag) 1.374 +{ 1.375 + ScopeGuard<aiNode> nd(new aiNode()); 1.376 + std::vector<aiNode*> children; 1.377 + std::vector<unsigned int> meshes; 1.378 + 1.379 + try { 1.380 + while (skipFirst || ReadElementUpToClosing(closetag)) { 1.381 + skipFirst = false; 1.382 + 1.383 + const std::string& s = GetElementName(); 1.384 + if (s == "mesh") { 1.385 + const size_t prev = scope.meshes_linear.size(); 1.386 + if(ReadMesh(scope)) { 1.387 + const size_t newc = scope.meshes_linear.size(); 1.388 + for(size_t i = 0; i < newc-prev; ++i) { 1.389 + meshes.push_back(static_cast<unsigned int>(i+prev)); 1.390 + } 1.391 + } 1.392 + } 1.393 + else if (s == "mat") { 1.394 + ReadMaterial(scope); 1.395 + } 1.396 + else if (s == "object") { 1.397 + children.push_back(ReadObject(scope)); 1.398 + } 1.399 + else if (s == "objectref") { 1.400 + // XXX 1.401 + } 1.402 + else if (s == "meshref") { 1.403 + const unsigned int id = static_cast<unsigned int>( ReadIndexFromText() ); 1.404 + 1.405 + std::multimap<unsigned int, aiMesh*>::iterator it = scope.meshes.find(id), end = scope.meshes.end(); 1.406 + if (it == end) { 1.407 + ThrowException("<meshref> index out of range"); 1.408 + } 1.409 + 1.410 + for(; it != end && (*it).first == id; ++it) { 1.411 + // ok, this is n^2 and should get optimized one day 1.412 + aiMesh* const m = (*it).second; 1.413 + 1.414 + unsigned int i = 0, mcount = static_cast<unsigned int>(scope.meshes_linear.size()); 1.415 + for(; i < mcount; ++i) { 1.416 + if (scope.meshes_linear[i] == m) { 1.417 + meshes.push_back(i); 1.418 + break; 1.419 + } 1.420 + } 1.421 + 1.422 + ai_assert(i < mcount); 1.423 + } 1.424 + } 1.425 + else if (s == "transform") { 1.426 + nd->mTransformation = ReadTrafo(); 1.427 + } 1.428 + } 1.429 + 1.430 + } catch(...) { 1.431 + BOOST_FOREACH(aiNode* ch, children) { 1.432 + delete ch; 1.433 + } 1.434 + throw; 1.435 + } 1.436 + 1.437 + // link meshes to node 1.438 + nd->mNumMeshes = static_cast<unsigned int>(meshes.size()); 1.439 + if (nd->mNumMeshes) { 1.440 + nd->mMeshes = new unsigned int[nd->mNumMeshes](); 1.441 + for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { 1.442 + nd->mMeshes[i] = meshes[i]; 1.443 + } 1.444 + } 1.445 + 1.446 + // link children to parent 1.447 + nd->mNumChildren = static_cast<unsigned int>(children.size()); 1.448 + if (nd->mNumChildren) { 1.449 + nd->mChildren = new aiNode*[nd->mNumChildren](); 1.450 + for(unsigned int i = 0; i < nd->mNumChildren; ++i) { 1.451 + nd->mChildren[i] = children[i]; 1.452 + children[i]->mParent = nd; 1.453 + } 1.454 + } 1.455 + 1.456 + return nd.dismiss(); 1.457 +} 1.458 + 1.459 +// ------------------------------------------------------------------------------------------------ 1.460 +aiMatrix4x4 XGLImporter::ReadTrafo() 1.461 +{ 1.462 + aiVector3D forward, up, right, position; 1.463 + float scale = 1.0f; 1.464 + 1.465 + while (ReadElementUpToClosing("transform")) { 1.466 + const std::string& s = GetElementName(); 1.467 + if (s == "forward") { 1.468 + forward = ReadVec3(); 1.469 + } 1.470 + else if (s == "up") { 1.471 + up = ReadVec3(); 1.472 + } 1.473 + else if (s == "position") { 1.474 + position = ReadVec3(); 1.475 + } 1.476 + if (s == "scale") { 1.477 + scale = ReadFloat(); 1.478 + if(scale < 0.f) { 1.479 + // this is wrong, but we can leave the value and pass it to the caller 1.480 + LogError("found negative scaling in <transform>, ignoring"); 1.481 + } 1.482 + } 1.483 + } 1.484 + 1.485 + aiMatrix4x4 m; 1.486 + if(forward.SquareLength() < 1e-4 || up.SquareLength() < 1e-4) { 1.487 + LogError("A direction vector in <transform> is zero, ignoring trafo"); 1.488 + return m; 1.489 + } 1.490 + 1.491 + forward.Normalize(); 1.492 + up.Normalize(); 1.493 + 1.494 + right = forward ^ up; 1.495 + if (fabs(up * forward) > 1e-4) { 1.496 + // this is definitely wrong - a degenerate coordinate space ruins everything 1.497 + // so subtitute identity transform. 1.498 + LogError("<forward> and <up> vectors in <transform> are skewing, ignoring trafo"); 1.499 + return m; 1.500 + } 1.501 + 1.502 + right *= scale; 1.503 + up *= scale; 1.504 + forward *= scale; 1.505 + 1.506 + m.a1 = right.x; 1.507 + m.b1 = right.y; 1.508 + m.c1 = right.z; 1.509 + 1.510 + m.a2 = up.x; 1.511 + m.b2 = up.y; 1.512 + m.c2 = up.z; 1.513 + 1.514 + m.a3 = forward.x; 1.515 + m.b3 = forward.y; 1.516 + m.c3 = forward.z; 1.517 + 1.518 + m.a4 = position.x; 1.519 + m.b4 = position.y; 1.520 + m.c4 = position.z; 1.521 + 1.522 + return m; 1.523 +} 1.524 + 1.525 +// ------------------------------------------------------------------------------------------------ 1.526 +aiMesh* XGLImporter::ToOutputMesh(const TempMaterialMesh& m) 1.527 +{ 1.528 + ScopeGuard<aiMesh> mesh(new aiMesh()); 1.529 + 1.530 + mesh->mNumVertices = static_cast<unsigned int>(m.positions.size()); 1.531 + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; 1.532 + std::copy(m.positions.begin(),m.positions.end(),mesh->mVertices); 1.533 + 1.534 + if(m.normals.size()) { 1.535 + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; 1.536 + std::copy(m.normals.begin(),m.normals.end(),mesh->mNormals); 1.537 + } 1.538 + 1.539 + if(m.uvs.size()) { 1.540 + mesh->mNumUVComponents[0] = 2; 1.541 + mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; 1.542 + 1.543 + for(unsigned int i = 0; i < mesh->mNumVertices; ++i) { 1.544 + mesh->mTextureCoords[0][i] = aiVector3D(m.uvs[i].x,m.uvs[i].y,0.f); 1.545 + } 1.546 + } 1.547 + 1.548 + mesh->mNumFaces = static_cast<unsigned int>(m.vcounts.size()); 1.549 + mesh->mFaces = new aiFace[m.vcounts.size()]; 1.550 + 1.551 + unsigned int idx = 0; 1.552 + for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { 1.553 + aiFace& f = mesh->mFaces[i]; 1.554 + f.mNumIndices = m.vcounts[i]; 1.555 + f.mIndices = new unsigned int[f.mNumIndices]; 1.556 + for(unsigned int c = 0; c < f.mNumIndices; ++c) { 1.557 + f.mIndices[c] = idx++; 1.558 + } 1.559 + } 1.560 + 1.561 + ai_assert(idx == mesh->mNumVertices); 1.562 + 1.563 + mesh->mPrimitiveTypes = m.pflags; 1.564 + mesh->mMaterialIndex = m.matid; 1.565 + return mesh.dismiss(); 1.566 +} 1.567 + 1.568 +// ------------------------------------------------------------------------------------------------ 1.569 +bool XGLImporter::ReadMesh(TempScope& scope) 1.570 +{ 1.571 + TempMesh t; 1.572 + 1.573 + std::map<unsigned int, TempMaterialMesh> bymat; 1.574 + const unsigned int mesh_id = ReadIDAttr(); 1.575 + 1.576 + while (ReadElementUpToClosing("mesh")) { 1.577 + const std::string& s = GetElementName(); 1.578 + 1.579 + if (s == "mat") { 1.580 + ReadMaterial(scope); 1.581 + } 1.582 + else if (s == "p") { 1.583 + if (!reader->getAttributeValue("ID")) { 1.584 + LogWarn("no ID attribute on <p>, ignoring"); 1.585 + } 1.586 + else { 1.587 + int id = reader->getAttributeValueAsInt("ID"); 1.588 + t.points[id] = ReadVec3(); 1.589 + } 1.590 + } 1.591 + else if (s == "n") { 1.592 + if (!reader->getAttributeValue("ID")) { 1.593 + LogWarn("no ID attribute on <n>, ignoring"); 1.594 + } 1.595 + else { 1.596 + int id = reader->getAttributeValueAsInt("ID"); 1.597 + t.normals[id] = ReadVec3(); 1.598 + } 1.599 + } 1.600 + else if (s == "tc") { 1.601 + if (!reader->getAttributeValue("ID")) { 1.602 + LogWarn("no ID attribute on <tc>, ignoring"); 1.603 + } 1.604 + else { 1.605 + int id = reader->getAttributeValueAsInt("ID"); 1.606 + t.uvs[id] = ReadVec2(); 1.607 + } 1.608 + } 1.609 + else if (s == "f" || s == "l" || s == "p") { 1.610 + const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1); 1.611 + 1.612 + unsigned int mid = ~0u; 1.613 + TempFace tf[3]; 1.614 + bool has[3] = {0}; 1.615 + 1.616 + while (ReadElementUpToClosing(s.c_str())) { 1.617 + const std::string& s = GetElementName(); 1.618 + if (s == "fv1" || s == "lv1" || s == "pv1") { 1.619 + ReadFaceVertex(t,tf[0]); 1.620 + has[0] = true; 1.621 + } 1.622 + else if (s == "fv2" || s == "lv2") { 1.623 + ReadFaceVertex(t,tf[1]); 1.624 + has[1] = true; 1.625 + } 1.626 + else if (s == "fv3") { 1.627 + ReadFaceVertex(t,tf[2]); 1.628 + has[2] = true; 1.629 + } 1.630 + else if (s == "mat") { 1.631 + if (mid != ~0u) { 1.632 + LogWarn("only one material tag allowed per <f>"); 1.633 + } 1.634 + mid = ResolveMaterialRef(scope); 1.635 + } 1.636 + else if (s == "matref") { 1.637 + if (mid != ~0u) { 1.638 + LogWarn("only one material tag allowed per <f>"); 1.639 + } 1.640 + mid = ResolveMaterialRef(scope); 1.641 + } 1.642 + } 1.643 + 1.644 + if (mid == ~0u) { 1.645 + ThrowException("missing material index"); 1.646 + } 1.647 + 1.648 + bool nor = false; 1.649 + bool uv = false; 1.650 + for(unsigned int i = 0; i < vcount; ++i) { 1.651 + if (!has[i]) { 1.652 + ThrowException("missing face vertex data"); 1.653 + } 1.654 + 1.655 + nor = nor || tf[i].has_normal; 1.656 + uv = uv || tf[i].has_uv; 1.657 + } 1.658 + 1.659 + if (mid >= (1<<30)) { 1.660 + LogWarn("material indices exhausted, this may cause errors in the output"); 1.661 + } 1.662 + unsigned int meshId = mid | ((nor?1:0)<<31) | ((uv?1:0)<<30); 1.663 + 1.664 + TempMaterialMesh& mesh = bymat[meshId]; 1.665 + mesh.matid = mid; 1.666 + 1.667 + for(unsigned int i = 0; i < vcount; ++i) { 1.668 + mesh.positions.push_back(tf[i].pos); 1.669 + if(nor) { 1.670 + mesh.normals.push_back(tf[i].normal); 1.671 + } 1.672 + if(uv) { 1.673 + mesh.uvs.push_back(tf[i].uv); 1.674 + } 1.675 + 1.676 + mesh.pflags |= 1 << (vcount-1); 1.677 + } 1.678 + 1.679 + mesh.vcounts.push_back(vcount); 1.680 + } 1.681 + } 1.682 + 1.683 + // finally extract output meshes and add them to the scope 1.684 + typedef std::pair<unsigned int, TempMaterialMesh> pairt; 1.685 + BOOST_FOREACH(const pairt& p, bymat) { 1.686 + aiMesh* const m = ToOutputMesh(p.second); 1.687 + scope.meshes_linear.push_back(m); 1.688 + 1.689 + // if this is a definition, keep it on the stack 1.690 + if(mesh_id != ~0u) { 1.691 + scope.meshes.insert(std::pair<unsigned int, aiMesh*>(mesh_id,m)); 1.692 + } 1.693 + } 1.694 + 1.695 + // no id == not a reference, insert this mesh right *here* 1.696 + return mesh_id == ~0u; 1.697 +} 1.698 + 1.699 +// ---------------------------------------------------------------------------------------------- 1.700 +unsigned int XGLImporter::ResolveMaterialRef(TempScope& scope) 1.701 +{ 1.702 + const std::string& s = GetElementName(); 1.703 + if (s == "mat") { 1.704 + ReadMaterial(scope); 1.705 + return scope.materials_linear.size()-1; 1.706 + } 1.707 + 1.708 + const int id = ReadIndexFromText(); 1.709 + 1.710 + std::map<unsigned int, aiMaterial*>::iterator it = scope.materials.find(id), end = scope.materials.end(); 1.711 + if (it == end) { 1.712 + ThrowException("<matref> index out of range"); 1.713 + } 1.714 + 1.715 + // ok, this is n^2 and should get optimized one day 1.716 + aiMaterial* const m = (*it).second; 1.717 + 1.718 + unsigned int i = 0, mcount = static_cast<unsigned int>(scope.materials_linear.size()); 1.719 + for(; i < mcount; ++i) { 1.720 + if (scope.materials_linear[i] == m) { 1.721 + return i; 1.722 + } 1.723 + } 1.724 + 1.725 + ai_assert(false); 1.726 + return 0; 1.727 +} 1.728 + 1.729 +// ------------------------------------------------------------------------------------------------ 1.730 +void XGLImporter::ReadMaterial(TempScope& scope) 1.731 +{ 1.732 + const unsigned int mat_id = ReadIDAttr(); 1.733 + 1.734 + ScopeGuard<aiMaterial> mat(new aiMaterial()); 1.735 + while (ReadElementUpToClosing("mat")) { 1.736 + const std::string& s = GetElementName(); 1.737 + if (s == "amb") { 1.738 + const aiColor3D c = ReadCol3(); 1.739 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT); 1.740 + } 1.741 + else if (s == "diff") { 1.742 + const aiColor3D c = ReadCol3(); 1.743 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE); 1.744 + } 1.745 + else if (s == "spec") { 1.746 + const aiColor3D c = ReadCol3(); 1.747 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR); 1.748 + } 1.749 + else if (s == "emiss") { 1.750 + const aiColor3D c = ReadCol3(); 1.751 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_EMISSIVE); 1.752 + } 1.753 + else if (s == "alpha") { 1.754 + const float f = ReadFloat(); 1.755 + mat->AddProperty(&f,1,AI_MATKEY_OPACITY); 1.756 + } 1.757 + else if (s == "shine") { 1.758 + const float f = ReadFloat(); 1.759 + mat->AddProperty(&f,1,AI_MATKEY_SHININESS); 1.760 + } 1.761 + } 1.762 + 1.763 + scope.materials[mat_id] = mat; 1.764 + scope.materials_linear.push_back(mat.dismiss()); 1.765 +} 1.766 + 1.767 + 1.768 +// ---------------------------------------------------------------------------------------------- 1.769 +void XGLImporter::ReadFaceVertex(const TempMesh& t, TempFace& out) 1.770 +{ 1.771 + const std::string& end = GetElementName(); 1.772 + 1.773 + bool havep = false; 1.774 + while (ReadElementUpToClosing(end.c_str())) { 1.775 + const std::string& s = GetElementName(); 1.776 + if (s == "pref") { 1.777 + const unsigned int id = ReadIndexFromText(); 1.778 + std::map<unsigned int, aiVector3D>::const_iterator it = t.points.find(id); 1.779 + if (it == t.points.end()) { 1.780 + ThrowException("point index out of range"); 1.781 + } 1.782 + 1.783 + out.pos = (*it).second; 1.784 + havep = true; 1.785 + } 1.786 + else if (s == "nref") { 1.787 + const unsigned int id = ReadIndexFromText(); 1.788 + std::map<unsigned int, aiVector3D>::const_iterator it = t.normals.find(id); 1.789 + if (it == t.normals.end()) { 1.790 + ThrowException("normal index out of range"); 1.791 + } 1.792 + 1.793 + out.normal = (*it).second; 1.794 + out.has_normal = true; 1.795 + } 1.796 + else if (s == "tcref") { 1.797 + const unsigned int id = ReadIndexFromText(); 1.798 + std::map<unsigned int, aiVector2D>::const_iterator it = t.uvs.find(id); 1.799 + if (it == t.uvs.end()) { 1.800 + ThrowException("uv index out of range"); 1.801 + } 1.802 + 1.803 + out.uv = (*it).second; 1.804 + out.has_uv = true; 1.805 + } 1.806 + else if (s == "p") { 1.807 + out.pos = ReadVec3(); 1.808 + } 1.809 + else if (s == "n") { 1.810 + out.normal = ReadVec3(); 1.811 + } 1.812 + else if (s == "tc") { 1.813 + out.uv = ReadVec2(); 1.814 + } 1.815 + } 1.816 + 1.817 + if (!havep) { 1.818 + ThrowException("missing <pref> in <fvN> element"); 1.819 + } 1.820 +} 1.821 + 1.822 +// ------------------------------------------------------------------------------------------------ 1.823 +unsigned int XGLImporter::ReadIDAttr() 1.824 +{ 1.825 + for(int i = 0, e = reader->getAttributeCount(); i < e; ++i) { 1.826 + 1.827 + if(!ASSIMP_stricmp(reader->getAttributeName(i),"id")) { 1.828 + return reader->getAttributeValueAsInt(i); 1.829 + } 1.830 + } 1.831 + return ~0u; 1.832 +} 1.833 + 1.834 +// ------------------------------------------------------------------------------------------------ 1.835 +float XGLImporter::ReadFloat() 1.836 +{ 1.837 + if(!SkipToText()) { 1.838 + LogError("unexpected EOF reading float element contents"); 1.839 + return 0.f; 1.840 + } 1.841 + const char* s = reader->getNodeData(), *se; 1.842 + 1.843 + if(!SkipSpaces(&s)) { 1.844 + LogError("unexpected EOL, failed to parse float"); 1.845 + return 0.f; 1.846 + } 1.847 + 1.848 + float t; 1.849 + se = fast_atoreal_move(s,t); 1.850 + 1.851 + if (se == s) { 1.852 + LogError("failed to read float text"); 1.853 + return 0.f; 1.854 + } 1.855 + 1.856 + return t; 1.857 +} 1.858 + 1.859 +// ------------------------------------------------------------------------------------------------ 1.860 +unsigned int XGLImporter::ReadIndexFromText() 1.861 +{ 1.862 + if(!SkipToText()) { 1.863 + LogError("unexpected EOF reading index element contents"); 1.864 + return ~0u; 1.865 + } 1.866 + const char* s = reader->getNodeData(), *se; 1.867 + if(!SkipSpaces(&s)) { 1.868 + LogError("unexpected EOL, failed to parse index element"); 1.869 + return ~0u; 1.870 + } 1.871 + 1.872 + const unsigned int t = strtoul10(s,&se); 1.873 + 1.874 + if (se == s) { 1.875 + LogError("failed to read index"); 1.876 + return ~0u; 1.877 + } 1.878 + 1.879 + return t; 1.880 +} 1.881 + 1.882 +// ------------------------------------------------------------------------------------------------ 1.883 +aiVector2D XGLImporter::ReadVec2() 1.884 +{ 1.885 + aiVector2D vec; 1.886 + 1.887 + if(!SkipToText()) { 1.888 + LogError("unexpected EOF reading vec2 contents"); 1.889 + return vec; 1.890 + } 1.891 + const char* s = reader->getNodeData(); 1.892 + 1.893 + for(int i = 0; i < 2; ++i) { 1.894 + if(!SkipSpaces(&s)) { 1.895 + LogError("unexpected EOL, failed to parse vec2"); 1.896 + return vec; 1.897 + } 1.898 + vec[i] = fast_atof(&s); 1.899 + 1.900 + SkipSpaces(&s); 1.901 + if (i != 1 && *s != ',') { 1.902 + LogError("expected comma, failed to parse vec2"); 1.903 + return vec; 1.904 + } 1.905 + ++s; 1.906 + } 1.907 + 1.908 + return vec; 1.909 +} 1.910 + 1.911 +// ------------------------------------------------------------------------------------------------ 1.912 +aiVector3D XGLImporter::ReadVec3() 1.913 +{ 1.914 + aiVector3D vec; 1.915 + 1.916 + if(!SkipToText()) { 1.917 + LogError("unexpected EOF reading vec3 contents"); 1.918 + return vec; 1.919 + } 1.920 + const char* s = reader->getNodeData(); 1.921 + 1.922 + for(int i = 0; i < 3; ++i) { 1.923 + if(!SkipSpaces(&s)) { 1.924 + LogError("unexpected EOL, failed to parse vec3"); 1.925 + return vec; 1.926 + } 1.927 + vec[i] = fast_atof(&s); 1.928 + 1.929 + SkipSpaces(&s); 1.930 + if (i != 2 && *s != ',') { 1.931 + LogError("expected comma, failed to parse vec3"); 1.932 + return vec; 1.933 + } 1.934 + ++s; 1.935 + } 1.936 + 1.937 + return vec; 1.938 +} 1.939 + 1.940 +// ------------------------------------------------------------------------------------------------ 1.941 +aiColor3D XGLImporter::ReadCol3() 1.942 +{ 1.943 + const aiVector3D& v = ReadVec3(); 1.944 + 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) { 1.945 + LogWarn("color values out of range, ignoring"); 1.946 + } 1.947 + return aiColor3D(v.x,v.y,v.z); 1.948 +} 1.949 + 1.950 +#endif