nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file COBLoader.cpp nuclear@0: * @brief Implementation of the TrueSpace COB/SCN importer class. nuclear@0: */ nuclear@0: #include "AssimpPCH.h" nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_NO_COB_IMPORTER nuclear@0: #include "COBLoader.h" nuclear@0: #include "COBScene.h" nuclear@0: nuclear@0: #include "StreamReader.h" nuclear@0: #include "ParsingUtils.h" nuclear@0: #include "fast_atof.h" nuclear@0: nuclear@0: #include "LineSplitter.h" nuclear@0: #include "TinyFormatter.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: using namespace Assimp::COB; nuclear@0: using namespace Assimp::Formatter; nuclear@0: nuclear@0: #define for_each BOOST_FOREACH nuclear@0: nuclear@0: nuclear@0: static const float units[] = { nuclear@0: 1000.f, nuclear@0: 100.f, nuclear@0: 1.f, nuclear@0: 0.001f, nuclear@0: 1.f/0.0254f, nuclear@0: 1.f/0.3048f, nuclear@0: 1.f/0.9144f, nuclear@0: 1.f/1609.344f nuclear@0: }; nuclear@0: nuclear@0: static const aiImporterDesc desc = { nuclear@0: "TrueSpace Object Importer", nuclear@0: "", nuclear@0: "", nuclear@0: "little-endian files only", nuclear@0: aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: 0, nuclear@0: "cob scn" nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Constructor to be privately used by Importer nuclear@0: COBImporter::COBImporter() nuclear@0: {} nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Destructor, private as well nuclear@0: COBImporter::~COBImporter() nuclear@0: {} nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the class can handle the format of the given file. nuclear@0: bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const nuclear@0: { nuclear@0: const std::string& extension = GetExtension(pFile); nuclear@0: if (extension == "cob" || extension == "scn") { nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: else if ((!extension.length() || checkSig) && pIOHandler) { nuclear@0: const char* tokens[] = {"Caligary"}; nuclear@0: return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); nuclear@0: } nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Loader meta information nuclear@0: const aiImporterDesc* COBImporter::GetInfo () const nuclear@0: { nuclear@0: return &desc; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Setup configuration properties for the loader nuclear@0: void COBImporter::SetupProperties(const Importer* /*pImp*/) nuclear@0: { nuclear@0: // nothing to be done for the moment nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: /*static*/ void COBImporter::ThrowException(const std::string& msg) nuclear@0: { nuclear@0: throw DeadlyImportError("COB: "+msg); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Imports the given file into the given scene structure. nuclear@0: void COBImporter::InternReadFile( const std::string& pFile, nuclear@0: aiScene* pScene, IOSystem* pIOHandler) nuclear@0: { nuclear@0: COB::Scene scene; nuclear@0: boost::scoped_ptr stream(new StreamReaderLE( pIOHandler->Open(pFile,"rb")) ); nuclear@0: nuclear@0: // check header nuclear@0: char head[32]; nuclear@0: stream->CopyAndAdvance(head,32); nuclear@0: if (strncmp(head,"Caligari ",9)) { nuclear@0: ThrowException("Could not found magic id: `Caligari`"); nuclear@0: } nuclear@0: nuclear@0: DefaultLogger::get()->info("File format tag: "+std::string(head+9,6)); nuclear@0: void (COBImporter::* load)(Scene&,StreamReaderLE*)= head[15]=='A'?&COBImporter::ReadAsciiFile:&COBImporter::ReadBinaryFile; nuclear@0: if (head[16]!='L') { nuclear@0: ThrowException("File is big-endian, which is not supported"); nuclear@0: } nuclear@0: nuclear@0: // load data into intermediate structures nuclear@0: (this->*load)(scene,stream.get()); nuclear@0: if(scene.nodes.empty()) { nuclear@0: ThrowException("No nodes loaded"); nuclear@0: } nuclear@0: nuclear@0: // sort faces by material indices nuclear@0: for_each(boost::shared_ptr< Node >& n,scene.nodes) { nuclear@0: if (n->type == Node::TYPE_MESH) { nuclear@0: Mesh& mesh = (Mesh&)(*n.get()); nuclear@0: for_each(Face& f,mesh.faces) { nuclear@0: mesh.temp_map[f.material].push_back(&f); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // count meshes nuclear@0: for_each(boost::shared_ptr< Node >& n,scene.nodes) { nuclear@0: if (n->type == Node::TYPE_MESH) { nuclear@0: Mesh& mesh = (Mesh&)(*n.get()); nuclear@0: if (mesh.vertex_positions.size() && mesh.texture_coords.size()) { nuclear@0: pScene->mNumMeshes += mesh.temp_map.size(); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: pScene->mMeshes = new aiMesh*[pScene->mNumMeshes](); nuclear@0: pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes](); nuclear@0: pScene->mNumMeshes = 0; nuclear@0: nuclear@0: // count lights and cameras nuclear@0: for_each(boost::shared_ptr< Node >& n,scene.nodes) { nuclear@0: if (n->type == Node::TYPE_LIGHT) { nuclear@0: ++pScene->mNumLights; nuclear@0: } nuclear@0: else if (n->type == Node::TYPE_CAMERA) { nuclear@0: ++pScene->mNumCameras; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (pScene->mNumLights) { nuclear@0: pScene->mLights = new aiLight*[pScene->mNumLights](); nuclear@0: } nuclear@0: if (pScene->mNumCameras) { nuclear@0: pScene->mCameras = new aiCamera*[pScene->mNumCameras](); nuclear@0: } nuclear@0: pScene->mNumLights = pScene->mNumCameras = 0; nuclear@0: nuclear@0: // resolve parents by their IDs and build the output graph nuclear@0: boost::scoped_ptr root(new Group()); nuclear@0: for(size_t n = 0; n < scene.nodes.size(); ++n) { nuclear@0: const Node& nn = *scene.nodes[n].get(); nuclear@0: if(nn.parent_id==0) { nuclear@0: root->temp_children.push_back(&nn); nuclear@0: } nuclear@0: nuclear@0: for(size_t m = n; m < scene.nodes.size(); ++m) { nuclear@0: const Node& mm = *scene.nodes[m].get(); nuclear@0: if (mm.parent_id == nn.id) { nuclear@0: nn.temp_children.push_back(&mm); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: pScene->mRootNode = BuildNodes(*root.get(),scene,pScene); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ConvertTexture(boost::shared_ptr< Texture > tex, aiMaterial* out, aiTextureType type) nuclear@0: { nuclear@0: const aiString path( tex->path ); nuclear@0: out->AddProperty(&path,AI_MATKEY_TEXTURE(type,0)); nuclear@0: out->AddProperty(&tex->transform,1,AI_MATKEY_UVTRANSFORM(type,0)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill) nuclear@0: { nuclear@0: aiNode* nd = new aiNode(); nuclear@0: nd->mName.Set(root.name); nuclear@0: nd->mTransformation = root.transform; nuclear@0: nuclear@0: // Note to everybody believing Voodoo is appropriate here: nuclear@0: // I know polymorphism, run as fast as you can ;-) nuclear@0: if (Node::TYPE_MESH == root.type) { nuclear@0: const Mesh& ndmesh = (const Mesh&)(root); nuclear@0: if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) { nuclear@0: nuclear@0: typedef std::pair Entry; nuclear@0: for_each(const Entry& reflist,ndmesh.temp_map) { nuclear@0: { // create mesh nuclear@0: size_t n = 0; nuclear@0: for_each(Face* f, reflist.second) { nuclear@0: n += f->indices.size(); nuclear@0: } nuclear@0: if (!n) { nuclear@0: continue; nuclear@0: } nuclear@0: aiMesh* outmesh = fill->mMeshes[fill->mNumMeshes++] = new aiMesh(); nuclear@0: ++nd->mNumMeshes; nuclear@0: nuclear@0: outmesh->mVertices = new aiVector3D[n]; nuclear@0: outmesh->mTextureCoords[0] = new aiVector3D[n]; nuclear@0: nuclear@0: outmesh->mFaces = new aiFace[reflist.second.size()](); nuclear@0: for_each(Face* f, reflist.second) { nuclear@0: if (f->indices.empty()) { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: aiFace& fout = outmesh->mFaces[outmesh->mNumFaces++]; nuclear@0: fout.mIndices = new unsigned int[f->indices.size()]; nuclear@0: nuclear@0: for_each(VertexIndex& v, f->indices) { nuclear@0: if (v.pos_idx >= ndmesh.vertex_positions.size()) { nuclear@0: ThrowException("Position index out of range"); nuclear@0: } nuclear@0: if (v.uv_idx >= ndmesh.texture_coords.size()) { nuclear@0: ThrowException("UV index out of range"); nuclear@0: } nuclear@0: outmesh->mVertices[outmesh->mNumVertices] = ndmesh.vertex_positions[ v.pos_idx ]; nuclear@0: outmesh->mTextureCoords[0][outmesh->mNumVertices] = aiVector3D( nuclear@0: ndmesh.texture_coords[ v.uv_idx ].x, nuclear@0: ndmesh.texture_coords[ v.uv_idx ].y, nuclear@0: 0.f nuclear@0: ); nuclear@0: nuclear@0: fout.mIndices[fout.mNumIndices++] = outmesh->mNumVertices++; nuclear@0: } nuclear@0: } nuclear@0: outmesh->mMaterialIndex = fill->mNumMaterials; nuclear@0: }{ // create material nuclear@0: const Material* min = NULL; nuclear@0: for_each(const Material& m, scin.materials) { nuclear@0: if (m.parent_id == ndmesh.id && m.matnum == reflist.first) { nuclear@0: min = &m; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: boost::scoped_ptr defmat; nuclear@0: if(!min) { nuclear@0: DefaultLogger::get()->debug(format()<<"Could not resolve material index " nuclear@0: <mMaterials[fill->mNumMaterials++] = mat; nuclear@0: nuclear@0: const aiString s(format("#mat_")<mNumMeshes<<"_"<matnum); nuclear@0: mat->AddProperty(&s,AI_MATKEY_NAME); nuclear@0: nuclear@0: if(int tmp = ndmesh.draw_flags & Mesh::WIRED ? 1 : 0) { nuclear@0: mat->AddProperty(&tmp,1,AI_MATKEY_ENABLE_WIREFRAME); nuclear@0: } nuclear@0: nuclear@0: { int shader; nuclear@0: switch(min->shader) nuclear@0: { nuclear@0: case Material::FLAT: nuclear@0: shader = aiShadingMode_Gouraud; nuclear@0: break; nuclear@0: nuclear@0: case Material::PHONG: nuclear@0: shader = aiShadingMode_Phong; nuclear@0: break; nuclear@0: nuclear@0: case Material::METAL: nuclear@0: shader = aiShadingMode_CookTorrance; nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: ai_assert(false); // shouldn't be here nuclear@0: } nuclear@0: mat->AddProperty(&shader,1,AI_MATKEY_SHADING_MODEL); nuclear@0: if(shader != aiShadingMode_Gouraud) { nuclear@0: mat->AddProperty(&min->exp,1,AI_MATKEY_SHININESS); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: mat->AddProperty(&min->ior,1,AI_MATKEY_REFRACTI); nuclear@0: mat->AddProperty(&min->rgb,1,AI_MATKEY_COLOR_DIFFUSE); nuclear@0: nuclear@0: aiColor3D c = aiColor3D(min->rgb)*min->ks; nuclear@0: mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR); nuclear@0: nuclear@0: c = aiColor3D(min->rgb)*min->ka; nuclear@0: mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT); nuclear@0: nuclear@0: // convert textures if some exist. nuclear@0: if(min->tex_color) { nuclear@0: ConvertTexture(min->tex_color,mat,aiTextureType_DIFFUSE); nuclear@0: } nuclear@0: if(min->tex_env) { nuclear@0: ConvertTexture(min->tex_env ,mat,aiTextureType_UNKNOWN); nuclear@0: } nuclear@0: if(min->tex_bump) { nuclear@0: ConvertTexture(min->tex_bump ,mat,aiTextureType_HEIGHT); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: else if (Node::TYPE_LIGHT == root.type) { nuclear@0: const Light& ndlight = (const Light&)(root); nuclear@0: aiLight* outlight = fill->mLights[fill->mNumLights++] = new aiLight(); nuclear@0: nuclear@0: outlight->mName.Set(ndlight.name); nuclear@0: outlight->mColorDiffuse = outlight->mColorAmbient = outlight->mColorSpecular = ndlight.color; nuclear@0: nuclear@0: outlight->mAngleOuterCone = AI_DEG_TO_RAD(ndlight.angle); nuclear@0: outlight->mAngleInnerCone = AI_DEG_TO_RAD(ndlight.inner_angle); nuclear@0: nuclear@0: // XXX nuclear@0: outlight->mType = ndlight.ltype==Light::SPOT ? aiLightSource_SPOT : aiLightSource_DIRECTIONAL; nuclear@0: } nuclear@0: else if (Node::TYPE_CAMERA == root.type) { nuclear@0: const Camera& ndcam = (const Camera&)(root); nuclear@0: aiCamera* outcam = fill->mCameras[fill->mNumCameras++] = new aiCamera(); nuclear@0: nuclear@0: outcam->mName.Set(ndcam.name); nuclear@0: } nuclear@0: nuclear@0: // add meshes nuclear@0: if (nd->mNumMeshes) { // mMeshes must be NULL if count is 0 nuclear@0: nd->mMeshes = new unsigned int[nd->mNumMeshes]; nuclear@0: for(unsigned int i = 0; i < nd->mNumMeshes;++i) { nuclear@0: nd->mMeshes[i] = fill->mNumMeshes-i-1; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // add children recursively nuclear@0: nd->mChildren = new aiNode*[root.temp_children.size()](); nuclear@0: for_each(const Node* n, root.temp_children) { nuclear@0: (nd->mChildren[nd->mNumChildren++] = BuildNodes(*n,scin,fill))->mParent = nd; nuclear@0: } nuclear@0: nuclear@0: return nd; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Read an ASCII file into the given scene data structure nuclear@0: void COBImporter::ReadAsciiFile(Scene& out, StreamReaderLE* stream) nuclear@0: { nuclear@0: ChunkInfo ci; nuclear@0: for(LineSplitter splitter(*stream);splitter;++splitter) { nuclear@0: nuclear@0: // add all chunks to be recognized here. /else ../ omitted intentionally. nuclear@0: if (splitter.match_start("PolH ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadPolH_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("BitM ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadBitM_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Mat1 ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadMat1_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Grou ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadGrou_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Lght ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadLght_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Came ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadCame_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Bone ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadBone_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Chan ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadChan_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("Unit ")) { nuclear@0: ReadChunkInfo_Ascii(ci,splitter); nuclear@0: ReadUnit_Ascii(out,splitter,ci); nuclear@0: } nuclear@0: if (splitter.match_start("END ")) { nuclear@0: // we don't need this, but I guess there is a reason this nuclear@0: // chunk has been implemented into COB for. nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadChunkInfo_Ascii(ChunkInfo& out, const LineSplitter& splitter) nuclear@0: { nuclear@0: const char* all_tokens[8]; nuclear@0: splitter.get_tokens(all_tokens); nuclear@0: nuclear@0: out.version = (all_tokens[1][1]-'0')*100+(all_tokens[1][3]-'0')*10+(all_tokens[1][4]-'0'); nuclear@0: out.id = strtoul10(all_tokens[3]); nuclear@0: out.parent_id = strtoul10(all_tokens[5]); nuclear@0: out.size = strtol10(all_tokens[7]); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo& nfo, const char* name) nuclear@0: { nuclear@0: const std::string error = format("Encountered unsupported chunk: ") << name << nuclear@0: " [version: "<(-1)) { nuclear@0: DefaultLogger::get()->error(error); nuclear@0: nuclear@0: // (HACK) - our current position in the stream is the beginning of the nuclear@0: // head line of the next chunk. That's fine, but the caller is going nuclear@0: // to call ++ on `splitter`, which we need to swallow to avoid nuclear@0: // missing the next line. nuclear@0: splitter.get_stream().IncPtr(nfo.size); nuclear@0: splitter.swallow_next_increment(); nuclear@0: } nuclear@0: else ThrowException(error); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message) { nuclear@0: LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message) { nuclear@0: LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message) { nuclear@0: LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message) { nuclear@0: LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogWarn_Ascii(const Formatter::format& message) { nuclear@0: DefaultLogger::get()->warn(std::string("COB: ")+=message); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogError_Ascii(const Formatter::format& message) { nuclear@0: DefaultLogger::get()->error(std::string("COB: ")+=message); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogInfo_Ascii(const Formatter::format& message) { nuclear@0: DefaultLogger::get()->info(std::string("COB: ")+=message); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::LogDebug_Ascii(const Formatter::format& message) { nuclear@0: DefaultLogger::get()->debug(std::string("COB: ")+=message); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/) nuclear@0: { nuclear@0: for(;splitter;++splitter) { nuclear@0: if (splitter.match_start("Name")) { nuclear@0: msh.name = std::string(splitter[1]); nuclear@0: nuclear@0: // make nice names by merging the dupe count nuclear@0: std::replace(msh.name.begin(),msh.name.end(), nuclear@0: ',','_'); nuclear@0: } nuclear@0: else if (splitter.match_start("Transform")) { nuclear@0: for(unsigned int y = 0; y < 4 && ++splitter; ++y) { nuclear@0: const char* s = splitter->c_str(); nuclear@0: for(unsigned int x = 0; x < 4; ++x) { nuclear@0: SkipSpaces(&s); nuclear@0: msh.transform[y][x] = fast_atof(&s); nuclear@0: } nuclear@0: } nuclear@0: // we need the transform chunk, so we won't return until we have it. nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: template nuclear@0: void COBImporter::ReadFloat3Tuple_Ascii(T& fill, const char** in) nuclear@0: { nuclear@0: const char* rgb = *in; nuclear@0: for(unsigned int i = 0; i < 3; ++i) { nuclear@0: SkipSpaces(&rgb); nuclear@0: if (*rgb == ',')++rgb; nuclear@0: SkipSpaces(&rgb); nuclear@0: nuclear@0: fill[i] = fast_atof(&rgb); nuclear@0: } nuclear@0: *in = rgb; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 8) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Mat1"); nuclear@0: } nuclear@0: nuclear@0: ++splitter; nuclear@0: if (!splitter.match_start("mat# ")) { nuclear@0: LogWarn_Ascii(splitter,format()<< nuclear@0: "Expected `mat#` line in `Mat1` chunk "< 1) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Unit"); nuclear@0: } nuclear@0: ++splitter; nuclear@0: if (!splitter.match_start("Units ")) { nuclear@0: LogWarn_Ascii(splitter,format()<< nuclear@0: "Expected `Units` line in `Unit` chunk "<& nd, out.nodes) { nuclear@0: if (nd->id == nfo.parent_id) { nuclear@0: const unsigned int t=strtoul10(splitter[1]); nuclear@0: nuclear@0: nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( nuclear@0: LogWarn_Ascii(splitter,format()< 8) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Chan"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 8) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Lght"); nuclear@0: } nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Light())); nuclear@0: Light& msh = (Light&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); nuclear@0: nuclear@0: if (splitter.match_start("Infinite ")) { nuclear@0: msh.ltype = Light::INFINITE; nuclear@0: } nuclear@0: else if (splitter.match_start("Local ")) { nuclear@0: msh.ltype = Light::LOCAL; nuclear@0: } nuclear@0: else if (splitter.match_start("Spot ")) { nuclear@0: msh.ltype = Light::SPOT; nuclear@0: } nuclear@0: else { nuclear@0: LogWarn_Ascii(splitter,format()<< nuclear@0: "Unknown kind of light source in `Lght` chunk "< 2) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Came"); nuclear@0: } nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Camera())); nuclear@0: Camera& msh = (Camera&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); nuclear@0: nuclear@0: // skip the next line, we don't know this differenciation between a nuclear@0: // standard camera and a panoramic camera. nuclear@0: ++splitter; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBone_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 5) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Bone"); nuclear@0: } nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Bone())); nuclear@0: Bone& msh = (Bone&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); nuclear@0: nuclear@0: // TODO nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadGrou_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 1) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"Grou"); nuclear@0: } nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Group())); nuclear@0: Group& msh = (Group&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 8) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"PolH"); nuclear@0: } nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Mesh())); nuclear@0: Mesh& msh = (Mesh&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Ascii(msh,++splitter,nfo); nuclear@0: nuclear@0: // the chunk has a fixed order of components, but some are not interesting of us so nuclear@0: // we're just looking for keywords in arbitrary order. The end of the chunk is nuclear@0: // either the last `Face` or the `DrawFlags` attribute, depending on the format ver. nuclear@0: for(;splitter;++splitter) { nuclear@0: if (splitter.match_start("World Vertices")) { nuclear@0: const unsigned int cnt = strtoul10(splitter[2]); nuclear@0: msh.vertex_positions.resize(cnt); nuclear@0: nuclear@0: for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) { nuclear@0: const char* s = splitter->c_str(); nuclear@0: nuclear@0: aiVector3D& v = msh.vertex_positions[cur]; nuclear@0: nuclear@0: SkipSpaces(&s); nuclear@0: v.x = fast_atof(&s); nuclear@0: SkipSpaces(&s); nuclear@0: v.y = fast_atof(&s); nuclear@0: SkipSpaces(&s); nuclear@0: v.z = fast_atof(&s); nuclear@0: } nuclear@0: } nuclear@0: else if (splitter.match_start("Texture Vertices")) { nuclear@0: const unsigned int cnt = strtoul10(splitter[2]); nuclear@0: msh.texture_coords.resize(cnt); nuclear@0: nuclear@0: for(unsigned int cur = 0;cur < cnt && ++splitter;++cur) { nuclear@0: const char* s = splitter->c_str(); nuclear@0: nuclear@0: aiVector2D& v = msh.texture_coords[cur]; nuclear@0: nuclear@0: SkipSpaces(&s); nuclear@0: v.x = fast_atof(&s); nuclear@0: SkipSpaces(&s); nuclear@0: v.y = fast_atof(&s); nuclear@0: } nuclear@0: } nuclear@0: else if (splitter.match_start("Faces")) { nuclear@0: const unsigned int cnt = strtoul10(splitter[1]); nuclear@0: msh.faces.reserve(cnt); nuclear@0: nuclear@0: for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) { nuclear@0: if (splitter.match_start("Hole")) { nuclear@0: LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line"); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: if (!splitter.match_start("Face")) { nuclear@0: ThrowException("Expected Face line"); nuclear@0: } nuclear@0: nuclear@0: msh.faces.push_back(Face()); nuclear@0: Face& face = msh.faces.back(); nuclear@0: nuclear@0: face.indices.resize(strtoul10(splitter[2])); nuclear@0: face.flags = strtoul10(splitter[4]); nuclear@0: face.material = strtoul10(splitter[6]); nuclear@0: nuclear@0: const char* s = (++splitter)->c_str(); nuclear@0: for(size_t i = 0; i < face.indices.size(); ++i) { nuclear@0: if(!SkipSpaces(&s)) { nuclear@0: ThrowException("Expected EOL token in Face entry"); nuclear@0: } nuclear@0: if ('<' != *s++) { nuclear@0: ThrowException("Expected < token in Face entry"); nuclear@0: } nuclear@0: face.indices[i].pos_idx = strtoul10(s,&s); nuclear@0: if (',' != *s++) { nuclear@0: ThrowException("Expected , token in Face entry"); nuclear@0: } nuclear@0: face.indices[i].uv_idx = strtoul10(s,&s); nuclear@0: if ('>' != *s++) { nuclear@0: ThrowException("Expected < token in Face entry"); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: if (nfo.version <= 4) { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: else if (splitter.match_start("DrawFlags")) { nuclear@0: msh.draw_flags = strtoul10(splitter[1]); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 1) { nuclear@0: return UnsupportedChunk_Ascii(splitter,nfo,"BitM"); nuclear@0: } nuclear@0: /* nuclear@0: "\nThumbNailHdrSize %ld" nuclear@0: "\nThumbHeader: %02hx 02hx %02hx " nuclear@0: "\nColorBufSize %ld" nuclear@0: "\nColorBufZipSize %ld" nuclear@0: "\nZippedThumbnail: %02hx 02hx %02hx " nuclear@0: */ nuclear@0: nuclear@0: const unsigned int head = strtoul10((++splitter)[1]); nuclear@0: if (head != sizeof(Bitmap::BitmapHeader)) { nuclear@0: LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: /*union { nuclear@0: Bitmap::BitmapHeader data; nuclear@0: char opaq[sizeof Bitmap::BitmapHeader()]; nuclear@0: };*/ nuclear@0: // ReadHexOctets(opaq,head,(++splitter)[1]); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadString_Binary(std::string& out, StreamReaderLE& reader) nuclear@0: { nuclear@0: out.resize( reader.GetI2()); nuclear@0: for_each(char& c,out) { nuclear@0: c = reader.GetI1(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBasicNodeInfo_Binary(Node& msh, StreamReaderLE& reader, const ChunkInfo& /*nfo*/) nuclear@0: { nuclear@0: const unsigned int dupes = reader.GetI2(); nuclear@0: ReadString_Binary(msh.name,reader); nuclear@0: nuclear@0: msh.name = format(msh.name)<<'_'<(-1)) { nuclear@0: DefaultLogger::get()->error(error); nuclear@0: reader.IncPtr(nfo.size); nuclear@0: } nuclear@0: else ThrowException(error); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // tiny utility guard to aid me at staying within chunk boundaries. nuclear@0: class chunk_guard { nuclear@0: nuclear@0: public: nuclear@0: nuclear@0: chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader) nuclear@0: : nfo(nfo) nuclear@0: , reader(reader) nuclear@0: , cur(reader.GetCurrentPos()) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: ~chunk_guard() { nuclear@0: // don't do anything if the size is not given nuclear@0: if(nfo.size != static_cast(-1)) { nuclear@0: reader.IncPtr(static_cast(nfo.size)-reader.GetCurrentPos()+cur); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: private: nuclear@0: nuclear@0: const COB::ChunkInfo& nfo; nuclear@0: StreamReaderLE& reader; nuclear@0: long cur; nuclear@0: }; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) nuclear@0: { nuclear@0: while(1) { nuclear@0: std::string type; nuclear@0: type += reader -> GetI1() nuclear@0: ,type += reader -> GetI1() nuclear@0: ,type += reader -> GetI1() nuclear@0: ,type += reader -> GetI1() nuclear@0: ; nuclear@0: nuclear@0: ChunkInfo nfo; nuclear@0: nfo.version = reader -> GetI2()*10; nuclear@0: nfo.version += reader -> GetI2(); nuclear@0: nuclear@0: nfo.id = reader->GetI4(); nuclear@0: nfo.parent_id = reader->GetI4(); nuclear@0: nfo.size = reader->GetI4(); nuclear@0: nuclear@0: if (type == "PolH") { nuclear@0: ReadPolH_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "BitM") { nuclear@0: ReadBitM_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "Grou") { nuclear@0: ReadGrou_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "Lght") { nuclear@0: ReadLght_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "Came") { nuclear@0: ReadCame_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "Mat1") { nuclear@0: ReadMat1_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: /* else if (type == "Bone") { nuclear@0: ReadBone_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "Chan") { nuclear@0: ReadChan_Binary(out,*reader,nfo); nuclear@0: }*/ nuclear@0: else if (type == "Unit") { nuclear@0: ReadUnit_Binary(out,*reader,nfo); nuclear@0: } nuclear@0: else if (type == "OLay") { nuclear@0: // ignore layer index silently. nuclear@0: if(nfo.size != static_cast(-1) ) { nuclear@0: reader->IncPtr(nfo.size); nuclear@0: } nuclear@0: else return UnsupportedChunk_Binary(*reader,nfo,type.c_str()); nuclear@0: } nuclear@0: else if (type == "END ") { nuclear@0: return; nuclear@0: } nuclear@0: else UnsupportedChunk_Binary(*reader,nfo,type.c_str()); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 8) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"PolH"); nuclear@0: } nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Mesh())); nuclear@0: Mesh& msh = (Mesh&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Binary(msh,reader,nfo); nuclear@0: nuclear@0: msh.vertex_positions.resize(reader.GetI4()); nuclear@0: for_each(aiVector3D& v,msh.vertex_positions) { nuclear@0: v.x = reader.GetF4(); nuclear@0: v.y = reader.GetF4(); nuclear@0: v.z = reader.GetF4(); nuclear@0: } nuclear@0: nuclear@0: msh.texture_coords.resize(reader.GetI4()); nuclear@0: for_each(aiVector2D& v,msh.texture_coords) { nuclear@0: v.x = reader.GetF4(); nuclear@0: v.y = reader.GetF4(); nuclear@0: } nuclear@0: nuclear@0: const size_t numf = reader.GetI4(); nuclear@0: msh.faces.reserve(numf); nuclear@0: for(size_t i = 0; i < numf; ++i) { nuclear@0: // XXX backface culling flag is 0x10 in flags nuclear@0: nuclear@0: // hole? nuclear@0: bool hole; nuclear@0: if ((hole = (reader.GetI1() & 0x08) != 0)) { nuclear@0: // XXX Basically this should just work fine - then triangulator nuclear@0: // should output properly triangulated data even for polygons nuclear@0: // with holes. Test data specific to COB is needed to confirm it. nuclear@0: if (msh.faces.empty()) { nuclear@0: ThrowException(format("A hole is the first entity in the `PolH` chunk with id ") << nfo.id); nuclear@0: } nuclear@0: } nuclear@0: else msh.faces.push_back(Face()); nuclear@0: Face& f = msh.faces.back(); nuclear@0: nuclear@0: const size_t num = reader.GetI2(); nuclear@0: f.indices.reserve(f.indices.size() + num); nuclear@0: nuclear@0: if(!hole) { nuclear@0: f.material = reader.GetI2(); nuclear@0: f.flags = 0; nuclear@0: } nuclear@0: nuclear@0: for(size_t x = 0; x < num; ++x) { nuclear@0: f.indices.push_back(VertexIndex()); nuclear@0: nuclear@0: VertexIndex& v = f.indices.back(); nuclear@0: v.pos_idx = reader.GetI4(); nuclear@0: v.uv_idx = reader.GetI4(); nuclear@0: } nuclear@0: nuclear@0: if(hole) { nuclear@0: std::reverse(f.indices.rbegin(),f.indices.rbegin()+num); nuclear@0: } nuclear@0: } nuclear@0: if (nfo.version>4) { nuclear@0: msh.draw_flags = reader.GetI4(); nuclear@0: } nuclear@0: nfo.version>5 && nfo.version<8 ? reader.GetI4() : 0; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadBitM_Binary(COB::Scene& /*out*/, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 1) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"BitM"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: const uint32_t len = reader.GetI4(); nuclear@0: reader.IncPtr(len); nuclear@0: nuclear@0: reader.GetI4(); nuclear@0: reader.IncPtr(reader.GetI4()); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 8) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"Mat1"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: out.materials.push_back(Material()); nuclear@0: Material& mat = out.materials.back(); nuclear@0: mat = nfo; nuclear@0: nuclear@0: mat.matnum = reader.GetI2(); nuclear@0: switch(reader.GetI1()) { nuclear@0: case 'f': nuclear@0: mat.type = Material::FLAT; nuclear@0: break; nuclear@0: case 'p': nuclear@0: mat.type = Material::PHONG; nuclear@0: break; nuclear@0: case 'm': nuclear@0: mat.type = Material::METAL; nuclear@0: break; nuclear@0: default: nuclear@0: LogError_Ascii(format("Unrecognized shader type in `Mat1` chunk with id ")<(reader.GetI1()); nuclear@0: nuclear@0: mat.rgb.r = reader.GetF4(); nuclear@0: mat.rgb.g = reader.GetF4(); nuclear@0: mat.rgb.b = reader.GetF4(); nuclear@0: nuclear@0: mat.alpha = reader.GetF4(); nuclear@0: mat.ka = reader.GetF4(); nuclear@0: mat.ks = reader.GetF4(); nuclear@0: mat.exp = reader.GetF4(); nuclear@0: mat.ior = reader.GetF4(); nuclear@0: nuclear@0: char id[2]; nuclear@0: id[0] = reader.GetI1(),id[1] = reader.GetI1(); nuclear@0: nuclear@0: if (id[0] == 'e' && id[1] == ':') { nuclear@0: mat.tex_env.reset(new Texture()); nuclear@0: nuclear@0: reader.GetI1(); nuclear@0: ReadString_Binary(mat.tex_env->path,reader); nuclear@0: nuclear@0: // advance to next texture-id nuclear@0: id[0] = reader.GetI1(),id[1] = reader.GetI1(); nuclear@0: } nuclear@0: nuclear@0: if (id[0] == 't' && id[1] == ':') { nuclear@0: mat.tex_color.reset(new Texture()); nuclear@0: nuclear@0: reader.GetI1(); nuclear@0: ReadString_Binary(mat.tex_color->path,reader); nuclear@0: nuclear@0: mat.tex_color->transform.mTranslation.x = reader.GetF4(); nuclear@0: mat.tex_color->transform.mTranslation.y = reader.GetF4(); nuclear@0: nuclear@0: mat.tex_color->transform.mScaling.x = reader.GetF4(); nuclear@0: mat.tex_color->transform.mScaling.y = reader.GetF4(); nuclear@0: nuclear@0: // advance to next texture-id nuclear@0: id[0] = reader.GetI1(),id[1] = reader.GetI1(); nuclear@0: } nuclear@0: nuclear@0: if (id[0] == 'b' && id[1] == ':') { nuclear@0: mat.tex_bump.reset(new Texture()); nuclear@0: nuclear@0: reader.GetI1(); nuclear@0: ReadString_Binary(mat.tex_bump->path,reader); nuclear@0: nuclear@0: mat.tex_bump->transform.mTranslation.x = reader.GetF4(); nuclear@0: mat.tex_bump->transform.mTranslation.y = reader.GetF4(); nuclear@0: nuclear@0: mat.tex_bump->transform.mScaling.x = reader.GetF4(); nuclear@0: mat.tex_bump->transform.mScaling.y = reader.GetF4(); nuclear@0: nuclear@0: // skip amplitude for I don't know its purpose. nuclear@0: reader.GetF4(); nuclear@0: } nuclear@0: reader.IncPtr(-2); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 2) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"Came"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Camera())); nuclear@0: Camera& msh = (Camera&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Binary(msh,reader,nfo); nuclear@0: nuclear@0: // the rest is not interesting for us, so we skip over it. nuclear@0: if(nfo.version > 1) { nuclear@0: if (reader.GetI2()==512) { nuclear@0: reader.IncPtr(42); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 2) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"Lght"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Light())); nuclear@0: Light& msh = (Light&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Binary(msh,reader,nfo); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 2) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"Grou"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: out.nodes.push_back(boost::shared_ptr(new Group())); nuclear@0: Group& msh = (Group&)(*out.nodes.back().get()); nuclear@0: msh = nfo; nuclear@0: nuclear@0: ReadBasicNodeInfo_Binary(msh,reader,nfo); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const ChunkInfo& nfo) nuclear@0: { nuclear@0: if(nfo.version > 1) { nuclear@0: return UnsupportedChunk_Binary(reader,nfo,"Unit"); nuclear@0: } nuclear@0: nuclear@0: const chunk_guard cn(nfo,reader); nuclear@0: nuclear@0: // parent chunks preceede their childs, so we should have the nuclear@0: // corresponding chunk already. nuclear@0: for_each(boost::shared_ptr< Node >& nd, out.nodes) { nuclear@0: if (nd->id == nfo.parent_id) { nuclear@0: const unsigned int t=reader.GetI2(); nuclear@0: nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( nuclear@0: LogWarn_Ascii(format()<