vrshoot

annotate libs/assimp/COBLoader.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file COBLoader.cpp
nuclear@0 42 * @brief Implementation of the TrueSpace COB/SCN importer class.
nuclear@0 43 */
nuclear@0 44 #include "AssimpPCH.h"
nuclear@0 45
nuclear@0 46 #ifndef ASSIMP_BUILD_NO_COB_IMPORTER
nuclear@0 47 #include "COBLoader.h"
nuclear@0 48 #include "COBScene.h"
nuclear@0 49
nuclear@0 50 #include "StreamReader.h"
nuclear@0 51 #include "ParsingUtils.h"
nuclear@0 52 #include "fast_atof.h"
nuclear@0 53
nuclear@0 54 #include "LineSplitter.h"
nuclear@0 55 #include "TinyFormatter.h"
nuclear@0 56
nuclear@0 57 using namespace Assimp;
nuclear@0 58 using namespace Assimp::COB;
nuclear@0 59 using namespace Assimp::Formatter;
nuclear@0 60
nuclear@0 61 #define for_each BOOST_FOREACH
nuclear@0 62
nuclear@0 63
nuclear@0 64 static const float units[] = {
nuclear@0 65 1000.f,
nuclear@0 66 100.f,
nuclear@0 67 1.f,
nuclear@0 68 0.001f,
nuclear@0 69 1.f/0.0254f,
nuclear@0 70 1.f/0.3048f,
nuclear@0 71 1.f/0.9144f,
nuclear@0 72 1.f/1609.344f
nuclear@0 73 };
nuclear@0 74
nuclear@0 75 static const aiImporterDesc desc = {
nuclear@0 76 "TrueSpace Object Importer",
nuclear@0 77 "",
nuclear@0 78 "",
nuclear@0 79 "little-endian files only",
nuclear@0 80 aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
nuclear@0 81 0,
nuclear@0 82 0,
nuclear@0 83 0,
nuclear@0 84 0,
nuclear@0 85 "cob scn"
nuclear@0 86 };
nuclear@0 87
nuclear@0 88
nuclear@0 89 // ------------------------------------------------------------------------------------------------
nuclear@0 90 // Constructor to be privately used by Importer
nuclear@0 91 COBImporter::COBImporter()
nuclear@0 92 {}
nuclear@0 93
nuclear@0 94 // ------------------------------------------------------------------------------------------------
nuclear@0 95 // Destructor, private as well
nuclear@0 96 COBImporter::~COBImporter()
nuclear@0 97 {}
nuclear@0 98
nuclear@0 99 // ------------------------------------------------------------------------------------------------
nuclear@0 100 // Returns whether the class can handle the format of the given file.
nuclear@0 101 bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
nuclear@0 102 {
nuclear@0 103 const std::string& extension = GetExtension(pFile);
nuclear@0 104 if (extension == "cob" || extension == "scn") {
nuclear@0 105 return true;
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 else if ((!extension.length() || checkSig) && pIOHandler) {
nuclear@0 109 const char* tokens[] = {"Caligary"};
nuclear@0 110 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
nuclear@0 111 }
nuclear@0 112 return false;
nuclear@0 113 }
nuclear@0 114
nuclear@0 115 // ------------------------------------------------------------------------------------------------
nuclear@0 116 // Loader meta information
nuclear@0 117 const aiImporterDesc* COBImporter::GetInfo () const
nuclear@0 118 {
nuclear@0 119 return &desc;
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 // ------------------------------------------------------------------------------------------------
nuclear@0 123 // Setup configuration properties for the loader
nuclear@0 124 void COBImporter::SetupProperties(const Importer* /*pImp*/)
nuclear@0 125 {
nuclear@0 126 // nothing to be done for the moment
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 // ------------------------------------------------------------------------------------------------
nuclear@0 130 /*static*/ void COBImporter::ThrowException(const std::string& msg)
nuclear@0 131 {
nuclear@0 132 throw DeadlyImportError("COB: "+msg);
nuclear@0 133 }
nuclear@0 134
nuclear@0 135 // ------------------------------------------------------------------------------------------------
nuclear@0 136 // Imports the given file into the given scene structure.
nuclear@0 137 void COBImporter::InternReadFile( const std::string& pFile,
nuclear@0 138 aiScene* pScene, IOSystem* pIOHandler)
nuclear@0 139 {
nuclear@0 140 COB::Scene scene;
nuclear@0 141 boost::scoped_ptr<StreamReaderLE> stream(new StreamReaderLE( pIOHandler->Open(pFile,"rb")) );
nuclear@0 142
nuclear@0 143 // check header
nuclear@0 144 char head[32];
nuclear@0 145 stream->CopyAndAdvance(head,32);
nuclear@0 146 if (strncmp(head,"Caligari ",9)) {
nuclear@0 147 ThrowException("Could not found magic id: `Caligari`");
nuclear@0 148 }
nuclear@0 149
nuclear@0 150 DefaultLogger::get()->info("File format tag: "+std::string(head+9,6));
nuclear@0 151 void (COBImporter::* load)(Scene&,StreamReaderLE*)= head[15]=='A'?&COBImporter::ReadAsciiFile:&COBImporter::ReadBinaryFile;
nuclear@0 152 if (head[16]!='L') {
nuclear@0 153 ThrowException("File is big-endian, which is not supported");
nuclear@0 154 }
nuclear@0 155
nuclear@0 156 // load data into intermediate structures
nuclear@0 157 (this->*load)(scene,stream.get());
nuclear@0 158 if(scene.nodes.empty()) {
nuclear@0 159 ThrowException("No nodes loaded");
nuclear@0 160 }
nuclear@0 161
nuclear@0 162 // sort faces by material indices
nuclear@0 163 for_each(boost::shared_ptr< Node >& n,scene.nodes) {
nuclear@0 164 if (n->type == Node::TYPE_MESH) {
nuclear@0 165 Mesh& mesh = (Mesh&)(*n.get());
nuclear@0 166 for_each(Face& f,mesh.faces) {
nuclear@0 167 mesh.temp_map[f.material].push_back(&f);
nuclear@0 168 }
nuclear@0 169 }
nuclear@0 170 }
nuclear@0 171
nuclear@0 172 // count meshes
nuclear@0 173 for_each(boost::shared_ptr< Node >& n,scene.nodes) {
nuclear@0 174 if (n->type == Node::TYPE_MESH) {
nuclear@0 175 Mesh& mesh = (Mesh&)(*n.get());
nuclear@0 176 if (mesh.vertex_positions.size() && mesh.texture_coords.size()) {
nuclear@0 177 pScene->mNumMeshes += mesh.temp_map.size();
nuclear@0 178 }
nuclear@0 179 }
nuclear@0 180 }
nuclear@0 181 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
nuclear@0 182 pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes]();
nuclear@0 183 pScene->mNumMeshes = 0;
nuclear@0 184
nuclear@0 185 // count lights and cameras
nuclear@0 186 for_each(boost::shared_ptr< Node >& n,scene.nodes) {
nuclear@0 187 if (n->type == Node::TYPE_LIGHT) {
nuclear@0 188 ++pScene->mNumLights;
nuclear@0 189 }
nuclear@0 190 else if (n->type == Node::TYPE_CAMERA) {
nuclear@0 191 ++pScene->mNumCameras;
nuclear@0 192 }
nuclear@0 193 }
nuclear@0 194
nuclear@0 195 if (pScene->mNumLights) {
nuclear@0 196 pScene->mLights = new aiLight*[pScene->mNumLights]();
nuclear@0 197 }
nuclear@0 198 if (pScene->mNumCameras) {
nuclear@0 199 pScene->mCameras = new aiCamera*[pScene->mNumCameras]();
nuclear@0 200 }
nuclear@0 201 pScene->mNumLights = pScene->mNumCameras = 0;
nuclear@0 202
nuclear@0 203 // resolve parents by their IDs and build the output graph
nuclear@0 204 boost::scoped_ptr<Node> root(new Group());
nuclear@0 205 for(size_t n = 0; n < scene.nodes.size(); ++n) {
nuclear@0 206 const Node& nn = *scene.nodes[n].get();
nuclear@0 207 if(nn.parent_id==0) {
nuclear@0 208 root->temp_children.push_back(&nn);
nuclear@0 209 }
nuclear@0 210
nuclear@0 211 for(size_t m = n; m < scene.nodes.size(); ++m) {
nuclear@0 212 const Node& mm = *scene.nodes[m].get();
nuclear@0 213 if (mm.parent_id == nn.id) {
nuclear@0 214 nn.temp_children.push_back(&mm);
nuclear@0 215 }
nuclear@0 216 }
nuclear@0 217 }
nuclear@0 218
nuclear@0 219 pScene->mRootNode = BuildNodes(*root.get(),scene,pScene);
nuclear@0 220 }
nuclear@0 221
nuclear@0 222 // ------------------------------------------------------------------------------------------------
nuclear@0 223 void ConvertTexture(boost::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type)
nuclear@0 224 {
nuclear@0 225 const aiString path( tex->path );
nuclear@0 226 out->AddProperty(&path,AI_MATKEY_TEXTURE(type,0));
nuclear@0 227 out->AddProperty(&tex->transform,1,AI_MATKEY_UVTRANSFORM(type,0));
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 // ------------------------------------------------------------------------------------------------
nuclear@0 231 aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill)
nuclear@0 232 {
nuclear@0 233 aiNode* nd = new aiNode();
nuclear@0 234 nd->mName.Set(root.name);
nuclear@0 235 nd->mTransformation = root.transform;
nuclear@0 236
nuclear@0 237 // Note to everybody believing Voodoo is appropriate here:
nuclear@0 238 // I know polymorphism, run as fast as you can ;-)
nuclear@0 239 if (Node::TYPE_MESH == root.type) {
nuclear@0 240 const Mesh& ndmesh = (const Mesh&)(root);
nuclear@0 241 if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
nuclear@0 242
nuclear@0 243 typedef std::pair<unsigned int,Mesh::FaceRefList> Entry;
nuclear@0 244 for_each(const Entry& reflist,ndmesh.temp_map) {
nuclear@0 245 { // create mesh
nuclear@0 246 size_t n = 0;
nuclear@0 247 for_each(Face* f, reflist.second) {
nuclear@0 248 n += f->indices.size();
nuclear@0 249 }
nuclear@0 250 if (!n) {
nuclear@0 251 continue;
nuclear@0 252 }
nuclear@0 253 aiMesh* outmesh = fill->mMeshes[fill->mNumMeshes++] = new aiMesh();
nuclear@0 254 ++nd->mNumMeshes;
nuclear@0 255
nuclear@0 256 outmesh->mVertices = new aiVector3D[n];
nuclear@0 257 outmesh->mTextureCoords[0] = new aiVector3D[n];
nuclear@0 258
nuclear@0 259 outmesh->mFaces = new aiFace[reflist.second.size()]();
nuclear@0 260 for_each(Face* f, reflist.second) {
nuclear@0 261 if (f->indices.empty()) {
nuclear@0 262 continue;
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 aiFace& fout = outmesh->mFaces[outmesh->mNumFaces++];
nuclear@0 266 fout.mIndices = new unsigned int[f->indices.size()];
nuclear@0 267
nuclear@0 268 for_each(VertexIndex& v, f->indices) {
nuclear@0 269 if (v.pos_idx >= ndmesh.vertex_positions.size()) {
nuclear@0 270 ThrowException("Position index out of range");
nuclear@0 271 }
nuclear@0 272 if (v.uv_idx >= ndmesh.texture_coords.size()) {
nuclear@0 273 ThrowException("UV index out of range");
nuclear@0 274 }
nuclear@0 275 outmesh->mVertices[outmesh->mNumVertices] = ndmesh.vertex_positions[ v.pos_idx ];
nuclear@0 276 outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D(
nuclear@0 277 ndmesh.texture_coords[ v.uv_idx ].x,
nuclear@0 278 ndmesh.texture_coords[ v.uv_idx ].y,
nuclear@0 279 0.f
nuclear@0 280 );
nuclear@0 281
nuclear@0 282 fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++;
nuclear@0 283 }
nuclear@0 284 }
nuclear@0 285 outmesh->mMaterialIndex = fill->mNumMaterials;
nuclear@0 286 }{ // create material
nuclear@0 287 const Material* min = NULL;
nuclear@0 288 for_each(const Material& m, scin.materials) {
nuclear@0 289 if (m.parent_id == ndmesh.id && m.matnum == reflist.first) {
nuclear@0 290 min = &m;
nuclear@0 291 break;
nuclear@0 292 }
nuclear@0 293 }
nuclear@0 294 boost::scoped_ptr<const Material> defmat;
nuclear@0 295 if(!min) {
nuclear@0 296 DefaultLogger::get()->debug(format()<<"Could not resolve material index "
nuclear@0 297 <<reflist.first<<" - creating default material for this slot");
nuclear@0 298
nuclear@0 299 defmat.reset(min=new Material());
nuclear@0 300 }
nuclear@0 301
nuclear@0 302 aiMaterial* mat = new aiMaterial();
nuclear@0 303 fill->mMaterials[fill->mNumMaterials++] = mat;
nuclear@0 304
nuclear@0 305 const aiString s(format("#mat_")<<fill->mNumMeshes<<"_"<<min->matnum);
nuclear@0 306 mat->AddProperty(&s,AI_MATKEY_NAME);
nuclear@0 307
nuclear@0 308 if(int tmp = ndmesh.draw_flags & Mesh::WIRED ? 1 : 0) {
nuclear@0 309 mat->AddProperty(&tmp,1,AI_MATKEY_ENABLE_WIREFRAME);
nuclear@0 310 }
nuclear@0 311
nuclear@0 312 { int shader;
nuclear@0 313 switch(min->shader)
nuclear@0 314 {
nuclear@0 315 case Material::FLAT:
nuclear@0 316 shader = aiShadingMode_Gouraud;
nuclear@0 317 break;
nuclear@0 318
nuclear@0 319 case Material::PHONG:
nuclear@0 320 shader = aiShadingMode_Phong;
nuclear@0 321 break;
nuclear@0 322
nuclear@0 323 case Material::METAL:
nuclear@0 324 shader = aiShadingMode_CookTorrance;
nuclear@0 325 break;
nuclear@0 326
nuclear@0 327 default:
nuclear@0 328 ai_assert(false); // shouldn't be here
nuclear@0 329 }
nuclear@0 330 mat->AddProperty(&shader,1,AI_MATKEY_SHADING_MODEL);
nuclear@0 331 if(shader != aiShadingMode_Gouraud) {
nuclear@0 332 mat->AddProperty(&min->exp,1,AI_MATKEY_SHININESS);
nuclear@0 333 }
nuclear@0 334 }
nuclear@0 335
nuclear@0 336 mat->AddProperty(&min->ior,1,AI_MATKEY_REFRACTI);
nuclear@0 337 mat->AddProperty(&min->rgb,1,AI_MATKEY_COLOR_DIFFUSE);
nuclear@0 338
nuclear@0 339 aiColor3D c = aiColor3D(min->rgb)*min->ks;
nuclear@0 340 mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
nuclear@0 341
nuclear@0 342 c = aiColor3D(min->rgb)*min->ka;
nuclear@0 343 mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT);
nuclear@0 344
nuclear@0 345 // convert textures if some exist.
nuclear@0 346 if(min->tex_color) {
nuclear@0 347 ConvertTexture(min->tex_color,mat,aiTextureType_DIFFUSE);
nuclear@0 348 }
nuclear@0 349 if(min->tex_env) {
nuclear@0 350 ConvertTexture(min->tex_env ,mat,aiTextureType_UNKNOWN);
nuclear@0 351 }
nuclear@0 352 if(min->tex_bump) {
nuclear@0 353 ConvertTexture(min->tex_bump ,mat,aiTextureType_HEIGHT);
nuclear@0 354 }
nuclear@0 355 }
nuclear@0 356 }
nuclear@0 357 }
nuclear@0 358 }
nuclear@0 359 else if (Node::TYPE_LIGHT == root.type) {
nuclear@0 360 const Light& ndlight = (const Light&)(root);
nuclear@0 361 aiLight* outlight = fill->mLights[fill->mNumLights++] = new aiLight();
nuclear@0 362
nuclear@0 363 outlight->mName.Set(ndlight.name);
nuclear@0 364 outlight->mColorDiffuse = outlight->mColorAmbient = outlight->mColorSpecular = ndlight.color;
nuclear@0 365
nuclear@0 366 outlight->mAngleOuterCone = AI_DEG_TO_RAD(ndlight.angle);
nuclear@0 367 outlight->mAngleInnerCone = AI_DEG_TO_RAD(ndlight.inner_angle);
nuclear@0 368
nuclear@0 369 // XXX
nuclear@0 370 outlight->mType = ndlight.ltype==Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL;
nuclear@0 371 }
nuclear@0 372 else if (Node::TYPE_CAMERA == root.type) {
nuclear@0 373 const Camera& ndcam = (const Camera&)(root);
nuclear@0 374 aiCamera* outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera();
nuclear@0 375
nuclear@0 376 outcam->mName.Set(ndcam.name);
nuclear@0 377 }
nuclear@0 378
nuclear@0 379 // add meshes
nuclear@0 380 if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0
nuclear@0 381 nd->mMeshes = new unsigned int[nd->mNumMeshes];
nuclear@0 382 for(unsigned int i = 0; i < nd->mNumMeshes;++i) {
nuclear@0 383 nd->mMeshes[i] = fill->mNumMeshes-i-1;
nuclear@0 384 }
nuclear@0 385 }
nuclear@0 386
nuclear@0 387 // add children recursively
nuclear@0 388 nd->mChildren = new aiNode*[root.temp_children.size()]();
nuclear@0 389 for_each(const Node* n, root.temp_children) {
nuclear@0 390 (nd->mChildren[nd->mNumChildren++] = BuildNodes(*n,scin,fill))->mParent = nd;
nuclear@0 391 }
nuclear@0 392
nuclear@0 393 return nd;
nuclear@0 394 }
nuclear@0 395
nuclear@0 396 // ------------------------------------------------------------------------------------------------
nuclear@0 397 // Read an ASCII file into the given scene data structure
nuclear@0 398 void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
nuclear@0 399 {
nuclear@0 400 ChunkInfo ci;
nuclear@0 401 for(LineSplitter splitter(*stream);splitter;++splitter) {
nuclear@0 402
nuclear@0 403 // add all chunks to be recognized here. /else ../ omitted intentionally.
nuclear@0 404 if (splitter.match_start("PolH ")) {
nuclear@0 405 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 406 ReadPolH_Ascii(out,splitter,ci);
nuclear@0 407 }
nuclear@0 408 if (splitter.match_start("BitM ")) {
nuclear@0 409 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 410 ReadBitM_Ascii(out,splitter,ci);
nuclear@0 411 }
nuclear@0 412 if (splitter.match_start("Mat1 ")) {
nuclear@0 413 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 414 ReadMat1_Ascii(out,splitter,ci);
nuclear@0 415 }
nuclear@0 416 if (splitter.match_start("Grou ")) {
nuclear@0 417 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 418 ReadGrou_Ascii(out,splitter,ci);
nuclear@0 419 }
nuclear@0 420 if (splitter.match_start("Lght ")) {
nuclear@0 421 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 422 ReadLght_Ascii(out,splitter,ci);
nuclear@0 423 }
nuclear@0 424 if (splitter.match_start("Came ")) {
nuclear@0 425 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 426 ReadCame_Ascii(out,splitter,ci);
nuclear@0 427 }
nuclear@0 428 if (splitter.match_start("Bone ")) {
nuclear@0 429 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 430 ReadBone_Ascii(out,splitter,ci);
nuclear@0 431 }
nuclear@0 432 if (splitter.match_start("Chan ")) {
nuclear@0 433 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 434 ReadChan_Ascii(out,splitter,ci);
nuclear@0 435 }
nuclear@0 436 if (splitter.match_start("Unit ")) {
nuclear@0 437 ReadChunkInfo_Ascii(ci,splitter);
nuclear@0 438 ReadUnit_Ascii(out,splitter,ci);
nuclear@0 439 }
nuclear@0 440 if (splitter.match_start("END ")) {
nuclear@0 441 // we don't need this, but I guess there is a reason this
nuclear@0 442 // chunk has been implemented into COB for.
nuclear@0 443 return;
nuclear@0 444 }
nuclear@0 445 }
nuclear@0 446 }
nuclear@0 447
nuclear@0 448 // ------------------------------------------------------------------------------------------------
nuclear@0 449 void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter)
nuclear@0 450 {
nuclear@0 451 const char* all_tokens[8];
nuclear@0 452 splitter.get_tokens(all_tokens);
nuclear@0 453
nuclear@0 454 out.version = (all_tokens[1][1]-'0')*100+(all_tokens[1][3]-'0')*10+(all_tokens[1][4]-'0');
nuclear@0 455 out.id = strtoul10(all_tokens[3]);
nuclear@0 456 out.parent_id = strtoul10(all_tokens[5]);
nuclear@0 457 out.size = strtol10(all_tokens[7]);
nuclear@0 458 }
nuclear@0 459
nuclear@0 460 // ------------------------------------------------------------------------------------------------
nuclear@0 461 void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name)
nuclear@0 462 {
nuclear@0 463 const std::string error = format("Encountered unsupported chunk: ") << name <<
nuclear@0 464 " [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
nuclear@0 465
nuclear@0 466 // we can recover if the chunk size was specified.
nuclear@0 467 if(nfo.size != static_cast<unsigned int>(-1)) {
nuclear@0 468 DefaultLogger::get()->error(error);
nuclear@0 469
nuclear@0 470 // (HACK) - our current position in the stream is the beginning of the
nuclear@0 471 // head line of the next chunk. That's fine, but the caller is going
nuclear@0 472 // to call ++ on `splitter`, which we need to swallow to avoid
nuclear@0 473 // missing the next line.
nuclear@0 474 splitter.get_stream().IncPtr(nfo.size);
nuclear@0 475 splitter.swallow_next_increment();
nuclear@0 476 }
nuclear@0 477 else ThrowException(error);
nuclear@0 478 }
nuclear@0 479
nuclear@0 480 // ------------------------------------------------------------------------------------------------
nuclear@0 481 void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message) {
nuclear@0 482 LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]");
nuclear@0 483 }
nuclear@0 484
nuclear@0 485 // ------------------------------------------------------------------------------------------------
nuclear@0 486 void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message) {
nuclear@0 487 LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]");
nuclear@0 488 }
nuclear@0 489
nuclear@0 490 // ------------------------------------------------------------------------------------------------
nuclear@0 491 void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message) {
nuclear@0 492 LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]");
nuclear@0 493 }
nuclear@0 494
nuclear@0 495 // ------------------------------------------------------------------------------------------------
nuclear@0 496 void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message) {
nuclear@0 497 LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]");
nuclear@0 498 }
nuclear@0 499
nuclear@0 500 // ------------------------------------------------------------------------------------------------
nuclear@0 501 void COBImporter::LogWarn_Ascii(const Formatter::format& message) {
nuclear@0 502 DefaultLogger::get()->warn(std::string("COB: ")+=message);
nuclear@0 503 }
nuclear@0 504
nuclear@0 505 // ------------------------------------------------------------------------------------------------
nuclear@0 506 void COBImporter::LogError_Ascii(const Formatter::format& message) {
nuclear@0 507 DefaultLogger::get()->error(std::string("COB: ")+=message);
nuclear@0 508 }
nuclear@0 509
nuclear@0 510 // ------------------------------------------------------------------------------------------------
nuclear@0 511 void COBImporter::LogInfo_Ascii(const Formatter::format& message) {
nuclear@0 512 DefaultLogger::get()->info(std::string("COB: ")+=message);
nuclear@0 513 }
nuclear@0 514
nuclear@0 515 // ------------------------------------------------------------------------------------------------
nuclear@0 516 void COBImporter::LogDebug_Ascii(const Formatter::format& message) {
nuclear@0 517 DefaultLogger::get()->debug(std::string("COB: ")+=message);
nuclear@0 518 }
nuclear@0 519
nuclear@0 520 // ------------------------------------------------------------------------------------------------
nuclear@0 521 void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
nuclear@0 522 {
nuclear@0 523 for(;splitter;++splitter) {
nuclear@0 524 if (splitter.match_start("Name")) {
nuclear@0 525 msh.name = std::string(splitter[1]);
nuclear@0 526
nuclear@0 527 // make nice names by merging the dupe count
nuclear@0 528 std::replace(msh.name.begin(),msh.name.end(),
nuclear@0 529 ',','_');
nuclear@0 530 }
nuclear@0 531 else if (splitter.match_start("Transform")) {
nuclear@0 532 for(unsigned int y = 0; y < 4 && ++splitter; ++y) {
nuclear@0 533 const char* s = splitter->c_str();
nuclear@0 534 for(unsigned int x = 0; x < 4; ++x) {
nuclear@0 535 SkipSpaces(&s);
nuclear@0 536 msh.transform[y][x] = fast_atof(&s);
nuclear@0 537 }
nuclear@0 538 }
nuclear@0 539 // we need the transform chunk, so we won't return until we have it.
nuclear@0 540 return;
nuclear@0 541 }
nuclear@0 542 }
nuclear@0 543 }
nuclear@0 544
nuclear@0 545 // ------------------------------------------------------------------------------------------------
nuclear@0 546 template <typename T>
nuclear@0 547 void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
nuclear@0 548 {
nuclear@0 549 const char* rgb = *in;
nuclear@0 550 for(unsigned int i = 0; i < 3; ++i) {
nuclear@0 551 SkipSpaces(&rgb);
nuclear@0 552 if (*rgb == ',')++rgb;
nuclear@0 553 SkipSpaces(&rgb);
nuclear@0 554
nuclear@0 555 fill[i] = fast_atof(&rgb);
nuclear@0 556 }
nuclear@0 557 *in = rgb;
nuclear@0 558 }
nuclear@0 559
nuclear@0 560 // ------------------------------------------------------------------------------------------------
nuclear@0 561 void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 562 {
nuclear@0 563 if(nfo.version > 8) {
nuclear@0 564 return UnsupportedChunk_Ascii(splitter,nfo,"Mat1");
nuclear@0 565 }
nuclear@0 566
nuclear@0 567 ++splitter;
nuclear@0 568 if (!splitter.match_start("mat# ")) {
nuclear@0 569 LogWarn_Ascii(splitter,format()<<
nuclear@0 570 "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
nuclear@0 571 return;
nuclear@0 572 }
nuclear@0 573
nuclear@0 574 out.materials.push_back(Material());
nuclear@0 575 Material& mat = out.materials.back();
nuclear@0 576 mat = nfo;
nuclear@0 577
nuclear@0 578 mat.matnum = strtoul10(splitter[1]);
nuclear@0 579 ++splitter;
nuclear@0 580
nuclear@0 581 if (!splitter.match_start("shader: ")) {
nuclear@0 582 LogWarn_Ascii(splitter,format()<<
nuclear@0 583 "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
nuclear@0 584 return;
nuclear@0 585 }
nuclear@0 586 std::string shader = std::string(splitter[1]);
nuclear@0 587 shader = shader.substr(0,shader.find_first_of(" \t"));
nuclear@0 588
nuclear@0 589 if (shader == "metal") {
nuclear@0 590 mat.shader = Material::METAL;
nuclear@0 591 }
nuclear@0 592 else if (shader == "phong") {
nuclear@0 593 mat.shader = Material::PHONG;
nuclear@0 594 }
nuclear@0 595 else if (shader != "flat") {
nuclear@0 596 LogWarn_Ascii(splitter,format()<<
nuclear@0 597 "Unknown value for `shader` in `Mat1` chunk "<<nfo.id);
nuclear@0 598 }
nuclear@0 599
nuclear@0 600 ++splitter;
nuclear@0 601 if (!splitter.match_start("rgb ")) {
nuclear@0 602 LogWarn_Ascii(splitter,format()<<
nuclear@0 603 "Expected `rgb` line in `Mat1` chunk "<<nfo.id);
nuclear@0 604 }
nuclear@0 605
nuclear@0 606 const char* rgb = splitter[1];
nuclear@0 607 ReadFloat3Tuple_Ascii(mat.rgb,&rgb);
nuclear@0 608
nuclear@0 609 ++splitter;
nuclear@0 610 if (!splitter.match_start("alpha ")) {
nuclear@0 611 LogWarn_Ascii(splitter,format()<<
nuclear@0 612 "Expected `alpha` line in `Mat1` chunk "<<nfo.id);
nuclear@0 613 }
nuclear@0 614
nuclear@0 615 const char* tokens[10];
nuclear@0 616 splitter.get_tokens(tokens);
nuclear@0 617
nuclear@0 618 mat.alpha = fast_atof( tokens[1] );
nuclear@0 619 mat.ka = fast_atof( tokens[3] );
nuclear@0 620 mat.ks = fast_atof( tokens[5] );
nuclear@0 621 mat.exp = fast_atof( tokens[7] );
nuclear@0 622 mat.ior = fast_atof( tokens[9] );
nuclear@0 623 }
nuclear@0 624
nuclear@0 625 // ------------------------------------------------------------------------------------------------
nuclear@0 626 void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 627 {
nuclear@0 628 if(nfo.version > 1) {
nuclear@0 629 return UnsupportedChunk_Ascii(splitter,nfo,"Unit");
nuclear@0 630 }
nuclear@0 631 ++splitter;
nuclear@0 632 if (!splitter.match_start("Units ")) {
nuclear@0 633 LogWarn_Ascii(splitter,format()<<
nuclear@0 634 "Expected `Units` line in `Unit` chunk "<<nfo.id);
nuclear@0 635 return;
nuclear@0 636 }
nuclear@0 637
nuclear@0 638 // parent chunks preceede their childs, so we should have the
nuclear@0 639 // corresponding chunk already.
nuclear@0 640 for_each(boost::shared_ptr< Node >& nd, out.nodes) {
nuclear@0 641 if (nd->id == nfo.parent_id) {
nuclear@0 642 const unsigned int t=strtoul10(splitter[1]);
nuclear@0 643
nuclear@0 644 nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
nuclear@0 645 LogWarn_Ascii(splitter,format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id)
nuclear@0 646 ,1.f):units[t];
nuclear@0 647 return;
nuclear@0 648 }
nuclear@0 649 }
nuclear@0 650 LogWarn_Ascii(splitter,format()<<"`Unit` chunk "<<nfo.id<<" is a child of "
nuclear@0 651 <<nfo.parent_id<<" which does not exist");
nuclear@0 652 }
nuclear@0 653
nuclear@0 654 // ------------------------------------------------------------------------------------------------
nuclear@0 655 void COBImporter::ReadChan_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 656 {
nuclear@0 657 if(nfo.version > 8) {
nuclear@0 658 return UnsupportedChunk_Ascii(splitter,nfo,"Chan");
nuclear@0 659 }
nuclear@0 660 }
nuclear@0 661
nuclear@0 662 // ------------------------------------------------------------------------------------------------
nuclear@0 663 void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 664 {
nuclear@0 665 if(nfo.version > 8) {
nuclear@0 666 return UnsupportedChunk_Ascii(splitter,nfo,"Lght");
nuclear@0 667 }
nuclear@0 668
nuclear@0 669 out.nodes.push_back(boost::shared_ptr<Light>(new Light()));
nuclear@0 670 Light& msh = (Light&)(*out.nodes.back().get());
nuclear@0 671 msh = nfo;
nuclear@0 672
nuclear@0 673 ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
nuclear@0 674
nuclear@0 675 if (splitter.match_start("Infinite ")) {
nuclear@0 676 msh.ltype = Light::INFINITE;
nuclear@0 677 }
nuclear@0 678 else if (splitter.match_start("Local ")) {
nuclear@0 679 msh.ltype = Light::LOCAL;
nuclear@0 680 }
nuclear@0 681 else if (splitter.match_start("Spot ")) {
nuclear@0 682 msh.ltype = Light::SPOT;
nuclear@0 683 }
nuclear@0 684 else {
nuclear@0 685 LogWarn_Ascii(splitter,format()<<
nuclear@0 686 "Unknown kind of light source in `Lght` chunk "<<nfo.id<<" : "<<*splitter);
nuclear@0 687 msh.ltype = Light::SPOT;
nuclear@0 688 }
nuclear@0 689
nuclear@0 690 ++splitter;
nuclear@0 691 if (!splitter.match_start("color ")) {
nuclear@0 692 LogWarn_Ascii(splitter,format()<<
nuclear@0 693 "Expected `color` line in `Lght` chunk "<<nfo.id);
nuclear@0 694 }
nuclear@0 695
nuclear@0 696 const char* rgb = splitter[1];
nuclear@0 697 ReadFloat3Tuple_Ascii(msh.color ,&rgb);
nuclear@0 698
nuclear@0 699 SkipSpaces(&rgb);
nuclear@0 700 if (strncmp(rgb,"cone angle",10)) {
nuclear@0 701 LogWarn_Ascii(splitter,format()<<
nuclear@0 702 "Expected `cone angle` entity in `color` line in `Lght` chunk "<<nfo.id);
nuclear@0 703 }
nuclear@0 704 SkipSpaces(rgb+10,&rgb);
nuclear@0 705 msh.angle = fast_atof(&rgb);
nuclear@0 706
nuclear@0 707 SkipSpaces(&rgb);
nuclear@0 708 if (strncmp(rgb,"inner angle",11)) {
nuclear@0 709 LogWarn_Ascii(splitter,format()<<
nuclear@0 710 "Expected `inner angle` entity in `color` line in `Lght` chunk "<<nfo.id);
nuclear@0 711 }
nuclear@0 712 SkipSpaces(rgb+11,&rgb);
nuclear@0 713 msh.inner_angle = fast_atof(&rgb);
nuclear@0 714
nuclear@0 715 // skip the rest for we can't handle this kind of physically-based lighting information.
nuclear@0 716 }
nuclear@0 717
nuclear@0 718 // ------------------------------------------------------------------------------------------------
nuclear@0 719 void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 720 {
nuclear@0 721 if(nfo.version > 2) {
nuclear@0 722 return UnsupportedChunk_Ascii(splitter,nfo,"Came");
nuclear@0 723 }
nuclear@0 724
nuclear@0 725 out.nodes.push_back(boost::shared_ptr<Camera>(new Camera()));
nuclear@0 726 Camera& msh = (Camera&)(*out.nodes.back().get());
nuclear@0 727 msh = nfo;
nuclear@0 728
nuclear@0 729 ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
nuclear@0 730
nuclear@0 731 // skip the next line, we don't know this differenciation between a
nuclear@0 732 // standard camera and a panoramic camera.
nuclear@0 733 ++splitter;
nuclear@0 734 }
nuclear@0 735
nuclear@0 736 // ------------------------------------------------------------------------------------------------
nuclear@0 737 void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 738 {
nuclear@0 739 if(nfo.version > 5) {
nuclear@0 740 return UnsupportedChunk_Ascii(splitter,nfo,"Bone");
nuclear@0 741 }
nuclear@0 742
nuclear@0 743 out.nodes.push_back(boost::shared_ptr<Bone>(new Bone()));
nuclear@0 744 Bone& msh = (Bone&)(*out.nodes.back().get());
nuclear@0 745 msh = nfo;
nuclear@0 746
nuclear@0 747 ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
nuclear@0 748
nuclear@0 749 // TODO
nuclear@0 750 }
nuclear@0 751
nuclear@0 752 // ------------------------------------------------------------------------------------------------
nuclear@0 753 void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 754 {
nuclear@0 755 if(nfo.version > 1) {
nuclear@0 756 return UnsupportedChunk_Ascii(splitter,nfo,"Grou");
nuclear@0 757 }
nuclear@0 758
nuclear@0 759 out.nodes.push_back(boost::shared_ptr<Group>(new Group()));
nuclear@0 760 Group& msh = (Group&)(*out.nodes.back().get());
nuclear@0 761 msh = nfo;
nuclear@0 762
nuclear@0 763 ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
nuclear@0 764 }
nuclear@0 765
nuclear@0 766 // ------------------------------------------------------------------------------------------------
nuclear@0 767 void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 768 {
nuclear@0 769 if(nfo.version > 8) {
nuclear@0 770 return UnsupportedChunk_Ascii(splitter,nfo,"PolH");
nuclear@0 771 }
nuclear@0 772
nuclear@0 773 out.nodes.push_back(boost::shared_ptr<Mesh>(new Mesh()));
nuclear@0 774 Mesh& msh = (Mesh&)(*out.nodes.back().get());
nuclear@0 775 msh = nfo;
nuclear@0 776
nuclear@0 777 ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
nuclear@0 778
nuclear@0 779 // the chunk has a fixed order of components, but some are not interesting of us so
nuclear@0 780 // we're just looking for keywords in arbitrary order. The end of the chunk is
nuclear@0 781 // either the last `Face` or the `DrawFlags` attribute, depending on the format ver.
nuclear@0 782 for(;splitter;++splitter) {
nuclear@0 783 if (splitter.match_start("World Vertices")) {
nuclear@0 784 const unsigned int cnt = strtoul10(splitter[2]);
nuclear@0 785 msh.vertex_positions.resize(cnt);
nuclear@0 786
nuclear@0 787 for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) {
nuclear@0 788 const char* s = splitter->c_str();
nuclear@0 789
nuclear@0 790 aiVector3D& v = msh.vertex_positions[cur];
nuclear@0 791
nuclear@0 792 SkipSpaces(&s);
nuclear@0 793 v.x = fast_atof(&s);
nuclear@0 794 SkipSpaces(&s);
nuclear@0 795 v.y = fast_atof(&s);
nuclear@0 796 SkipSpaces(&s);
nuclear@0 797 v.z = fast_atof(&s);
nuclear@0 798 }
nuclear@0 799 }
nuclear@0 800 else if (splitter.match_start("Texture Vertices")) {
nuclear@0 801 const unsigned int cnt = strtoul10(splitter[2]);
nuclear@0 802 msh.texture_coords.resize(cnt);
nuclear@0 803
nuclear@0 804 for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) {
nuclear@0 805 const char* s = splitter->c_str();
nuclear@0 806
nuclear@0 807 aiVector2D& v = msh.texture_coords[cur];
nuclear@0 808
nuclear@0 809 SkipSpaces(&s);
nuclear@0 810 v.x = fast_atof(&s);
nuclear@0 811 SkipSpaces(&s);
nuclear@0 812 v.y = fast_atof(&s);
nuclear@0 813 }
nuclear@0 814 }
nuclear@0 815 else if (splitter.match_start("Faces")) {
nuclear@0 816 const unsigned int cnt = strtoul10(splitter[1]);
nuclear@0 817 msh.faces.reserve(cnt);
nuclear@0 818
nuclear@0 819 for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) {
nuclear@0 820 if (splitter.match_start("Hole")) {
nuclear@0 821 LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line");
nuclear@0 822 continue;
nuclear@0 823 }
nuclear@0 824
nuclear@0 825 if (!splitter.match_start("Face")) {
nuclear@0 826 ThrowException("Expected Face line");
nuclear@0 827 }
nuclear@0 828
nuclear@0 829 msh.faces.push_back(Face());
nuclear@0 830 Face& face = msh.faces.back();
nuclear@0 831
nuclear@0 832 face.indices.resize(strtoul10(splitter[2]));
nuclear@0 833 face.flags = strtoul10(splitter[4]);
nuclear@0 834 face.material = strtoul10(splitter[6]);
nuclear@0 835
nuclear@0 836 const char* s = (++splitter)->c_str();
nuclear@0 837 for(size_t i = 0; i < face.indices.size(); ++i) {
nuclear@0 838 if(!SkipSpaces(&s)) {
nuclear@0 839 ThrowException("Expected EOL token in Face entry");
nuclear@0 840 }
nuclear@0 841 if ('<' != *s++) {
nuclear@0 842 ThrowException("Expected < token in Face entry");
nuclear@0 843 }
nuclear@0 844 face.indices[i].pos_idx = strtoul10(s,&s);
nuclear@0 845 if (',' != *s++) {
nuclear@0 846 ThrowException("Expected , token in Face entry");
nuclear@0 847 }
nuclear@0 848 face.indices[i].uv_idx = strtoul10(s,&s);
nuclear@0 849 if ('>' != *s++) {
nuclear@0 850 ThrowException("Expected < token in Face entry");
nuclear@0 851 }
nuclear@0 852 }
nuclear@0 853 }
nuclear@0 854 if (nfo.version <= 4) {
nuclear@0 855 break;
nuclear@0 856 }
nuclear@0 857 }
nuclear@0 858 else if (splitter.match_start("DrawFlags")) {
nuclear@0 859 msh.draw_flags = strtoul10(splitter[1]);
nuclear@0 860 break;
nuclear@0 861 }
nuclear@0 862 }
nuclear@0 863 }
nuclear@0 864
nuclear@0 865 // ------------------------------------------------------------------------------------------------
nuclear@0 866 void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo)
nuclear@0 867 {
nuclear@0 868 if(nfo.version > 1) {
nuclear@0 869 return UnsupportedChunk_Ascii(splitter,nfo,"BitM");
nuclear@0 870 }
nuclear@0 871 /*
nuclear@0 872 "\nThumbNailHdrSize %ld"
nuclear@0 873 "\nThumbHeader: %02hx 02hx %02hx "
nuclear@0 874 "\nColorBufSize %ld"
nuclear@0 875 "\nColorBufZipSize %ld"
nuclear@0 876 "\nZippedThumbnail: %02hx 02hx %02hx "
nuclear@0 877 */
nuclear@0 878
nuclear@0 879 const unsigned int head = strtoul10((++splitter)[1]);
nuclear@0 880 if (head != sizeof(Bitmap::BitmapHeader)) {
nuclear@0 881 LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk");
nuclear@0 882 return;
nuclear@0 883 }
nuclear@0 884
nuclear@0 885 /*union {
nuclear@0 886 Bitmap::BitmapHeader data;
nuclear@0 887 char opaq[sizeof Bitmap::BitmapHeader()];
nuclear@0 888 };*/
nuclear@0 889 // ReadHexOctets(opaq,head,(++splitter)[1]);
nuclear@0 890 }
nuclear@0 891
nuclear@0 892 // ------------------------------------------------------------------------------------------------
nuclear@0 893 void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader)
nuclear@0 894 {
nuclear@0 895 out.resize( reader.GetI2());
nuclear@0 896 for_each(char& c,out) {
nuclear@0 897 c = reader.GetI1();
nuclear@0 898 }
nuclear@0 899 }
nuclear@0 900
nuclear@0 901 // ------------------------------------------------------------------------------------------------
nuclear@0 902 void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/)
nuclear@0 903 {
nuclear@0 904 const unsigned int dupes = reader.GetI2();
nuclear@0 905 ReadString_Binary(msh.name,reader);
nuclear@0 906
nuclear@0 907 msh.name = format(msh.name)<<'_'<<dupes;
nuclear@0 908
nuclear@0 909 // skip local axes for the moment
nuclear@0 910 reader.IncPtr(48);
nuclear@0 911
nuclear@0 912 msh.transform = aiMatrix4x4();
nuclear@0 913 for(unsigned int y = 0; y < 3; ++y) {
nuclear@0 914 for(unsigned int x =0; x < 4; ++x) {
nuclear@0 915 msh.transform[y][x] = reader.GetF4();
nuclear@0 916 }
nuclear@0 917 }
nuclear@0 918 }
nuclear@0 919
nuclear@0 920 // ------------------------------------------------------------------------------------------------
nuclear@0 921 void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkInfo& nfo, const char* name)
nuclear@0 922 {
nuclear@0 923 const std::string error = format("Encountered unsupported chunk: ") << name <<
nuclear@0 924 " [version: "<<nfo.version<<", size: "<<nfo.size<<"]";
nuclear@0 925
nuclear@0 926 // we can recover if the chunk size was specified.
nuclear@0 927 if(nfo.size != static_cast<unsigned int>(-1)) {
nuclear@0 928 DefaultLogger::get()->error(error);
nuclear@0 929 reader.IncPtr(nfo.size);
nuclear@0 930 }
nuclear@0 931 else ThrowException(error);
nuclear@0 932 }
nuclear@0 933
nuclear@0 934 // ------------------------------------------------------------------------------------------------
nuclear@0 935 // tiny utility guard to aid me at staying within chunk boundaries.
nuclear@0 936 class chunk_guard {
nuclear@0 937
nuclear@0 938 public:
nuclear@0 939
nuclear@0 940 chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader)
nuclear@0 941 : nfo(nfo)
nuclear@0 942 , reader(reader)
nuclear@0 943 , cur(reader.GetCurrentPos())
nuclear@0 944 {
nuclear@0 945 }
nuclear@0 946
nuclear@0 947 ~chunk_guard() {
nuclear@0 948 // don't do anything if the size is not given
nuclear@0 949 if(nfo.size != static_cast<unsigned int>(-1)) {
nuclear@0 950 reader.IncPtr(static_cast<int>(nfo.size)-reader.GetCurrentPos()+cur);
nuclear@0 951 }
nuclear@0 952 }
nuclear@0 953
nuclear@0 954 private:
nuclear@0 955
nuclear@0 956 const COB::ChunkInfo& nfo;
nuclear@0 957 StreamReaderLE& reader;
nuclear@0 958 long cur;
nuclear@0 959 };
nuclear@0 960
nuclear@0 961 // ------------------------------------------------------------------------------------------------
nuclear@0 962 void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader)
nuclear@0 963 {
nuclear@0 964 while(1) {
nuclear@0 965 std::string type;
nuclear@0 966 type += reader -> GetI1()
nuclear@0 967 ,type += reader -> GetI1()
nuclear@0 968 ,type += reader -> GetI1()
nuclear@0 969 ,type += reader -> GetI1()
nuclear@0 970 ;
nuclear@0 971
nuclear@0 972 ChunkInfo nfo;
nuclear@0 973 nfo.version = reader -> GetI2()*10;
nuclear@0 974 nfo.version += reader -> GetI2();
nuclear@0 975
nuclear@0 976 nfo.id = reader->GetI4();
nuclear@0 977 nfo.parent_id = reader->GetI4();
nuclear@0 978 nfo.size = reader->GetI4();
nuclear@0 979
nuclear@0 980 if (type == "PolH") {
nuclear@0 981 ReadPolH_Binary(out,*reader,nfo);
nuclear@0 982 }
nuclear@0 983 else if (type == "BitM") {
nuclear@0 984 ReadBitM_Binary(out,*reader,nfo);
nuclear@0 985 }
nuclear@0 986 else if (type == "Grou") {
nuclear@0 987 ReadGrou_Binary(out,*reader,nfo);
nuclear@0 988 }
nuclear@0 989 else if (type == "Lght") {
nuclear@0 990 ReadLght_Binary(out,*reader,nfo);
nuclear@0 991 }
nuclear@0 992 else if (type == "Came") {
nuclear@0 993 ReadCame_Binary(out,*reader,nfo);
nuclear@0 994 }
nuclear@0 995 else if (type == "Mat1") {
nuclear@0 996 ReadMat1_Binary(out,*reader,nfo);
nuclear@0 997 }
nuclear@0 998 /* else if (type == "Bone") {
nuclear@0 999 ReadBone_Binary(out,*reader,nfo);
nuclear@0 1000 }
nuclear@0 1001 else if (type == "Chan") {
nuclear@0 1002 ReadChan_Binary(out,*reader,nfo);
nuclear@0 1003 }*/
nuclear@0 1004 else if (type == "Unit") {
nuclear@0 1005 ReadUnit_Binary(out,*reader,nfo);
nuclear@0 1006 }
nuclear@0 1007 else if (type == "OLay") {
nuclear@0 1008 // ignore layer index silently.
nuclear@0 1009 if(nfo.size != static_cast<unsigned int>(-1) ) {
nuclear@0 1010 reader->IncPtr(nfo.size);
nuclear@0 1011 }
nuclear@0 1012 else return UnsupportedChunk_Binary(*reader,nfo,type.c_str());
nuclear@0 1013 }
nuclear@0 1014 else if (type == "END ") {
nuclear@0 1015 return;
nuclear@0 1016 }
nuclear@0 1017 else UnsupportedChunk_Binary(*reader,nfo,type.c_str());
nuclear@0 1018 }
nuclear@0 1019 }
nuclear@0 1020
nuclear@0 1021 // ------------------------------------------------------------------------------------------------
nuclear@0 1022 void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1023 {
nuclear@0 1024 if(nfo.version > 8) {
nuclear@0 1025 return UnsupportedChunk_Binary(reader,nfo,"PolH");
nuclear@0 1026 }
nuclear@0 1027 const chunk_guard cn(nfo,reader);
nuclear@0 1028
nuclear@0 1029 out.nodes.push_back(boost::shared_ptr<Mesh>(new Mesh()));
nuclear@0 1030 Mesh& msh = (Mesh&)(*out.nodes.back().get());
nuclear@0 1031 msh = nfo;
nuclear@0 1032
nuclear@0 1033 ReadBasicNodeInfo_Binary(msh,reader,nfo);
nuclear@0 1034
nuclear@0 1035 msh.vertex_positions.resize(reader.GetI4());
nuclear@0 1036 for_each(aiVector3D& v,msh.vertex_positions) {
nuclear@0 1037 v.x = reader.GetF4();
nuclear@0 1038 v.y = reader.GetF4();
nuclear@0 1039 v.z = reader.GetF4();
nuclear@0 1040 }
nuclear@0 1041
nuclear@0 1042 msh.texture_coords.resize(reader.GetI4());
nuclear@0 1043 for_each(aiVector2D& v,msh.texture_coords) {
nuclear@0 1044 v.x = reader.GetF4();
nuclear@0 1045 v.y = reader.GetF4();
nuclear@0 1046 }
nuclear@0 1047
nuclear@0 1048 const size_t numf = reader.GetI4();
nuclear@0 1049 msh.faces.reserve(numf);
nuclear@0 1050 for(size_t i = 0; i < numf; ++i) {
nuclear@0 1051 // XXX backface culling flag is 0x10 in flags
nuclear@0 1052
nuclear@0 1053 // hole?
nuclear@0 1054 bool hole;
nuclear@0 1055 if ((hole = (reader.GetI1() & 0x08) != 0)) {
nuclear@0 1056 // XXX Basically this should just work fine - then triangulator
nuclear@0 1057 // should output properly triangulated data even for polygons
nuclear@0 1058 // with holes. Test data specific to COB is needed to confirm it.
nuclear@0 1059 if (msh.faces.empty()) {
nuclear@0 1060 ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id);
nuclear@0 1061 }
nuclear@0 1062 }
nuclear@0 1063 else msh.faces.push_back(Face());
nuclear@0 1064 Face& f = msh.faces.back();
nuclear@0 1065
nuclear@0 1066 const size_t num = reader.GetI2();
nuclear@0 1067 f.indices.reserve(f.indices.size() + num);
nuclear@0 1068
nuclear@0 1069 if(!hole) {
nuclear@0 1070 f.material = reader.GetI2();
nuclear@0 1071 f.flags = 0;
nuclear@0 1072 }
nuclear@0 1073
nuclear@0 1074 for(size_t x = 0; x < num; ++x) {
nuclear@0 1075 f.indices.push_back(VertexIndex());
nuclear@0 1076
nuclear@0 1077 VertexIndex& v = f.indices.back();
nuclear@0 1078 v.pos_idx = reader.GetI4();
nuclear@0 1079 v.uv_idx = reader.GetI4();
nuclear@0 1080 }
nuclear@0 1081
nuclear@0 1082 if(hole) {
nuclear@0 1083 std::reverse(f.indices.rbegin(),f.indices.rbegin()+num);
nuclear@0 1084 }
nuclear@0 1085 }
nuclear@0 1086 if (nfo.version>4) {
nuclear@0 1087 msh.draw_flags = reader.GetI4();
nuclear@0 1088 }
nuclear@0 1089 nfo.version>5 && nfo.version<8 ? reader.GetI4() : 0;
nuclear@0 1090 }
nuclear@0 1091
nuclear@0 1092 // ------------------------------------------------------------------------------------------------
nuclear@0 1093 void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1094 {
nuclear@0 1095 if(nfo.version > 1) {
nuclear@0 1096 return UnsupportedChunk_Binary(reader,nfo,"BitM");
nuclear@0 1097 }
nuclear@0 1098
nuclear@0 1099 const chunk_guard cn(nfo,reader);
nuclear@0 1100
nuclear@0 1101 const uint32_t len = reader.GetI4();
nuclear@0 1102 reader.IncPtr(len);
nuclear@0 1103
nuclear@0 1104 reader.GetI4();
nuclear@0 1105 reader.IncPtr(reader.GetI4());
nuclear@0 1106 }
nuclear@0 1107
nuclear@0 1108 // ------------------------------------------------------------------------------------------------
nuclear@0 1109 void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1110 {
nuclear@0 1111 if(nfo.version > 8) {
nuclear@0 1112 return UnsupportedChunk_Binary(reader,nfo,"Mat1");
nuclear@0 1113 }
nuclear@0 1114
nuclear@0 1115 const chunk_guard cn(nfo,reader);
nuclear@0 1116
nuclear@0 1117 out.materials.push_back(Material());
nuclear@0 1118 Material& mat = out.materials.back();
nuclear@0 1119 mat = nfo;
nuclear@0 1120
nuclear@0 1121 mat.matnum = reader.GetI2();
nuclear@0 1122 switch(reader.GetI1()) {
nuclear@0 1123 case 'f':
nuclear@0 1124 mat.type = Material::FLAT;
nuclear@0 1125 break;
nuclear@0 1126 case 'p':
nuclear@0 1127 mat.type = Material::PHONG;
nuclear@0 1128 break;
nuclear@0 1129 case 'm':
nuclear@0 1130 mat.type = Material::METAL;
nuclear@0 1131 break;
nuclear@0 1132 default:
nuclear@0 1133 LogError_Ascii(format("Unrecognized shader type in `Mat1` chunk with id ")<<nfo.id);
nuclear@0 1134 mat.type = Material::FLAT;
nuclear@0 1135 }
nuclear@0 1136
nuclear@0 1137 switch(reader.GetI1()) {
nuclear@0 1138 case 'f':
nuclear@0 1139 mat.autofacet = Material::FACETED;
nuclear@0 1140 break;
nuclear@0 1141 case 'a':
nuclear@0 1142 mat.autofacet = Material::AUTOFACETED;
nuclear@0 1143 break;
nuclear@0 1144 case 's':
nuclear@0 1145 mat.autofacet = Material::SMOOTH;
nuclear@0 1146 break;
nuclear@0 1147 default:
nuclear@0 1148 LogError_Ascii(format("Unrecognized faceting mode in `Mat1` chunk with id ")<<nfo.id);
nuclear@0 1149 mat.autofacet = Material::FACETED;
nuclear@0 1150 }
nuclear@0 1151 mat.autofacet_angle = static_cast<float>(reader.GetI1());
nuclear@0 1152
nuclear@0 1153 mat.rgb.r = reader.GetF4();
nuclear@0 1154 mat.rgb.g = reader.GetF4();
nuclear@0 1155 mat.rgb.b = reader.GetF4();
nuclear@0 1156
nuclear@0 1157 mat.alpha = reader.GetF4();
nuclear@0 1158 mat.ka = reader.GetF4();
nuclear@0 1159 mat.ks = reader.GetF4();
nuclear@0 1160 mat.exp = reader.GetF4();
nuclear@0 1161 mat.ior = reader.GetF4();
nuclear@0 1162
nuclear@0 1163 char id[2];
nuclear@0 1164 id[0] = reader.GetI1(),id[1] = reader.GetI1();
nuclear@0 1165
nuclear@0 1166 if (id[0] == 'e' && id[1] == ':') {
nuclear@0 1167 mat.tex_env.reset(new Texture());
nuclear@0 1168
nuclear@0 1169 reader.GetI1();
nuclear@0 1170 ReadString_Binary(mat.tex_env->path,reader);
nuclear@0 1171
nuclear@0 1172 // advance to next texture-id
nuclear@0 1173 id[0] = reader.GetI1(),id[1] = reader.GetI1();
nuclear@0 1174 }
nuclear@0 1175
nuclear@0 1176 if (id[0] == 't' && id[1] == ':') {
nuclear@0 1177 mat.tex_color.reset(new Texture());
nuclear@0 1178
nuclear@0 1179 reader.GetI1();
nuclear@0 1180 ReadString_Binary(mat.tex_color->path,reader);
nuclear@0 1181
nuclear@0 1182 mat.tex_color->transform.mTranslation.x = reader.GetF4();
nuclear@0 1183 mat.tex_color->transform.mTranslation.y = reader.GetF4();
nuclear@0 1184
nuclear@0 1185 mat.tex_color->transform.mScaling.x = reader.GetF4();
nuclear@0 1186 mat.tex_color->transform.mScaling.y = reader.GetF4();
nuclear@0 1187
nuclear@0 1188 // advance to next texture-id
nuclear@0 1189 id[0] = reader.GetI1(),id[1] = reader.GetI1();
nuclear@0 1190 }
nuclear@0 1191
nuclear@0 1192 if (id[0] == 'b' && id[1] == ':') {
nuclear@0 1193 mat.tex_bump.reset(new Texture());
nuclear@0 1194
nuclear@0 1195 reader.GetI1();
nuclear@0 1196 ReadString_Binary(mat.tex_bump->path,reader);
nuclear@0 1197
nuclear@0 1198 mat.tex_bump->transform.mTranslation.x = reader.GetF4();
nuclear@0 1199 mat.tex_bump->transform.mTranslation.y = reader.GetF4();
nuclear@0 1200
nuclear@0 1201 mat.tex_bump->transform.mScaling.x = reader.GetF4();
nuclear@0 1202 mat.tex_bump->transform.mScaling.y = reader.GetF4();
nuclear@0 1203
nuclear@0 1204 // skip amplitude for I don't know its purpose.
nuclear@0 1205 reader.GetF4();
nuclear@0 1206 }
nuclear@0 1207 reader.IncPtr(-2);
nuclear@0 1208 }
nuclear@0 1209
nuclear@0 1210 // ------------------------------------------------------------------------------------------------
nuclear@0 1211 void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1212 {
nuclear@0 1213 if(nfo.version > 2) {
nuclear@0 1214 return UnsupportedChunk_Binary(reader,nfo,"Came");
nuclear@0 1215 }
nuclear@0 1216
nuclear@0 1217 const chunk_guard cn(nfo,reader);
nuclear@0 1218
nuclear@0 1219 out.nodes.push_back(boost::shared_ptr<Camera>(new Camera()));
nuclear@0 1220 Camera& msh = (Camera&)(*out.nodes.back().get());
nuclear@0 1221 msh = nfo;
nuclear@0 1222
nuclear@0 1223 ReadBasicNodeInfo_Binary(msh,reader,nfo);
nuclear@0 1224
nuclear@0 1225 // the rest is not interesting for us, so we skip over it.
nuclear@0 1226 if(nfo.version > 1) {
nuclear@0 1227 if (reader.GetI2()==512) {
nuclear@0 1228 reader.IncPtr(42);
nuclear@0 1229 }
nuclear@0 1230 }
nuclear@0 1231 }
nuclear@0 1232
nuclear@0 1233 // ------------------------------------------------------------------------------------------------
nuclear@0 1234 void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1235 {
nuclear@0 1236 if(nfo.version > 2) {
nuclear@0 1237 return UnsupportedChunk_Binary(reader,nfo,"Lght");
nuclear@0 1238 }
nuclear@0 1239
nuclear@0 1240 const chunk_guard cn(nfo,reader);
nuclear@0 1241
nuclear@0 1242 out.nodes.push_back(boost::shared_ptr<Light>(new Light()));
nuclear@0 1243 Light& msh = (Light&)(*out.nodes.back().get());
nuclear@0 1244 msh = nfo;
nuclear@0 1245
nuclear@0 1246 ReadBasicNodeInfo_Binary(msh,reader,nfo);
nuclear@0 1247 }
nuclear@0 1248
nuclear@0 1249 // ------------------------------------------------------------------------------------------------
nuclear@0 1250 void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1251 {
nuclear@0 1252 if(nfo.version > 2) {
nuclear@0 1253 return UnsupportedChunk_Binary(reader,nfo,"Grou");
nuclear@0 1254 }
nuclear@0 1255
nuclear@0 1256 const chunk_guard cn(nfo,reader);
nuclear@0 1257
nuclear@0 1258 out.nodes.push_back(boost::shared_ptr<Group>(new Group()));
nuclear@0 1259 Group& msh = (Group&)(*out.nodes.back().get());
nuclear@0 1260 msh = nfo;
nuclear@0 1261
nuclear@0 1262 ReadBasicNodeInfo_Binary(msh,reader,nfo);
nuclear@0 1263 }
nuclear@0 1264
nuclear@0 1265 // ------------------------------------------------------------------------------------------------
nuclear@0 1266 void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo)
nuclear@0 1267 {
nuclear@0 1268 if(nfo.version > 1) {
nuclear@0 1269 return UnsupportedChunk_Binary(reader,nfo,"Unit");
nuclear@0 1270 }
nuclear@0 1271
nuclear@0 1272 const chunk_guard cn(nfo,reader);
nuclear@0 1273
nuclear@0 1274 // parent chunks preceede their childs, so we should have the
nuclear@0 1275 // corresponding chunk already.
nuclear@0 1276 for_each(boost::shared_ptr< Node >& nd, out.nodes) {
nuclear@0 1277 if (nd->id == nfo.parent_id) {
nuclear@0 1278 const unsigned int t=reader.GetI2();
nuclear@0 1279 nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
nuclear@0 1280 LogWarn_Ascii(format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id)
nuclear@0 1281 ,1.f):units[t];
nuclear@0 1282
nuclear@0 1283 return;
nuclear@0 1284 }
nuclear@0 1285 }
nuclear@0 1286 LogWarn_Ascii(format()<<"`Unit` chunk "<<nfo.id<<" is a child of "
nuclear@0 1287 <<nfo.parent_id<<" which does not exist");
nuclear@0 1288 }
nuclear@0 1289
nuclear@0 1290
nuclear@0 1291 #endif