vrshoot
diff libs/assimp/COBLoader.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/COBLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,1291 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +/** @file COBLoader.cpp 1.45 + * @brief Implementation of the TrueSpace COB/SCN importer class. 1.46 + */ 1.47 +#include "AssimpPCH.h" 1.48 + 1.49 +#ifndef ASSIMP_BUILD_NO_COB_IMPORTER 1.50 +#include "COBLoader.h" 1.51 +#include "COBScene.h" 1.52 + 1.53 +#include "StreamReader.h" 1.54 +#include "ParsingUtils.h" 1.55 +#include "fast_atof.h" 1.56 + 1.57 +#include "LineSplitter.h" 1.58 +#include "TinyFormatter.h" 1.59 + 1.60 +using namespace Assimp; 1.61 +using namespace Assimp::COB; 1.62 +using namespace Assimp::Formatter; 1.63 + 1.64 +#define for_each BOOST_FOREACH 1.65 + 1.66 + 1.67 +static const float units[] = { 1.68 + 1000.f, 1.69 + 100.f, 1.70 + 1.f, 1.71 + 0.001f, 1.72 + 1.f/0.0254f, 1.73 + 1.f/0.3048f, 1.74 + 1.f/0.9144f, 1.75 + 1.f/1609.344f 1.76 +}; 1.77 + 1.78 +static const aiImporterDesc desc = { 1.79 + "TrueSpace Object Importer", 1.80 + "", 1.81 + "", 1.82 + "little-endian files only", 1.83 + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, 1.84 + 0, 1.85 + 0, 1.86 + 0, 1.87 + 0, 1.88 + "cob scn" 1.89 +}; 1.90 + 1.91 + 1.92 +// ------------------------------------------------------------------------------------------------ 1.93 +// Constructor to be privately used by Importer 1.94 +COBImporter::COBImporter() 1.95 +{} 1.96 + 1.97 +// ------------------------------------------------------------------------------------------------ 1.98 +// Destructor, private as well 1.99 +COBImporter::~COBImporter() 1.100 +{} 1.101 + 1.102 +// ------------------------------------------------------------------------------------------------ 1.103 +// Returns whether the class can handle the format of the given file. 1.104 +bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.105 +{ 1.106 + const std::string& extension = GetExtension(pFile); 1.107 + if (extension == "cob" || extension == "scn") { 1.108 + return true; 1.109 + } 1.110 + 1.111 + else if ((!extension.length() || checkSig) && pIOHandler) { 1.112 + const char* tokens[] = {"Caligary"}; 1.113 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); 1.114 + } 1.115 + return false; 1.116 +} 1.117 + 1.118 +// ------------------------------------------------------------------------------------------------ 1.119 +// Loader meta information 1.120 +const aiImporterDesc* COBImporter::GetInfo () const 1.121 +{ 1.122 + return &desc; 1.123 +} 1.124 + 1.125 +// ------------------------------------------------------------------------------------------------ 1.126 +// Setup configuration properties for the loader 1.127 +void COBImporter::SetupProperties(const Importer* /*pImp*/) 1.128 +{ 1.129 + // nothing to be done for the moment 1.130 +} 1.131 + 1.132 +// ------------------------------------------------------------------------------------------------ 1.133 +/*static*/ void COBImporter::ThrowException(const std::string& msg) 1.134 +{ 1.135 + throw DeadlyImportError("COB: "+msg); 1.136 +} 1.137 + 1.138 +// ------------------------------------------------------------------------------------------------ 1.139 +// Imports the given file into the given scene structure. 1.140 +void COBImporter::InternReadFile( const std::string& pFile, 1.141 + aiScene* pScene, IOSystem* pIOHandler) 1.142 +{ 1.143 + COB::Scene scene; 1.144 + boost::scoped_ptr<StreamReaderLE> stream(new StreamReaderLE( pIOHandler->Open(pFile,"rb")) ); 1.145 + 1.146 + // check header 1.147 + char head[32]; 1.148 + stream->CopyAndAdvance(head,32); 1.149 + if (strncmp(head,"Caligari ",9)) { 1.150 + ThrowException("Could not found magic id: `Caligari`"); 1.151 + } 1.152 + 1.153 + DefaultLogger::get()->info("File format tag: "+std::string(head+9,6)); 1.154 + void (COBImporter::* load)(Scene&,StreamReaderLE*)= head[15]=='A'?&COBImporter::ReadAsciiFile:&COBImporter::ReadBinaryFile; 1.155 + if (head[16]!='L') { 1.156 + ThrowException("File is big-endian, which is not supported"); 1.157 + } 1.158 + 1.159 + // load data into intermediate structures 1.160 + (this->*load)(scene,stream.get()); 1.161 + if(scene.nodes.empty()) { 1.162 + ThrowException("No nodes loaded"); 1.163 + } 1.164 + 1.165 + // sort faces by material indices 1.166 + for_each(boost::shared_ptr< Node >& n,scene.nodes) { 1.167 + if (n->type == Node::TYPE_MESH) { 1.168 + Mesh& mesh = (Mesh&)(*n.get()); 1.169 + for_each(Face& f,mesh.faces) { 1.170 + mesh.temp_map[f.material].push_back(&f); 1.171 + } 1.172 + } 1.173 + } 1.174 + 1.175 + // count meshes 1.176 + for_each(boost::shared_ptr< Node >& n,scene.nodes) { 1.177 + if (n->type == Node::TYPE_MESH) { 1.178 + Mesh& mesh = (Mesh&)(*n.get()); 1.179 + if (mesh.vertex_positions.size() && mesh.texture_coords.size()) { 1.180 + pScene->mNumMeshes += mesh.temp_map.size(); 1.181 + } 1.182 + } 1.183 + } 1.184 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes](); 1.185 + pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes](); 1.186 + pScene->mNumMeshes = 0; 1.187 + 1.188 + // count lights and cameras 1.189 + for_each(boost::shared_ptr< Node >& n,scene.nodes) { 1.190 + if (n->type == Node::TYPE_LIGHT) { 1.191 + ++pScene->mNumLights; 1.192 + } 1.193 + else if (n->type == Node::TYPE_CAMERA) { 1.194 + ++pScene->mNumCameras; 1.195 + } 1.196 + } 1.197 + 1.198 + if (pScene->mNumLights) { 1.199 + pScene->mLights = new aiLight*[pScene->mNumLights](); 1.200 + } 1.201 + if (pScene->mNumCameras) { 1.202 + pScene->mCameras = new aiCamera*[pScene->mNumCameras](); 1.203 + } 1.204 + pScene->mNumLights = pScene->mNumCameras = 0; 1.205 + 1.206 + // resolve parents by their IDs and build the output graph 1.207 + boost::scoped_ptr<Node> root(new Group()); 1.208 + for(size_t n = 0; n < scene.nodes.size(); ++n) { 1.209 + const Node& nn = *scene.nodes[n].get(); 1.210 + if(nn.parent_id==0) { 1.211 + root->temp_children.push_back(&nn); 1.212 + } 1.213 + 1.214 + for(size_t m = n; m < scene.nodes.size(); ++m) { 1.215 + const Node& mm = *scene.nodes[m].get(); 1.216 + if (mm.parent_id == nn.id) { 1.217 + nn.temp_children.push_back(&mm); 1.218 + } 1.219 + } 1.220 + } 1.221 + 1.222 + pScene->mRootNode = BuildNodes(*root.get(),scene,pScene); 1.223 +} 1.224 + 1.225 +// ------------------------------------------------------------------------------------------------ 1.226 +void ConvertTexture(boost::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type) 1.227 +{ 1.228 + const aiString path( tex->path ); 1.229 + out->AddProperty(&path,AI_MATKEY_TEXTURE(type,0)); 1.230 + out->AddProperty(&tex->transform,1,AI_MATKEY_UVTRANSFORM(type,0)); 1.231 +} 1.232 + 1.233 +// ------------------------------------------------------------------------------------------------ 1.234 +aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill) 1.235 +{ 1.236 + aiNode* nd = new aiNode(); 1.237 + nd->mName.Set(root.name); 1.238 + nd->mTransformation = root.transform; 1.239 + 1.240 + // Note to everybody believing Voodoo is appropriate here: 1.241 + // I know polymorphism, run as fast as you can ;-) 1.242 + if (Node::TYPE_MESH == root.type) { 1.243 + const Mesh& ndmesh = (const Mesh&)(root); 1.244 + if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) { 1.245 + 1.246 + typedef std::pair<unsigned int,Mesh::FaceRefList> Entry; 1.247 + for_each(const Entry& reflist,ndmesh.temp_map) { 1.248 + { // create mesh 1.249 + size_t n = 0; 1.250 + for_each(Face* f, reflist.second) { 1.251 + n += f->indices.size(); 1.252 + } 1.253 + if (!n) { 1.254 + continue; 1.255 + } 1.256 + aiMesh* outmesh = fill->mMeshes[fill->mNumMeshes++] = new aiMesh(); 1.257 + ++nd->mNumMeshes; 1.258 + 1.259 + outmesh->mVertices = new aiVector3D[n]; 1.260 + outmesh->mTextureCoords[0] = new aiVector3D[n]; 1.261 + 1.262 + outmesh->mFaces = new aiFace[reflist.second.size()](); 1.263 + for_each(Face* f, reflist.second) { 1.264 + if (f->indices.empty()) { 1.265 + continue; 1.266 + } 1.267 + 1.268 + aiFace& fout = outmesh->mFaces[outmesh->mNumFaces++]; 1.269 + fout.mIndices = new unsigned int[f->indices.size()]; 1.270 + 1.271 + for_each(VertexIndex& v, f->indices) { 1.272 + if (v.pos_idx >= ndmesh.vertex_positions.size()) { 1.273 + ThrowException("Position index out of range"); 1.274 + } 1.275 + if (v.uv_idx >= ndmesh.texture_coords.size()) { 1.276 + ThrowException("UV index out of range"); 1.277 + } 1.278 + outmesh->mVertices[outmesh->mNumVertices] = ndmesh.vertex_positions[ v.pos_idx ]; 1.279 + outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D( 1.280 + ndmesh.texture_coords[ v.uv_idx ].x, 1.281 + ndmesh.texture_coords[ v.uv_idx ].y, 1.282 + 0.f 1.283 + ); 1.284 + 1.285 + fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++; 1.286 + } 1.287 + } 1.288 + outmesh->mMaterialIndex = fill->mNumMaterials; 1.289 + }{ // create material 1.290 + const Material* min = NULL; 1.291 + for_each(const Material& m, scin.materials) { 1.292 + if (m.parent_id == ndmesh.id && m.matnum == reflist.first) { 1.293 + min = &m; 1.294 + break; 1.295 + } 1.296 + } 1.297 + boost::scoped_ptr<const Material> defmat; 1.298 + if(!min) { 1.299 + DefaultLogger::get()->debug(format()<<"Could not resolve material index " 1.300 + <<reflist.first<<" - creating default material for this slot"); 1.301 + 1.302 + defmat.reset(min=new Material()); 1.303 + } 1.304 + 1.305 + aiMaterial* mat = new aiMaterial(); 1.306 + fill->mMaterials[fill->mNumMaterials++] = mat; 1.307 + 1.308 + const aiString s(format("#mat_")<<fill->mNumMeshes<<"_"<<min->matnum); 1.309 + mat->AddProperty(&s,AI_MATKEY_NAME); 1.310 + 1.311 + if(int tmp = ndmesh.draw_flags & Mesh::WIRED ? 1 : 0) { 1.312 + mat->AddProperty(&tmp,1,AI_MATKEY_ENABLE_WIREFRAME); 1.313 + } 1.314 + 1.315 + { int shader; 1.316 + switch(min->shader) 1.317 + { 1.318 + case Material::FLAT: 1.319 + shader = aiShadingMode_Gouraud; 1.320 + break; 1.321 + 1.322 + case Material::PHONG: 1.323 + shader = aiShadingMode_Phong; 1.324 + break; 1.325 + 1.326 + case Material::METAL: 1.327 + shader = aiShadingMode_CookTorrance; 1.328 + break; 1.329 + 1.330 + default: 1.331 + ai_assert(false); // shouldn't be here 1.332 + } 1.333 + mat->AddProperty(&shader,1,AI_MATKEY_SHADING_MODEL); 1.334 + if(shader != aiShadingMode_Gouraud) { 1.335 + mat->AddProperty(&min->exp,1,AI_MATKEY_SHININESS); 1.336 + } 1.337 + } 1.338 + 1.339 + mat->AddProperty(&min->ior,1,AI_MATKEY_REFRACTI); 1.340 + mat->AddProperty(&min->rgb,1,AI_MATKEY_COLOR_DIFFUSE); 1.341 + 1.342 + aiColor3D c = aiColor3D(min->rgb)*min->ks; 1.343 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR); 1.344 + 1.345 + c = aiColor3D(min->rgb)*min->ka; 1.346 + mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT); 1.347 + 1.348 + // convert textures if some exist. 1.349 + if(min->tex_color) { 1.350 + ConvertTexture(min->tex_color,mat,aiTextureType_DIFFUSE); 1.351 + } 1.352 + if(min->tex_env) { 1.353 + ConvertTexture(min->tex_env ,mat,aiTextureType_UNKNOWN); 1.354 + } 1.355 + if(min->tex_bump) { 1.356 + ConvertTexture(min->tex_bump ,mat,aiTextureType_HEIGHT); 1.357 + } 1.358 + } 1.359 + } 1.360 + } 1.361 + } 1.362 + else if (Node::TYPE_LIGHT == root.type) { 1.363 + const Light& ndlight = (const Light&)(root); 1.364 + aiLight* outlight = fill->mLights[fill->mNumLights++] = new aiLight(); 1.365 + 1.366 + outlight->mName.Set(ndlight.name); 1.367 + outlight->mColorDiffuse = outlight->mColorAmbient = outlight->mColorSpecular = ndlight.color; 1.368 + 1.369 + outlight->mAngleOuterCone = AI_DEG_TO_RAD(ndlight.angle); 1.370 + outlight->mAngleInnerCone = AI_DEG_TO_RAD(ndlight.inner_angle); 1.371 + 1.372 + // XXX 1.373 + outlight->mType = ndlight.ltype==Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL; 1.374 + } 1.375 + else if (Node::TYPE_CAMERA == root.type) { 1.376 + const Camera& ndcam = (const Camera&)(root); 1.377 + aiCamera* outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera(); 1.378 + 1.379 + outcam->mName.Set(ndcam.name); 1.380 + } 1.381 + 1.382 + // add meshes 1.383 + if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0 1.384 + nd->mMeshes = new unsigned int[nd->mNumMeshes]; 1.385 + for(unsigned int i = 0; i < nd->mNumMeshes;++i) { 1.386 + nd->mMeshes[i] = fill->mNumMeshes-i-1; 1.387 + } 1.388 + } 1.389 + 1.390 + // add children recursively 1.391 + nd->mChildren = new aiNode*[root.temp_children.size()](); 1.392 + for_each(const Node* n, root.temp_children) { 1.393 + (nd->mChildren[nd->mNumChildren++] = BuildNodes(*n,scin,fill))->mParent = nd; 1.394 + } 1.395 + 1.396 + return nd; 1.397 +} 1.398 + 1.399 +// ------------------------------------------------------------------------------------------------ 1.400 +// Read an ASCII file into the given scene data structure 1.401 +void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream) 1.402 +{ 1.403 + ChunkInfo ci; 1.404 + for(LineSplitter splitter(*stream);splitter;++splitter) { 1.405 + 1.406 + // add all chunks to be recognized here. /else ../ omitted intentionally. 1.407 + if (splitter.match_start("PolH ")) { 1.408 + ReadChunkInfo_Ascii(ci,splitter); 1.409 + ReadPolH_Ascii(out,splitter,ci); 1.410 + } 1.411 + if (splitter.match_start("BitM ")) { 1.412 + ReadChunkInfo_Ascii(ci,splitter); 1.413 + ReadBitM_Ascii(out,splitter,ci); 1.414 + } 1.415 + if (splitter.match_start("Mat1 ")) { 1.416 + ReadChunkInfo_Ascii(ci,splitter); 1.417 + ReadMat1_Ascii(out,splitter,ci); 1.418 + } 1.419 + if (splitter.match_start("Grou ")) { 1.420 + ReadChunkInfo_Ascii(ci,splitter); 1.421 + ReadGrou_Ascii(out,splitter,ci); 1.422 + } 1.423 + if (splitter.match_start("Lght ")) { 1.424 + ReadChunkInfo_Ascii(ci,splitter); 1.425 + ReadLght_Ascii(out,splitter,ci); 1.426 + } 1.427 + if (splitter.match_start("Came ")) { 1.428 + ReadChunkInfo_Ascii(ci,splitter); 1.429 + ReadCame_Ascii(out,splitter,ci); 1.430 + } 1.431 + if (splitter.match_start("Bone ")) { 1.432 + ReadChunkInfo_Ascii(ci,splitter); 1.433 + ReadBone_Ascii(out,splitter,ci); 1.434 + } 1.435 + if (splitter.match_start("Chan ")) { 1.436 + ReadChunkInfo_Ascii(ci,splitter); 1.437 + ReadChan_Ascii(out,splitter,ci); 1.438 + } 1.439 + if (splitter.match_start("Unit ")) { 1.440 + ReadChunkInfo_Ascii(ci,splitter); 1.441 + ReadUnit_Ascii(out,splitter,ci); 1.442 + } 1.443 + if (splitter.match_start("END ")) { 1.444 + // we don't need this, but I guess there is a reason this 1.445 + // chunk has been implemented into COB for. 1.446 + return; 1.447 + } 1.448 + } 1.449 +} 1.450 + 1.451 +// ------------------------------------------------------------------------------------------------ 1.452 +void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter) 1.453 +{ 1.454 + const char* all_tokens[8]; 1.455 + splitter.get_tokens(all_tokens); 1.456 + 1.457 + out.version = (all_tokens[1][1]-'0')*100+(all_tokens[1][3]-'0')*10+(all_tokens[1][4]-'0'); 1.458 + out.id = strtoul10(all_tokens[3]); 1.459 + out.parent_id = strtoul10(all_tokens[5]); 1.460 + out.size = strtol10(all_tokens[7]); 1.461 +} 1.462 + 1.463 +// ------------------------------------------------------------------------------------------------ 1.464 +void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name) 1.465 +{ 1.466 + const std::string error = format("Encountered unsupported chunk: ") << name << 1.467 + " [version: "<<nfo.version<<", size: "<<nfo.size<<"]"; 1.468 + 1.469 + // we can recover if the chunk size was specified. 1.470 + if(nfo.size != static_cast<unsigned int>(-1)) { 1.471 + DefaultLogger::get()->error(error); 1.472 + 1.473 + // (HACK) - our current position in the stream is the beginning of the 1.474 + // head line of the next chunk. That's fine, but the caller is going 1.475 + // to call ++ on `splitter`, which we need to swallow to avoid 1.476 + // missing the next line. 1.477 + splitter.get_stream().IncPtr(nfo.size); 1.478 + splitter.swallow_next_increment(); 1.479 + } 1.480 + else ThrowException(error); 1.481 +} 1.482 + 1.483 +// ------------------------------------------------------------------------------------------------ 1.484 +void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message) { 1.485 + LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]"); 1.486 +} 1.487 + 1.488 +// ------------------------------------------------------------------------------------------------ 1.489 +void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message) { 1.490 + LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]"); 1.491 +} 1.492 + 1.493 +// ------------------------------------------------------------------------------------------------ 1.494 +void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message) { 1.495 + LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]"); 1.496 +} 1.497 + 1.498 +// ------------------------------------------------------------------------------------------------ 1.499 +void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message) { 1.500 + LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]"); 1.501 +} 1.502 + 1.503 +// ------------------------------------------------------------------------------------------------ 1.504 +void COBImporter::LogWarn_Ascii(const Formatter::format& message) { 1.505 + DefaultLogger::get()->warn(std::string("COB: ")+=message); 1.506 +} 1.507 + 1.508 +// ------------------------------------------------------------------------------------------------ 1.509 +void COBImporter::LogError_Ascii(const Formatter::format& message) { 1.510 + DefaultLogger::get()->error(std::string("COB: ")+=message); 1.511 +} 1.512 + 1.513 +// ------------------------------------------------------------------------------------------------ 1.514 +void COBImporter::LogInfo_Ascii(const Formatter::format& message) { 1.515 + DefaultLogger::get()->info(std::string("COB: ")+=message); 1.516 +} 1.517 + 1.518 +// ------------------------------------------------------------------------------------------------ 1.519 +void COBImporter::LogDebug_Ascii(const Formatter::format& message) { 1.520 + DefaultLogger::get()->debug(std::string("COB: ")+=message); 1.521 +} 1.522 + 1.523 +// ------------------------------------------------------------------------------------------------ 1.524 +void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/) 1.525 +{ 1.526 + for(;splitter;++splitter) { 1.527 + if (splitter.match_start("Name")) { 1.528 + msh.name = std::string(splitter[1]); 1.529 + 1.530 + // make nice names by merging the dupe count 1.531 + std::replace(msh.name.begin(),msh.name.end(), 1.532 + ',','_'); 1.533 + } 1.534 + else if (splitter.match_start("Transform")) { 1.535 + for(unsigned int y = 0; y < 4 && ++splitter; ++y) { 1.536 + const char* s = splitter->c_str(); 1.537 + for(unsigned int x = 0; x < 4; ++x) { 1.538 + SkipSpaces(&s); 1.539 + msh.transform[y][x] = fast_atof(&s); 1.540 + } 1.541 + } 1.542 + // we need the transform chunk, so we won't return until we have it. 1.543 + return; 1.544 + } 1.545 + } 1.546 +} 1.547 + 1.548 +// ------------------------------------------------------------------------------------------------ 1.549 +template <typename T> 1.550 +void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in) 1.551 +{ 1.552 + const char* rgb = *in; 1.553 + for(unsigned int i = 0; i < 3; ++i) { 1.554 + SkipSpaces(&rgb); 1.555 + if (*rgb == ',')++rgb; 1.556 + SkipSpaces(&rgb); 1.557 + 1.558 + fill[i] = fast_atof(&rgb); 1.559 + } 1.560 + *in = rgb; 1.561 +} 1.562 + 1.563 +// ------------------------------------------------------------------------------------------------ 1.564 +void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.565 +{ 1.566 + if(nfo.version > 8) { 1.567 + return UnsupportedChunk_Ascii(splitter,nfo,"Mat1"); 1.568 + } 1.569 + 1.570 + ++splitter; 1.571 + if (!splitter.match_start("mat# ")) { 1.572 + LogWarn_Ascii(splitter,format()<< 1.573 + "Expected `mat#` line in `Mat1` chunk "<<nfo.id); 1.574 + return; 1.575 + } 1.576 + 1.577 + out.materials.push_back(Material()); 1.578 + Material& mat = out.materials.back(); 1.579 + mat = nfo; 1.580 + 1.581 + mat.matnum = strtoul10(splitter[1]); 1.582 + ++splitter; 1.583 + 1.584 + if (!splitter.match_start("shader: ")) { 1.585 + LogWarn_Ascii(splitter,format()<< 1.586 + "Expected `mat#` line in `Mat1` chunk "<<nfo.id); 1.587 + return; 1.588 + } 1.589 + std::string shader = std::string(splitter[1]); 1.590 + shader = shader.substr(0,shader.find_first_of(" \t")); 1.591 + 1.592 + if (shader == "metal") { 1.593 + mat.shader = Material::METAL; 1.594 + } 1.595 + else if (shader == "phong") { 1.596 + mat.shader = Material::PHONG; 1.597 + } 1.598 + else if (shader != "flat") { 1.599 + LogWarn_Ascii(splitter,format()<< 1.600 + "Unknown value for `shader` in `Mat1` chunk "<<nfo.id); 1.601 + } 1.602 + 1.603 + ++splitter; 1.604 + if (!splitter.match_start("rgb ")) { 1.605 + LogWarn_Ascii(splitter,format()<< 1.606 + "Expected `rgb` line in `Mat1` chunk "<<nfo.id); 1.607 + } 1.608 + 1.609 + const char* rgb = splitter[1]; 1.610 + ReadFloat3Tuple_Ascii(mat.rgb,&rgb); 1.611 + 1.612 + ++splitter; 1.613 + if (!splitter.match_start("alpha ")) { 1.614 + LogWarn_Ascii(splitter,format()<< 1.615 + "Expected `alpha` line in `Mat1` chunk "<<nfo.id); 1.616 + } 1.617 + 1.618 + const char* tokens[10]; 1.619 + splitter.get_tokens(tokens); 1.620 + 1.621 + mat.alpha = fast_atof( tokens[1] ); 1.622 + mat.ka = fast_atof( tokens[3] ); 1.623 + mat.ks = fast_atof( tokens[5] ); 1.624 + mat.exp = fast_atof( tokens[7] ); 1.625 + mat.ior = fast_atof( tokens[9] ); 1.626 +} 1.627 + 1.628 +// ------------------------------------------------------------------------------------------------ 1.629 +void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.630 +{ 1.631 + if(nfo.version > 1) { 1.632 + return UnsupportedChunk_Ascii(splitter,nfo,"Unit"); 1.633 + } 1.634 + ++splitter; 1.635 + if (!splitter.match_start("Units ")) { 1.636 + LogWarn_Ascii(splitter,format()<< 1.637 + "Expected `Units` line in `Unit` chunk "<<nfo.id); 1.638 + return; 1.639 + } 1.640 + 1.641 + // parent chunks preceede their childs, so we should have the 1.642 + // corresponding chunk already. 1.643 + for_each(boost::shared_ptr< Node >& nd, out.nodes) { 1.644 + if (nd->id == nfo.parent_id) { 1.645 + const unsigned int t=strtoul10(splitter[1]); 1.646 + 1.647 + nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( 1.648 + LogWarn_Ascii(splitter,format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id) 1.649 + ,1.f):units[t]; 1.650 + return; 1.651 + } 1.652 + } 1.653 + LogWarn_Ascii(splitter,format()<<"`Unit` chunk "<<nfo.id<<" is a child of " 1.654 + <<nfo.parent_id<<" which does not exist"); 1.655 +} 1.656 + 1.657 +// ------------------------------------------------------------------------------------------------ 1.658 +void COBImporter::ReadChan_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo) 1.659 +{ 1.660 + if(nfo.version > 8) { 1.661 + return UnsupportedChunk_Ascii(splitter,nfo,"Chan"); 1.662 + } 1.663 +} 1.664 + 1.665 +// ------------------------------------------------------------------------------------------------ 1.666 +void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.667 +{ 1.668 + if(nfo.version > 8) { 1.669 + return UnsupportedChunk_Ascii(splitter,nfo,"Lght"); 1.670 + } 1.671 + 1.672 + out.nodes.push_back(boost::shared_ptr<Light>(new Light())); 1.673 + Light& msh = (Light&)(*out.nodes.back().get()); 1.674 + msh = nfo; 1.675 + 1.676 + ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); 1.677 + 1.678 + if (splitter.match_start("Infinite ")) { 1.679 + msh.ltype = Light::INFINITE; 1.680 + } 1.681 + else if (splitter.match_start("Local ")) { 1.682 + msh.ltype = Light::LOCAL; 1.683 + } 1.684 + else if (splitter.match_start("Spot ")) { 1.685 + msh.ltype = Light::SPOT; 1.686 + } 1.687 + else { 1.688 + LogWarn_Ascii(splitter,format()<< 1.689 + "Unknown kind of light source in `Lght` chunk "<<nfo.id<<" : "<<*splitter); 1.690 + msh.ltype = Light::SPOT; 1.691 + } 1.692 + 1.693 + ++splitter; 1.694 + if (!splitter.match_start("color ")) { 1.695 + LogWarn_Ascii(splitter,format()<< 1.696 + "Expected `color` line in `Lght` chunk "<<nfo.id); 1.697 + } 1.698 + 1.699 + const char* rgb = splitter[1]; 1.700 + ReadFloat3Tuple_Ascii(msh.color ,&rgb); 1.701 + 1.702 + SkipSpaces(&rgb); 1.703 + if (strncmp(rgb,"cone angle",10)) { 1.704 + LogWarn_Ascii(splitter,format()<< 1.705 + "Expected `cone angle` entity in `color` line in `Lght` chunk "<<nfo.id); 1.706 + } 1.707 + SkipSpaces(rgb+10,&rgb); 1.708 + msh.angle = fast_atof(&rgb); 1.709 + 1.710 + SkipSpaces(&rgb); 1.711 + if (strncmp(rgb,"inner angle",11)) { 1.712 + LogWarn_Ascii(splitter,format()<< 1.713 + "Expected `inner angle` entity in `color` line in `Lght` chunk "<<nfo.id); 1.714 + } 1.715 + SkipSpaces(rgb+11,&rgb); 1.716 + msh.inner_angle = fast_atof(&rgb); 1.717 + 1.718 + // skip the rest for we can't handle this kind of physically-based lighting information. 1.719 +} 1.720 + 1.721 +// ------------------------------------------------------------------------------------------------ 1.722 +void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.723 +{ 1.724 + if(nfo.version > 2) { 1.725 + return UnsupportedChunk_Ascii(splitter,nfo,"Came"); 1.726 + } 1.727 + 1.728 + out.nodes.push_back(boost::shared_ptr<Camera>(new Camera())); 1.729 + Camera& msh = (Camera&)(*out.nodes.back().get()); 1.730 + msh = nfo; 1.731 + 1.732 + ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); 1.733 + 1.734 + // skip the next line, we don't know this differenciation between a 1.735 + // standard camera and a panoramic camera. 1.736 + ++splitter; 1.737 +} 1.738 + 1.739 +// ------------------------------------------------------------------------------------------------ 1.740 +void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.741 +{ 1.742 + if(nfo.version > 5) { 1.743 + return UnsupportedChunk_Ascii(splitter,nfo,"Bone"); 1.744 + } 1.745 + 1.746 + out.nodes.push_back(boost::shared_ptr<Bone>(new Bone())); 1.747 + Bone& msh = (Bone&)(*out.nodes.back().get()); 1.748 + msh = nfo; 1.749 + 1.750 + ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); 1.751 + 1.752 + // TODO 1.753 +} 1.754 + 1.755 +// ------------------------------------------------------------------------------------------------ 1.756 +void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.757 +{ 1.758 + if(nfo.version > 1) { 1.759 + return UnsupportedChunk_Ascii(splitter,nfo,"Grou"); 1.760 + } 1.761 + 1.762 + out.nodes.push_back(boost::shared_ptr<Group>(new Group())); 1.763 + Group& msh = (Group&)(*out.nodes.back().get()); 1.764 + msh = nfo; 1.765 + 1.766 + ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); 1.767 +} 1.768 + 1.769 +// ------------------------------------------------------------------------------------------------ 1.770 +void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) 1.771 +{ 1.772 + if(nfo.version > 8) { 1.773 + return UnsupportedChunk_Ascii(splitter,nfo,"PolH"); 1.774 + } 1.775 + 1.776 + out.nodes.push_back(boost::shared_ptr<Mesh>(new Mesh())); 1.777 + Mesh& msh = (Mesh&)(*out.nodes.back().get()); 1.778 + msh = nfo; 1.779 + 1.780 + ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); 1.781 + 1.782 + // the chunk has a fixed order of components, but some are not interesting of us so 1.783 + // we're just looking for keywords in arbitrary order. The end of the chunk is 1.784 + // either the last `Face` or the `DrawFlags` attribute, depending on the format ver. 1.785 + for(;splitter;++splitter) { 1.786 + if (splitter.match_start("World Vertices")) { 1.787 + const unsigned int cnt = strtoul10(splitter[2]); 1.788 + msh.vertex_positions.resize(cnt); 1.789 + 1.790 + for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) { 1.791 + const char* s = splitter->c_str(); 1.792 + 1.793 + aiVector3D& v = msh.vertex_positions[cur]; 1.794 + 1.795 + SkipSpaces(&s); 1.796 + v.x = fast_atof(&s); 1.797 + SkipSpaces(&s); 1.798 + v.y = fast_atof(&s); 1.799 + SkipSpaces(&s); 1.800 + v.z = fast_atof(&s); 1.801 + } 1.802 + } 1.803 + else if (splitter.match_start("Texture Vertices")) { 1.804 + const unsigned int cnt = strtoul10(splitter[2]); 1.805 + msh.texture_coords.resize(cnt); 1.806 + 1.807 + for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) { 1.808 + const char* s = splitter->c_str(); 1.809 + 1.810 + aiVector2D& v = msh.texture_coords[cur]; 1.811 + 1.812 + SkipSpaces(&s); 1.813 + v.x = fast_atof(&s); 1.814 + SkipSpaces(&s); 1.815 + v.y = fast_atof(&s); 1.816 + } 1.817 + } 1.818 + else if (splitter.match_start("Faces")) { 1.819 + const unsigned int cnt = strtoul10(splitter[1]); 1.820 + msh.faces.reserve(cnt); 1.821 + 1.822 + for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) { 1.823 + if (splitter.match_start("Hole")) { 1.824 + LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line"); 1.825 + continue; 1.826 + } 1.827 + 1.828 + if (!splitter.match_start("Face")) { 1.829 + ThrowException("Expected Face line"); 1.830 + } 1.831 + 1.832 + msh.faces.push_back(Face()); 1.833 + Face& face = msh.faces.back(); 1.834 + 1.835 + face.indices.resize(strtoul10(splitter[2])); 1.836 + face.flags = strtoul10(splitter[4]); 1.837 + face.material = strtoul10(splitter[6]); 1.838 + 1.839 + const char* s = (++splitter)->c_str(); 1.840 + for(size_t i = 0; i < face.indices.size(); ++i) { 1.841 + if(!SkipSpaces(&s)) { 1.842 + ThrowException("Expected EOL token in Face entry"); 1.843 + } 1.844 + if ('<' != *s++) { 1.845 + ThrowException("Expected < token in Face entry"); 1.846 + } 1.847 + face.indices[i].pos_idx = strtoul10(s,&s); 1.848 + if (',' != *s++) { 1.849 + ThrowException("Expected , token in Face entry"); 1.850 + } 1.851 + face.indices[i].uv_idx = strtoul10(s,&s); 1.852 + if ('>' != *s++) { 1.853 + ThrowException("Expected < token in Face entry"); 1.854 + } 1.855 + } 1.856 + } 1.857 + if (nfo.version <= 4) { 1.858 + break; 1.859 + } 1.860 + } 1.861 + else if (splitter.match_start("DrawFlags")) { 1.862 + msh.draw_flags = strtoul10(splitter[1]); 1.863 + break; 1.864 + } 1.865 + } 1.866 +} 1.867 + 1.868 +// ------------------------------------------------------------------------------------------------ 1.869 +void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo) 1.870 +{ 1.871 + if(nfo.version > 1) { 1.872 + return UnsupportedChunk_Ascii(splitter,nfo,"BitM"); 1.873 + } 1.874 +/* 1.875 + "\nThumbNailHdrSize %ld" 1.876 + "\nThumbHeader: %02hx 02hx %02hx " 1.877 + "\nColorBufSize %ld" 1.878 + "\nColorBufZipSize %ld" 1.879 + "\nZippedThumbnail: %02hx 02hx %02hx " 1.880 +*/ 1.881 + 1.882 + const unsigned int head = strtoul10((++splitter)[1]); 1.883 + if (head != sizeof(Bitmap::BitmapHeader)) { 1.884 + LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk"); 1.885 + return; 1.886 + } 1.887 + 1.888 + /*union { 1.889 + Bitmap::BitmapHeader data; 1.890 + char opaq[sizeof Bitmap::BitmapHeader()]; 1.891 + };*/ 1.892 +// ReadHexOctets(opaq,head,(++splitter)[1]); 1.893 +} 1.894 + 1.895 +// ------------------------------------------------------------------------------------------------ 1.896 +void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader) 1.897 +{ 1.898 + out.resize( reader.GetI2()); 1.899 + for_each(char& c,out) { 1.900 + c = reader.GetI1(); 1.901 + } 1.902 +} 1.903 + 1.904 +// ------------------------------------------------------------------------------------------------ 1.905 +void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/) 1.906 +{ 1.907 + const unsigned int dupes = reader.GetI2(); 1.908 + ReadString_Binary(msh.name,reader); 1.909 + 1.910 + msh.name = format(msh.name)<<'_'<<dupes; 1.911 + 1.912 + // skip local axes for the moment 1.913 + reader.IncPtr(48); 1.914 + 1.915 + msh.transform = aiMatrix4x4(); 1.916 + for(unsigned int y = 0; y < 3; ++y) { 1.917 + for(unsigned int x =0; x < 4; ++x) { 1.918 + msh.transform[y][x] = reader.GetF4(); 1.919 + } 1.920 + } 1.921 +} 1.922 + 1.923 +// ------------------------------------------------------------------------------------------------ 1.924 +void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkInfo& nfo, const char* name) 1.925 +{ 1.926 + const std::string error = format("Encountered unsupported chunk: ") << name << 1.927 + " [version: "<<nfo.version<<", size: "<<nfo.size<<"]"; 1.928 + 1.929 + // we can recover if the chunk size was specified. 1.930 + if(nfo.size != static_cast<unsigned int>(-1)) { 1.931 + DefaultLogger::get()->error(error); 1.932 + reader.IncPtr(nfo.size); 1.933 + } 1.934 + else ThrowException(error); 1.935 +} 1.936 + 1.937 +// ------------------------------------------------------------------------------------------------ 1.938 +// tiny utility guard to aid me at staying within chunk boundaries. 1.939 +class chunk_guard { 1.940 + 1.941 +public: 1.942 + 1.943 + chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader) 1.944 + : nfo(nfo) 1.945 + , reader(reader) 1.946 + , cur(reader.GetCurrentPos()) 1.947 + { 1.948 + } 1.949 + 1.950 + ~chunk_guard() { 1.951 + // don't do anything if the size is not given 1.952 + if(nfo.size != static_cast<unsigned int>(-1)) { 1.953 + reader.IncPtr(static_cast<int>(nfo.size)-reader.GetCurrentPos()+cur); 1.954 + } 1.955 + } 1.956 + 1.957 +private: 1.958 + 1.959 + const COB::ChunkInfo& nfo; 1.960 + StreamReaderLE& reader; 1.961 + long cur; 1.962 +}; 1.963 + 1.964 +// ------------------------------------------------------------------------------------------------ 1.965 +void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) 1.966 +{ 1.967 + while(1) { 1.968 + std::string type; 1.969 + type += reader -> GetI1() 1.970 + ,type += reader -> GetI1() 1.971 + ,type += reader -> GetI1() 1.972 + ,type += reader -> GetI1() 1.973 + ; 1.974 + 1.975 + ChunkInfo nfo; 1.976 + nfo.version = reader -> GetI2()*10; 1.977 + nfo.version += reader -> GetI2(); 1.978 + 1.979 + nfo.id = reader->GetI4(); 1.980 + nfo.parent_id = reader->GetI4(); 1.981 + nfo.size = reader->GetI4(); 1.982 + 1.983 + if (type == "PolH") { 1.984 + ReadPolH_Binary(out,*reader,nfo); 1.985 + } 1.986 + else if (type == "BitM") { 1.987 + ReadBitM_Binary(out,*reader,nfo); 1.988 + } 1.989 + else if (type == "Grou") { 1.990 + ReadGrou_Binary(out,*reader,nfo); 1.991 + } 1.992 + else if (type == "Lght") { 1.993 + ReadLght_Binary(out,*reader,nfo); 1.994 + } 1.995 + else if (type == "Came") { 1.996 + ReadCame_Binary(out,*reader,nfo); 1.997 + } 1.998 + else if (type == "Mat1") { 1.999 + ReadMat1_Binary(out,*reader,nfo); 1.1000 + } 1.1001 + /* else if (type == "Bone") { 1.1002 + ReadBone_Binary(out,*reader,nfo); 1.1003 + } 1.1004 + else if (type == "Chan") { 1.1005 + ReadChan_Binary(out,*reader,nfo); 1.1006 + }*/ 1.1007 + else if (type == "Unit") { 1.1008 + ReadUnit_Binary(out,*reader,nfo); 1.1009 + } 1.1010 + else if (type == "OLay") { 1.1011 + // ignore layer index silently. 1.1012 + if(nfo.size != static_cast<unsigned int>(-1) ) { 1.1013 + reader->IncPtr(nfo.size); 1.1014 + } 1.1015 + else return UnsupportedChunk_Binary(*reader,nfo,type.c_str()); 1.1016 + } 1.1017 + else if (type == "END ") { 1.1018 + return; 1.1019 + } 1.1020 + else UnsupportedChunk_Binary(*reader,nfo,type.c_str()); 1.1021 + } 1.1022 +} 1.1023 + 1.1024 +// ------------------------------------------------------------------------------------------------ 1.1025 +void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1026 +{ 1.1027 + if(nfo.version > 8) { 1.1028 + return UnsupportedChunk_Binary(reader,nfo,"PolH"); 1.1029 + } 1.1030 + const chunk_guard cn(nfo,reader); 1.1031 + 1.1032 + out.nodes.push_back(boost::shared_ptr<Mesh>(new Mesh())); 1.1033 + Mesh& msh = (Mesh&)(*out.nodes.back().get()); 1.1034 + msh = nfo; 1.1035 + 1.1036 + ReadBasicNodeInfo_Binary(msh,reader,nfo); 1.1037 + 1.1038 + msh.vertex_positions.resize(reader.GetI4()); 1.1039 + for_each(aiVector3D& v,msh.vertex_positions) { 1.1040 + v.x = reader.GetF4(); 1.1041 + v.y = reader.GetF4(); 1.1042 + v.z = reader.GetF4(); 1.1043 + } 1.1044 + 1.1045 + msh.texture_coords.resize(reader.GetI4()); 1.1046 + for_each(aiVector2D& v,msh.texture_coords) { 1.1047 + v.x = reader.GetF4(); 1.1048 + v.y = reader.GetF4(); 1.1049 + } 1.1050 + 1.1051 + const size_t numf = reader.GetI4(); 1.1052 + msh.faces.reserve(numf); 1.1053 + for(size_t i = 0; i < numf; ++i) { 1.1054 + // XXX backface culling flag is 0x10 in flags 1.1055 + 1.1056 + // hole? 1.1057 + bool hole; 1.1058 + if ((hole = (reader.GetI1() & 0x08) != 0)) { 1.1059 + // XXX Basically this should just work fine - then triangulator 1.1060 + // should output properly triangulated data even for polygons 1.1061 + // with holes. Test data specific to COB is needed to confirm it. 1.1062 + if (msh.faces.empty()) { 1.1063 + ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id); 1.1064 + } 1.1065 + } 1.1066 + else msh.faces.push_back(Face()); 1.1067 + Face& f = msh.faces.back(); 1.1068 + 1.1069 + const size_t num = reader.GetI2(); 1.1070 + f.indices.reserve(f.indices.size() + num); 1.1071 + 1.1072 + if(!hole) { 1.1073 + f.material = reader.GetI2(); 1.1074 + f.flags = 0; 1.1075 + } 1.1076 + 1.1077 + for(size_t x = 0; x < num; ++x) { 1.1078 + f.indices.push_back(VertexIndex()); 1.1079 + 1.1080 + VertexIndex& v = f.indices.back(); 1.1081 + v.pos_idx = reader.GetI4(); 1.1082 + v.uv_idx = reader.GetI4(); 1.1083 + } 1.1084 + 1.1085 + if(hole) { 1.1086 + std::reverse(f.indices.rbegin(),f.indices.rbegin()+num); 1.1087 + } 1.1088 + } 1.1089 + if (nfo.version>4) { 1.1090 + msh.draw_flags = reader.GetI4(); 1.1091 + } 1.1092 + nfo.version>5 && nfo.version<8 ? reader.GetI4() : 0; 1.1093 +} 1.1094 + 1.1095 +// ------------------------------------------------------------------------------------------------ 1.1096 +void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1097 +{ 1.1098 + if(nfo.version > 1) { 1.1099 + return UnsupportedChunk_Binary(reader,nfo,"BitM"); 1.1100 + } 1.1101 + 1.1102 + const chunk_guard cn(nfo,reader); 1.1103 + 1.1104 + const uint32_t len = reader.GetI4(); 1.1105 + reader.IncPtr(len); 1.1106 + 1.1107 + reader.GetI4(); 1.1108 + reader.IncPtr(reader.GetI4()); 1.1109 +} 1.1110 + 1.1111 +// ------------------------------------------------------------------------------------------------ 1.1112 +void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1113 +{ 1.1114 + if(nfo.version > 8) { 1.1115 + return UnsupportedChunk_Binary(reader,nfo,"Mat1"); 1.1116 + } 1.1117 + 1.1118 + const chunk_guard cn(nfo,reader); 1.1119 + 1.1120 + out.materials.push_back(Material()); 1.1121 + Material& mat = out.materials.back(); 1.1122 + mat = nfo; 1.1123 + 1.1124 + mat.matnum = reader.GetI2(); 1.1125 + switch(reader.GetI1()) { 1.1126 + case 'f': 1.1127 + mat.type = Material::FLAT; 1.1128 + break; 1.1129 + case 'p': 1.1130 + mat.type = Material::PHONG; 1.1131 + break; 1.1132 + case 'm': 1.1133 + mat.type = Material::METAL; 1.1134 + break; 1.1135 + default: 1.1136 + LogError_Ascii(format("Unrecognized shader type in `Mat1` chunk with id ")<<nfo.id); 1.1137 + mat.type = Material::FLAT; 1.1138 + } 1.1139 + 1.1140 + switch(reader.GetI1()) { 1.1141 + case 'f': 1.1142 + mat.autofacet = Material::FACETED; 1.1143 + break; 1.1144 + case 'a': 1.1145 + mat.autofacet = Material::AUTOFACETED; 1.1146 + break; 1.1147 + case 's': 1.1148 + mat.autofacet = Material::SMOOTH; 1.1149 + break; 1.1150 + default: 1.1151 + LogError_Ascii(format("Unrecognized faceting mode in `Mat1` chunk with id ")<<nfo.id); 1.1152 + mat.autofacet = Material::FACETED; 1.1153 + } 1.1154 + mat.autofacet_angle = static_cast<float>(reader.GetI1()); 1.1155 + 1.1156 + mat.rgb.r = reader.GetF4(); 1.1157 + mat.rgb.g = reader.GetF4(); 1.1158 + mat.rgb.b = reader.GetF4(); 1.1159 + 1.1160 + mat.alpha = reader.GetF4(); 1.1161 + mat.ka = reader.GetF4(); 1.1162 + mat.ks = reader.GetF4(); 1.1163 + mat.exp = reader.GetF4(); 1.1164 + mat.ior = reader.GetF4(); 1.1165 + 1.1166 + char id[2]; 1.1167 + id[0] = reader.GetI1(),id[1] = reader.GetI1(); 1.1168 + 1.1169 + if (id[0] == 'e' && id[1] == ':') { 1.1170 + mat.tex_env.reset(new Texture()); 1.1171 + 1.1172 + reader.GetI1(); 1.1173 + ReadString_Binary(mat.tex_env->path,reader); 1.1174 + 1.1175 + // advance to next texture-id 1.1176 + id[0] = reader.GetI1(),id[1] = reader.GetI1(); 1.1177 + } 1.1178 + 1.1179 + if (id[0] == 't' && id[1] == ':') { 1.1180 + mat.tex_color.reset(new Texture()); 1.1181 + 1.1182 + reader.GetI1(); 1.1183 + ReadString_Binary(mat.tex_color->path,reader); 1.1184 + 1.1185 + mat.tex_color->transform.mTranslation.x = reader.GetF4(); 1.1186 + mat.tex_color->transform.mTranslation.y = reader.GetF4(); 1.1187 + 1.1188 + mat.tex_color->transform.mScaling.x = reader.GetF4(); 1.1189 + mat.tex_color->transform.mScaling.y = reader.GetF4(); 1.1190 + 1.1191 + // advance to next texture-id 1.1192 + id[0] = reader.GetI1(),id[1] = reader.GetI1(); 1.1193 + } 1.1194 + 1.1195 + if (id[0] == 'b' && id[1] == ':') { 1.1196 + mat.tex_bump.reset(new Texture()); 1.1197 + 1.1198 + reader.GetI1(); 1.1199 + ReadString_Binary(mat.tex_bump->path,reader); 1.1200 + 1.1201 + mat.tex_bump->transform.mTranslation.x = reader.GetF4(); 1.1202 + mat.tex_bump->transform.mTranslation.y = reader.GetF4(); 1.1203 + 1.1204 + mat.tex_bump->transform.mScaling.x = reader.GetF4(); 1.1205 + mat.tex_bump->transform.mScaling.y = reader.GetF4(); 1.1206 + 1.1207 + // skip amplitude for I don't know its purpose. 1.1208 + reader.GetF4(); 1.1209 + } 1.1210 + reader.IncPtr(-2); 1.1211 +} 1.1212 + 1.1213 +// ------------------------------------------------------------------------------------------------ 1.1214 +void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1215 +{ 1.1216 + if(nfo.version > 2) { 1.1217 + return UnsupportedChunk_Binary(reader,nfo,"Came"); 1.1218 + } 1.1219 + 1.1220 + const chunk_guard cn(nfo,reader); 1.1221 + 1.1222 + out.nodes.push_back(boost::shared_ptr<Camera>(new Camera())); 1.1223 + Camera& msh = (Camera&)(*out.nodes.back().get()); 1.1224 + msh = nfo; 1.1225 + 1.1226 + ReadBasicNodeInfo_Binary(msh,reader,nfo); 1.1227 + 1.1228 + // the rest is not interesting for us, so we skip over it. 1.1229 + if(nfo.version > 1) { 1.1230 + if (reader.GetI2()==512) { 1.1231 + reader.IncPtr(42); 1.1232 + } 1.1233 + } 1.1234 +} 1.1235 + 1.1236 +// ------------------------------------------------------------------------------------------------ 1.1237 +void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1238 +{ 1.1239 + if(nfo.version > 2) { 1.1240 + return UnsupportedChunk_Binary(reader,nfo,"Lght"); 1.1241 + } 1.1242 + 1.1243 + const chunk_guard cn(nfo,reader); 1.1244 + 1.1245 + out.nodes.push_back(boost::shared_ptr<Light>(new Light())); 1.1246 + Light& msh = (Light&)(*out.nodes.back().get()); 1.1247 + msh = nfo; 1.1248 + 1.1249 + ReadBasicNodeInfo_Binary(msh,reader,nfo); 1.1250 +} 1.1251 + 1.1252 +// ------------------------------------------------------------------------------------------------ 1.1253 +void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1254 +{ 1.1255 + if(nfo.version > 2) { 1.1256 + return UnsupportedChunk_Binary(reader,nfo,"Grou"); 1.1257 + } 1.1258 + 1.1259 + const chunk_guard cn(nfo,reader); 1.1260 + 1.1261 + out.nodes.push_back(boost::shared_ptr<Group>(new Group())); 1.1262 + Group& msh = (Group&)(*out.nodes.back().get()); 1.1263 + msh = nfo; 1.1264 + 1.1265 + ReadBasicNodeInfo_Binary(msh,reader,nfo); 1.1266 +} 1.1267 + 1.1268 +// ------------------------------------------------------------------------------------------------ 1.1269 +void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) 1.1270 +{ 1.1271 + if(nfo.version > 1) { 1.1272 + return UnsupportedChunk_Binary(reader,nfo,"Unit"); 1.1273 + } 1.1274 + 1.1275 + const chunk_guard cn(nfo,reader); 1.1276 + 1.1277 + // parent chunks preceede their childs, so we should have the 1.1278 + // corresponding chunk already. 1.1279 + for_each(boost::shared_ptr< Node >& nd, out.nodes) { 1.1280 + if (nd->id == nfo.parent_id) { 1.1281 + const unsigned int t=reader.GetI2(); 1.1282 + nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( 1.1283 + LogWarn_Ascii(format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id) 1.1284 + ,1.f):units[t]; 1.1285 + 1.1286 + return; 1.1287 + } 1.1288 + } 1.1289 + LogWarn_Ascii(format()<<"`Unit` chunk "<<nfo.id<<" is a child of " 1.1290 + <<nfo.parent_id<<" which does not exist"); 1.1291 +} 1.1292 + 1.1293 + 1.1294 +#endif