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