COBLoader.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. Open Asset Import Library (ASSIMP)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2008, ASSIMP Development Team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the ASSIMP team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the ASSIMP Development Team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. /** @file COBLoader.cpp
  34. * @brief Implementation of the TrueSpace COB/SCN importer class.
  35. */
  36. #include "AssimpPCH.h"
  37. #ifndef AI_BUILD_NO_COB_IMPORTER
  38. #include "COBLoader.h"
  39. #include "COBScene.h"
  40. #include "StreamReader.h"
  41. #include "ParsingUtils.h"
  42. #include "fast_atof.h"
  43. #include "LineSplitter.h"
  44. #include "TinyFormatter.h"
  45. using namespace Assimp;
  46. using namespace Assimp::COB;
  47. using namespace Assimp::Formatter;
  48. #define for_each BOOST_FOREACH
  49. // ------------------------------------------------------------------------------------------------
  50. // Constructor to be privately used by Importer
  51. COBImporter::COBImporter()
  52. {}
  53. // ------------------------------------------------------------------------------------------------
  54. // Destructor, private as well
  55. COBImporter::~COBImporter()
  56. {}
  57. // ------------------------------------------------------------------------------------------------
  58. // Returns whether the class can handle the format of the given file.
  59. bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
  60. {
  61. const std::string& extension = GetExtension(pFile);
  62. if (extension == "cob" || extension == "scn") {
  63. return true;
  64. }
  65. else if (!extension.length() || checkSig) {
  66. if (!pIOHandler) {
  67. return true;
  68. }
  69. const char* tokens[] = {"Caligary"};
  70. return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
  71. }
  72. return false;
  73. }
  74. // ------------------------------------------------------------------------------------------------
  75. // List all extensions handled by this loader
  76. void COBImporter::GetExtensionList(std::set<std::string>& app)
  77. {
  78. app.insert("cob");
  79. app.insert("scn");
  80. }
  81. // ------------------------------------------------------------------------------------------------
  82. // Setup configuration properties for the loader
  83. void COBImporter::SetupProperties(const Importer* pImp)
  84. {
  85. // nothing to be done for the moment
  86. }
  87. // ------------------------------------------------------------------------------------------------
  88. /*static*/ void COBImporter::ThrowException(const std::string& msg)
  89. {
  90. throw DeadlyImportError("COB: "+msg);
  91. }
  92. // ------------------------------------------------------------------------------------------------
  93. // Imports the given file into the given scene structure.
  94. void COBImporter::InternReadFile( const std::string& pFile,
  95. aiScene* pScene, IOSystem* pIOHandler)
  96. {
  97. COB::Scene scene;
  98. boost::scoped_ptr<StreamReaderLE> stream(new StreamReaderLE(
  99. pIOHandler->Open(pFile,"rb")) );
  100. // check header
  101. char head[32];
  102. stream->CopyAndAdvance(head,32);
  103. if (strncmp(head,"Caligari ",9)) {
  104. ThrowException("Could not found magic id: `Caligari`");
  105. }
  106. DefaultLogger::get()->info("File format tag: "+std::string(head+9,6));
  107. void (COBImporter::* load)(Scene&,StreamReaderLE*)= head[15]=='A'?&COBImporter::ReadAsciiFile:&COBImporter::ReadBinaryFile;
  108. if (head[16]!='L') {
  109. ThrowException("File is big-endian, which is not supported");
  110. }
  111. // load data into intermediate structures
  112. (this->*load)(scene,stream.get());
  113. if(scene.nodes.empty()) {
  114. ThrowException("No nodes loaded");
  115. }
  116. // sort faces by material indices
  117. for_each(boost::shared_ptr< Node >& n,scene.nodes) {
  118. try {
  119. Mesh& mesh = dynamic_cast<Mesh&>(*n.get());
  120. for_each(Face& f,mesh.faces) {
  121. mesh.temp_map[f.material].push_back(&f);
  122. }
  123. } catch (std::bad_cast&) {}
  124. }
  125. // count meshes
  126. for_each(boost::shared_ptr< Node >& n,scene.nodes) {
  127. try {
  128. Mesh& mesh = dynamic_cast<Mesh&>(*n.get());
  129. if (mesh.vertex_positions.size() && mesh.texture_coords.size()) {
  130. pScene->mNumMeshes += mesh.temp_map.size();
  131. }
  132. } catch (std::bad_cast&) {}
  133. }
  134. pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
  135. pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes]();
  136. pScene->mNumMeshes = 0;
  137. // count lights and cameras
  138. for_each(boost::shared_ptr< Node >& n,scene.nodes) {
  139. if (n->type == Node::TYPE_LIGHT) {
  140. ++pScene->mNumLights;
  141. }
  142. else if (n->type == Node::TYPE_CAMERA) {
  143. ++pScene->mNumCameras;
  144. }
  145. }
  146. if (pScene->mNumLights) {
  147. pScene->mLights = new aiLight*[pScene->mNumLights]();
  148. }
  149. if (pScene->mNumCameras) {
  150. pScene->mCameras = new aiCamera*[pScene->mNumCameras]();
  151. }
  152. pScene->mNumLights = pScene->mNumCameras = 0;
  153. // resolve parents by their IDs and build the output graph
  154. boost::scoped_ptr<Node> root(new Group());
  155. for(size_t n = 0; n < scene.nodes.size(); ++n) {
  156. const Node& nn = *scene.nodes[n].get();
  157. if(nn.parent_id==0) {
  158. root->temp_children.push_back(&nn);
  159. }
  160. for(size_t m = n; m < scene.nodes.size(); ++m) {
  161. const Node& mm = *scene.nodes[m].get();
  162. if (mm.parent_id == nn.id) {
  163. nn.temp_children.push_back(&mm);
  164. }
  165. }
  166. }
  167. pScene->mRootNode = BuildNodes(*root.get(),scene,pScene);
  168. }
  169. // ------------------------------------------------------------------------------------------------
  170. aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill)
  171. {
  172. aiNode* nd = new aiNode();
  173. nd->mName.Set(root.name);
  174. nd->mTransformation = root.transform;
  175. // Note to everybody believing Voodoo is appropriate here:
  176. // I know polymorphism, run as fast as you can ;-)
  177. if (Node::TYPE_MESH == root.type) {
  178. const Mesh& ndmesh = dynamic_cast<const Mesh&>(root);
  179. if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
  180. typedef std::pair<unsigned int,Mesh::FaceRefList> Entry;
  181. for_each(const Entry& reflist,ndmesh.temp_map) {
  182. { // create mesh
  183. size_t n = 0;
  184. for_each(Face* f, reflist.second) {
  185. n += f->indices.size();
  186. }
  187. if (!n) {
  188. continue;
  189. }
  190. aiMesh* outmesh = fill->mMeshes[fill->mNumMeshes++] = new aiMesh();
  191. ++nd->mNumMeshes;
  192. outmesh->mVertices = new aiVector3D[n];
  193. outmesh->mTextureCoords[0] = new aiVector3D[n];
  194. outmesh->mFaces = new aiFace[reflist.second.size()]();
  195. for_each(Face* f, reflist.second) {
  196. if (f->indices.empty()) {
  197. continue;
  198. }
  199. aiFace& fout = outmesh->mFaces[outmesh->mNumFaces++];
  200. fout.mIndices = new unsigned int[f->indices.size()];
  201. for_each(VertexIndex& v, f->indices) {
  202. if (v.pos_idx >= ndmesh.vertex_positions.size()) {
  203. ThrowException("Position index out of range");
  204. }
  205. if (v.uv_idx >= ndmesh.texture_coords.size()) {
  206. ThrowException("UV index out of range");
  207. }
  208. outmesh->mVertices[outmesh->mNumVertices] = ndmesh.vertex_positions[ v.pos_idx ];
  209. outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D(
  210. ndmesh.texture_coords[ v.uv_idx ].x,
  211. ndmesh.texture_coords[ v.uv_idx ].y,
  212. 0.f
  213. );
  214. fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++;
  215. }
  216. }
  217. outmesh->mMaterialIndex = fill->mNumMaterials;
  218. }{ // create material
  219. const Material* min = NULL;
  220. for_each(const Material& m, scin.materials) {
  221. if (m.parent_id == ndmesh.id && m.matnum == reflist.first) {
  222. min = &m;
  223. break;
  224. }
  225. }
  226. boost::scoped_ptr<const Material> defmat;
  227. if(!min) {
  228. DefaultLogger::get()->debug(format()<<"Could not resolve material index "
  229. <<reflist.first<<" - creating default material for this slot");
  230. defmat.reset(min=new Material());
  231. }
  232. MaterialHelper* mat = new MaterialHelper();
  233. fill->mMaterials[fill->mNumMaterials++] = mat;
  234. aiString s;
  235. s.Set(min->type);
  236. mat->AddProperty(&s,AI_MATKEY_NAME);
  237. if(int tmp = ndmesh.draw_flags & Mesh::WIRED ? 1 : 0) {
  238. mat->AddProperty(&tmp,1,AI_MATKEY_ENABLE_WIREFRAME);
  239. }
  240. { int shader;
  241. switch(min->shader)
  242. {
  243. case Material::FLAT:
  244. shader = aiShadingMode_Gouraud;
  245. break;
  246. case Material::PHONG:
  247. shader = aiShadingMode_Phong;
  248. break;
  249. case Material::METAL:
  250. shader = aiShadingMode_CookTorrance;
  251. break;
  252. default:
  253. ai_assert(false); // shouldn't be here
  254. }
  255. mat->AddProperty(&shader,1,AI_MATKEY_SHADING_MODEL);
  256. if(shader != aiShadingMode_Gouraud) {
  257. mat->AddProperty(&min->exp,1,AI_MATKEY_SHININESS);
  258. }
  259. }
  260. mat->AddProperty(&min->ior,1,AI_MATKEY_REFRACTI);
  261. mat->AddProperty(&min->rgb,1,AI_MATKEY_COLOR_DIFFUSE);
  262. aiColor3D c = aiColor3D(min->rgb)*min->ks;
  263. mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
  264. c = aiColor3D(min->rgb)*min->ka;
  265. mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT);
  266. }
  267. }
  268. }
  269. }
  270. else if (Node::TYPE_LIGHT == root.type) {
  271. const Light& ndlight = dynamic_cast<const Light&>(root);
  272. }
  273. else if (Node::TYPE_CAMERA == root.type) {
  274. const Camera& ndcam = dynamic_cast<const Camera&>(root);
  275. }
  276. // add meshes
  277. if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0
  278. nd->mMeshes = new unsigned int[nd->mNumMeshes];
  279. for(unsigned int i = 0; i < nd->mNumMeshes;++i) {
  280. nd->mMeshes[i] = fill->mNumMeshes-i-1;
  281. }
  282. }
  283. // add children recursively
  284. nd->mChildren = new aiNode*[root.temp_children.size()]();
  285. for_each(const Node* n, root.temp_children) {
  286. (nd->mChildren[nd->mNumChildren++] = BuildNodes(*n,scin,fill))->mParent = nd;
  287. }
  288. return nd;
  289. }
  290. // ------------------------------------------------------------------------------------------------
  291. // Read an ASCII file into the given scene data structure
  292. void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream)
  293. {
  294. ChunkInfo ci;
  295. for(LineSplitter splitter(*stream);splitter;++splitter) {
  296. // add all chunks to be recognized here. /else ../ ommitted intentionally.
  297. if (splitter.match_start("PolH ")) {
  298. ReadChunkInfo_Ascii(ci,splitter);
  299. ReadPolH_Ascii(out,splitter,ci);
  300. }
  301. if (splitter.match_start("BitM ")) {
  302. ReadChunkInfo_Ascii(ci,splitter);
  303. ReadBitM_Ascii(out,splitter,ci);
  304. }
  305. if (splitter.match_start("Mat1 ")) {
  306. ReadChunkInfo_Ascii(ci,splitter);
  307. ReadMat1_Ascii(out,splitter,ci);
  308. }
  309. if (splitter.match_start("Grou ")) {
  310. ReadChunkInfo_Ascii(ci,splitter);
  311. ReadGrou_Ascii(out,splitter,ci);
  312. }
  313. if (splitter.match_start("Lght ")) {
  314. ReadChunkInfo_Ascii(ci,splitter);
  315. ReadLght_Ascii(out,splitter,ci);
  316. }
  317. if (splitter.match_start("Came ")) {
  318. ReadChunkInfo_Ascii(ci,splitter);
  319. ReadCame_Ascii(out,splitter,ci);
  320. }
  321. if (splitter.match_start("Bone ")) {
  322. ReadChunkInfo_Ascii(ci,splitter);
  323. ReadBone_Ascii(out,splitter,ci);
  324. }
  325. if (splitter.match_start("Chan ")) {
  326. ReadChunkInfo_Ascii(ci,splitter);
  327. ReadChan_Ascii(out,splitter,ci);
  328. }
  329. if (splitter.match_start("Unit ")) {
  330. ReadChunkInfo_Ascii(ci,splitter);
  331. ReadUnit_Ascii(out,splitter,ci);
  332. }
  333. if (splitter.match_start("END ")) {
  334. // we don't need this, but I guess there is a reason this
  335. // chunk has been implemented into COB for.
  336. return;
  337. }
  338. }
  339. }
  340. // ------------------------------------------------------------------------------------------------
  341. void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter)
  342. {
  343. const char* all_tokens[8];
  344. splitter.get_tokens(all_tokens);
  345. out.version = (all_tokens[1][1]-'0')*100+(all_tokens[1][3]-'0')*10+(all_tokens[1][4]-'0');
  346. out.id = strtol10(all_tokens[3]);
  347. out.parent_id = strtol10(all_tokens[5]);
  348. out.size = strtol10s(all_tokens[7]);
  349. }
  350. // ------------------------------------------------------------------------------------------------
  351. void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name)
  352. {
  353. std::string error = "Encountered unsupported chunk: "; error += name;
  354. // we can recover if the chunk size was specified.
  355. if(nfo.size) {
  356. DefaultLogger::get()->error(error);
  357. // (HACK) - our current position in the stream is the beginning of the
  358. // head line of the next chunk. That's fine, but the caller is going
  359. // to call ++ on `splitter`, which we need to swallow to avoid
  360. // missing the next line.
  361. splitter.get_stream().IncPtr(nfo.size);
  362. splitter.swallow_next_increment();
  363. }
  364. else ThrowException(error);
  365. }
  366. // ------------------------------------------------------------------------------------------------
  367. void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message) {
  368. LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]");
  369. }
  370. // ------------------------------------------------------------------------------------------------
  371. void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message) {
  372. LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]");
  373. }
  374. // ------------------------------------------------------------------------------------------------
  375. void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message) {
  376. LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]");
  377. }
  378. // ------------------------------------------------------------------------------------------------
  379. void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message) {
  380. LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]");
  381. }
  382. // ------------------------------------------------------------------------------------------------
  383. void COBImporter::LogWarn_Ascii(const std::string& message) {
  384. DefaultLogger::get()->warn("COB: "+message);
  385. }
  386. // ------------------------------------------------------------------------------------------------
  387. void COBImporter::LogError_Ascii(const std::string& message) {
  388. DefaultLogger::get()->error("COB: "+message);
  389. }
  390. // ------------------------------------------------------------------------------------------------
  391. void COBImporter::LogInfo_Ascii(const std::string& message) {
  392. DefaultLogger::get()->info("COB: "+message);
  393. }
  394. // ------------------------------------------------------------------------------------------------
  395. void COBImporter::LogDebug_Ascii(const std::string& message) {
  396. DefaultLogger::get()->debug("COB: "+message);
  397. }
  398. // ------------------------------------------------------------------------------------------------
  399. void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& nfo)
  400. {
  401. for(;splitter;++splitter) {
  402. if (splitter.match_start("Name")) {
  403. msh.name = std::string(splitter[1]);
  404. // make nice names by merging the dupe count
  405. std::replace(msh.name.begin(),msh.name.end(),
  406. ',','_');
  407. }
  408. else if (splitter.match_start("Transform")) {
  409. for(unsigned int y = 0; y < 4 && ++splitter; ++y) {
  410. const char* s = splitter->c_str();
  411. for(unsigned int x = 0; x < 4; ++x) {
  412. SkipSpaces(&s);
  413. msh.transform[y][x] = fast_atof(&s);
  414. }
  415. }
  416. // we need the transform chunk, so we won't return until we have it.
  417. return;
  418. }
  419. }
  420. }
  421. // ------------------------------------------------------------------------------------------------
  422. template <typename T>
  423. void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in)
  424. {
  425. const char* rgb = *in;
  426. for(unsigned int i = 0; i < 3; ++i) {
  427. SkipSpaces(&rgb);
  428. if (*rgb == ',')++rgb;
  429. SkipSpaces(&rgb);
  430. fill[i] = fast_atof(&rgb);
  431. }
  432. *in = rgb;
  433. }
  434. // ------------------------------------------------------------------------------------------------
  435. void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  436. {
  437. if(nfo.version > 8) {
  438. return UnsupportedChunk_Ascii(splitter,nfo,"Mat1");
  439. }
  440. ++splitter;
  441. if (!splitter.match_start("mat# ")) {
  442. LogWarn_Ascii(splitter,format()<<
  443. "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
  444. return;
  445. }
  446. out.materials.push_back(Material());
  447. Material& mat = out.materials.back();
  448. mat = nfo;
  449. mat.matnum = strtol10(splitter[1]);
  450. ++splitter;
  451. if (!splitter.match_start("shader: ")) {
  452. LogWarn_Ascii(splitter,format()<<
  453. "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
  454. return;
  455. }
  456. std::string shader = std::string(splitter[1]);
  457. shader = shader.substr(0,shader.find_first_of(" \t"));
  458. if (shader == "metal") {
  459. mat.shader = Material::METAL;
  460. }
  461. else if (shader == "phong") {
  462. mat.shader = Material::PHONG;
  463. }
  464. else if (shader != "flat") {
  465. LogWarn_Ascii(splitter,format()<<
  466. "Unknown value for `shader` in `Mat1` chunk "<<nfo.id);
  467. }
  468. ++splitter;
  469. if (!splitter.match_start("rgb ")) {
  470. LogWarn_Ascii(splitter,format()<<
  471. "Expected `rgb` line in `Mat1` chunk "<<nfo.id);
  472. }
  473. const char* rgb = splitter[1];
  474. ReadFloat3Tuple_Ascii(mat.rgb,&rgb);
  475. ++splitter;
  476. if (!splitter.match_start("alpha ")) {
  477. LogWarn_Ascii(splitter,format()<<
  478. "Expected `alpha` line in `Mat1` chunk "<<nfo.id);
  479. }
  480. const char* tokens[10];
  481. splitter.get_tokens(tokens);
  482. mat.alpha = fast_atof( tokens[1] );
  483. mat.ka = fast_atof( tokens[3] );
  484. mat.ks = fast_atof( tokens[5] );
  485. mat.exp = fast_atof( tokens[7] );
  486. mat.ior = fast_atof( tokens[9] );
  487. }
  488. // ------------------------------------------------------------------------------------------------
  489. void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  490. {
  491. if(nfo.version > 1) {
  492. return UnsupportedChunk_Ascii(splitter,nfo,"Unit");
  493. }
  494. ++splitter;
  495. if (!splitter.match_start("Units ")) {
  496. LogWarn_Ascii(splitter,format()<<
  497. "Expected `Units` line in `Unit` chunk "<<nfo.id);
  498. return;
  499. }
  500. // parent chunks preceede their childs, so we should have the
  501. // corresponding chunk already.
  502. for_each(boost::shared_ptr< Node >& nd, out.nodes) {
  503. if (nd->id == nfo.parent_id) {
  504. unsigned int t;
  505. static const float units[] = {1000.f,100.f,1.f,0.001f,
  506. 1.f/0.0254f,1.f/0.3048f,1.f/0.9144f,1.f/1609.344f
  507. };
  508. nd->unit_scale = (t=strtol10(splitter[1]))>=sizeof(units)/sizeof(units[0])?(
  509. LogWarn_Ascii(splitter,format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id)
  510. ,1.f):units[t];
  511. return;
  512. }
  513. }
  514. LogWarn_Ascii(splitter,format()<<"`Unit` chunk "<<nfo.id<<" is a child of "
  515. <<nfo.parent_id<<" which does not exist");
  516. }
  517. // ------------------------------------------------------------------------------------------------
  518. void COBImporter::ReadChan_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  519. {
  520. if(nfo.version > 8) {
  521. return UnsupportedChunk_Ascii(splitter,nfo,"Chan");
  522. }
  523. }
  524. // ------------------------------------------------------------------------------------------------
  525. void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  526. {
  527. if(nfo.version > 8) {
  528. return UnsupportedChunk_Ascii(splitter,nfo,"Lght");
  529. }
  530. out.nodes.push_back(boost::shared_ptr<Light>(new Light()));
  531. Light& msh = *dynamic_cast<Light*>(out.nodes.back().get());
  532. msh = nfo;
  533. ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
  534. if (splitter.match_start("Infinite ")) {
  535. msh.ltype = Light::INFINITE;
  536. }
  537. else if (splitter.match_start("Local ")) {
  538. msh.ltype = Light::LOCAL;
  539. }
  540. else if (splitter.match_start("Spot ")) {
  541. msh.ltype = Light::SPOT;
  542. }
  543. else {
  544. LogWarn_Ascii(splitter,format()<<
  545. "Unknown kind of light source in `Lght` chunk "<<nfo.id<<" : "<<*splitter);
  546. msh.ltype = Light::SPOT;
  547. }
  548. ++splitter;
  549. if (!splitter.match_start("color ")) {
  550. LogWarn_Ascii(splitter,format()<<
  551. "Expected `color` line in `Lght` chunk "<<nfo.id);
  552. }
  553. const char* rgb = splitter[1];
  554. ReadFloat3Tuple_Ascii(msh.color ,&rgb);
  555. SkipSpaces(&rgb);
  556. if (strncmp(rgb,"cone angle",10)) {
  557. LogWarn_Ascii(splitter,format()<<
  558. "Expected `cone angle` entity in `color` line in `Lght` chunk "<<nfo.id);
  559. }
  560. SkipSpaces(rgb+10,&rgb);
  561. msh.angle = fast_atof(&rgb);
  562. SkipSpaces(&rgb);
  563. if (strncmp(rgb,"inner angle",11)) {
  564. LogWarn_Ascii(splitter,format()<<
  565. "Expected `inner angle` entity in `color` line in `Lght` chunk "<<nfo.id);
  566. }
  567. SkipSpaces(rgb+11,&rgb);
  568. msh.inner_angle = fast_atof(&rgb);
  569. // skip the rest for we can't handle this kind of physically-based lighting information.
  570. }
  571. // ------------------------------------------------------------------------------------------------
  572. void COBImporter::ReadCame_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  573. {
  574. if(nfo.version > 2) {
  575. return UnsupportedChunk_Ascii(splitter,nfo,"Came");
  576. }
  577. out.nodes.push_back(boost::shared_ptr<Camera>(new Camera()));
  578. Camera& msh = *dynamic_cast<Camera*>(out.nodes.back().get());
  579. msh = nfo;
  580. ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
  581. // skip the next line, we don't know this differenciation between a
  582. // standard camera and a panoramic camera.
  583. ++splitter;
  584. }
  585. // ------------------------------------------------------------------------------------------------
  586. void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  587. {
  588. if(nfo.version > 5) {
  589. return UnsupportedChunk_Ascii(splitter,nfo,"Bone");
  590. }
  591. out.nodes.push_back(boost::shared_ptr<Bone>(new Bone()));
  592. Bone& msh = *dynamic_cast<Bone*>(out.nodes.back().get());
  593. msh = nfo;
  594. ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
  595. // TODO
  596. }
  597. // ------------------------------------------------------------------------------------------------
  598. void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  599. {
  600. if(nfo.version > 1) {
  601. return UnsupportedChunk_Ascii(splitter,nfo,"Grou");
  602. }
  603. out.nodes.push_back(boost::shared_ptr<Group>(new Group()));
  604. Group& msh = *dynamic_cast<Group*>(out.nodes.back().get());
  605. msh = nfo;
  606. ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
  607. }
  608. // ------------------------------------------------------------------------------------------------
  609. void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  610. {
  611. if(nfo.version > 8) {
  612. return UnsupportedChunk_Ascii(splitter,nfo,"PolH");
  613. }
  614. out.nodes.push_back(boost::shared_ptr<Mesh>(new Mesh()));
  615. Mesh& msh = *dynamic_cast<Mesh*>(out.nodes.back().get());
  616. msh = nfo;
  617. ReadBasicNodeInfo_Ascii(msh,++splitter,nfo);
  618. // the chunk has a fixed order of components, but some are not interesting of us so
  619. // we're just looking for keywords in arbitrary order. The end of the chunk is
  620. // either the last `Face` or the `DrawFlags` attribute, depending on the format ver.
  621. for(;splitter;++splitter) {
  622. if (splitter.match_start("World Vertices")) {
  623. const unsigned int cnt = strtol10(splitter[2]);
  624. msh.vertex_positions.resize(cnt);
  625. for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) {
  626. const char* s = splitter->c_str();
  627. aiVector3D& v = msh.vertex_positions[cur];
  628. SkipSpaces(&s);
  629. v.x = fast_atof(&s);
  630. SkipSpaces(&s);
  631. v.y = fast_atof(&s);
  632. SkipSpaces(&s);
  633. v.z = fast_atof(&s);
  634. }
  635. }
  636. else if (splitter.match_start("Texture Vertices")) {
  637. const unsigned int cnt = strtol10(splitter[2]);
  638. msh.texture_coords.resize(cnt);
  639. for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) {
  640. const char* s = splitter->c_str();
  641. aiVector2D& v = msh.texture_coords[cur];
  642. SkipSpaces(&s);
  643. v.x = fast_atof(&s);
  644. SkipSpaces(&s);
  645. v.y = fast_atof(&s);
  646. }
  647. }
  648. else if (splitter.match_start("Faces")) {
  649. const unsigned int cnt = strtol10(splitter[1]);
  650. msh.faces.reserve(cnt);
  651. for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) {
  652. if (splitter.match_start("Hole")) {
  653. LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line");
  654. continue;
  655. }
  656. if (!splitter.match_start("Face")) {
  657. ThrowException("Expected Face line");
  658. }
  659. std::back_inserter(msh.faces) = Face();
  660. Face& face = msh.faces.back();
  661. face.indices.resize(strtol10(splitter[2]));
  662. face.flags = strtol10(splitter[4]);
  663. face.material = strtol10(splitter[6]);
  664. const char* s = (++splitter)->c_str();
  665. for(size_t i = 0; i < face.indices.size(); ++i) {
  666. if(!SkipSpaces(&s)) {
  667. ThrowException("Expected EOL token in Face entry");
  668. }
  669. if ('<' != *s++) {
  670. ThrowException("Expected < token in Face entry");
  671. }
  672. face.indices[i].pos_idx = strtol10(s,&s);
  673. if (',' != *s++) {
  674. ThrowException("Expected , token in Face entry");
  675. }
  676. face.indices[i].uv_idx = strtol10(s,&s);
  677. if ('>' != *s++) {
  678. ThrowException("Expected < token in Face entry");
  679. }
  680. }
  681. }
  682. if (nfo.version <= 4) {
  683. break;
  684. }
  685. }
  686. else if (splitter.match_start("DrawFlags")) {
  687. msh.draw_flags = strtol10(splitter[1]);
  688. break;
  689. }
  690. }
  691. }
  692. // ------------------------------------------------------------------------------------------------
  693. void COBImporter::ReadBitM_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo)
  694. {
  695. if(nfo.version > 1) {
  696. return UnsupportedChunk_Ascii(splitter,nfo,"BitM");
  697. }
  698. /*
  699. "\nThumbNailHdrSize %ld"
  700. "\nThumbHeader: %02hx 02hx %02hx "
  701. "\nColorBufSize %ld"
  702. "\nColorBufZipSize %ld"
  703. "\nZippedThumbnail: %02hx 02hx %02hx "
  704. */
  705. const unsigned int head = strtol10((++splitter)[1]);
  706. if (head != sizeof(Bitmap::BitmapHeader)) {
  707. LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk");
  708. return;
  709. }
  710. //union {
  711. // Bitmap::BitmapHeader data;
  712. // char opaq[sizeof Bitmap::BitmapHeader];
  713. //};
  714. // ReadHexOctets(opaq,head,(++splitter)[1]);
  715. }
  716. // ------------------------------------------------------------------------------------------------
  717. void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* stream)
  718. {
  719. }
  720. // ------------------------------------------------------------------------------------------------
  721. void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader)
  722. {
  723. }
  724. // ------------------------------------------------------------------------------------------------
  725. void COBImporter::ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader)
  726. {
  727. }
  728. // ------------------------------------------------------------------------------------------------
  729. void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader)
  730. {
  731. }
  732. // ------------------------------------------------------------------------------------------------
  733. void COBImporter::ReadBone_Binary(COB::Scene& out, StreamReaderLE& reader)
  734. {
  735. }
  736. // ------------------------------------------------------------------------------------------------
  737. void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader)
  738. {
  739. }
  740. // ------------------------------------------------------------------------------------------------
  741. void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader)
  742. {
  743. }
  744. // ------------------------------------------------------------------------------------------------
  745. void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader)
  746. {
  747. }
  748. #endif