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