diff options
Diffstat (limited to 'libs/assimp/tools/assimp_cmd')
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/CMakeLists.txt | 73 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/CompareDump.cpp | 956 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/Export.cpp | 166 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/ImageExtractor.cpp | 361 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/Info.cpp | 483 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/Main.cpp | 564 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/Main.h | 273 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/WriteDump.cpp | 172 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/assimp_cmd.rc | 51 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/generic_inserter.hpp | 113 | ||||
| -rw-r--r-- | libs/assimp/tools/assimp_cmd/resource.h | 21 | 
11 files changed, 3233 insertions, 0 deletions
diff --git a/libs/assimp/tools/assimp_cmd/CMakeLists.txt b/libs/assimp/tools/assimp_cmd/CMakeLists.txt new file mode 100644 index 0000000..6f4b613 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/CMakeLists.txt @@ -0,0 +1,73 @@ +# 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. +# +#---------------------------------------------------------------------- +cmake_minimum_required( VERSION 3.10 ) + +INCLUDE_DIRECTORIES( +  ${Assimp_SOURCE_DIR}/include +  ${Assimp_SOURCE_DIR}/code +  ${Assimp_BINARY_DIR}/tools/assimp_cmd +) + +LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib ) + +ADD_EXECUTABLE( assimp_cmd +  assimp_cmd.rc +  CompareDump.cpp +  ImageExtractor.cpp +  Main.cpp +  Main.h +  resource.h +  WriteDump.cpp +  Info.cpp +  Export.cpp +) + +TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp_cmd) + +SET_PROPERTY(TARGET assimp_cmd PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +TARGET_LINK_LIBRARIES( assimp_cmd assimp ${ZLIB_LIBRARIES} ) +SET_TARGET_PROPERTIES( assimp_cmd PROPERTIES +  OUTPUT_NAME assimp +) + +INSTALL( TARGETS assimp_cmd +  DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-bin +) diff --git a/libs/assimp/tools/assimp_cmd/CompareDump.cpp b/libs/assimp/tools/assimp_cmd/CompareDump.cpp new file mode 100644 index 0000000..49f680c --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/CompareDump.cpp @@ -0,0 +1,956 @@ +/* +--------------------------------------------------------------------------- +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  CompareDump.cpp + *  @brief Implementation of the 'assimp cmpdmp', which compares + *    two model dumps for equality. It plays an important role + *    in the regression test suite. + */ + +#include "Main.h" +const char* AICMD_MSG_CMPDUMP_HELP = +"assimp cmpdump <actual> <expected>\n" +"\tCompare two short dumps produced with \'assimp dump <..> -s\' for equality.\n" +; + +#include "Common/assbin_chunks.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +#include "generic_inserter.hpp" +#include <map> +#include <deque> +#include <stack> +#include <sstream> +#include <iostream> +#include <assimp/ai_assert.h> + +// get << for aiString +template <typename char_t, typename traits_t> +void mysprint(std::basic_ostream<char_t, traits_t>& os,  const aiString& vec)   { +    os << "[length: \'" << std::dec << vec.length << "\' content: \'"  << vec.data << "\']"; +} + +template <typename char_t, typename traits_t> +std::basic_ostream<char_t, traits_t>& operator<< (std::basic_ostream<char_t, traits_t>& os, const aiString& vec)    { +    return generic_inserter(mysprint<char_t,traits_t>, os, vec); +} + +class sliced_chunk_iterator; +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// @class  compare_fails_exception +/// +/// @brief  Sentinel exception to return quickly from deeply nested control paths +//////////////////////////////////////////////////////////////////////////////////////////////////// +class compare_fails_exception : public virtual std::exception { +public: + +    enum {MAX_ERR_LEN = 4096}; + +    /* public c'tors */ +    compare_fails_exception(const char* msg) { +        strncpy(mywhat,msg,MAX_ERR_LEN-1); +        strcat(mywhat,"\n"); +    } + +    /* public member functions */ +    const char* what() const throw() { +        return mywhat; +    } + +private: + +    char mywhat[MAX_ERR_LEN+1]; +}; + + +#define MY_FLT_EPSILON 1e-1f +#define MY_DBL_EPSILON 1e-1 +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// @class  comparer_context +/// +/// @brief  Record our way through the files to be compared and dump useful information if we fail. +//////////////////////////////////////////////////////////////////////////////////////////////////// +class comparer_context { +    friend class sliced_chunk_iterator; + +public: + +    /* construct given two file handles to compare */ +    comparer_context(FILE* actual,FILE* expect) +        : actual(actual) +        , expect(expect) +        , cnt_chunks(0) +    { +        ai_assert(actual); +        ai_assert(expect); + +        fseek(actual,0,SEEK_END); +        lengths.push(std::make_pair(static_cast<uint32_t>(ftell(actual)),0)); +        fseek(actual,0,SEEK_SET); + +        history.push_back(HistoryEntry("---",PerChunkCounter())); +    } + +public: + + +    /* set new scope */ +    void push_elem(const char* msg) { +        const std::string s = msg; + +        PerChunkCounter::const_iterator it = history.back().second.find(s); +        if(it != history.back().second.end()) { +            ++history.back().second[s]; +        } +        else history.back().second[s] = 0; + +        history.push_back(HistoryEntry(s,PerChunkCounter())); +        debug_trace.push_back("PUSH " + s); +    } + +    /* leave current scope */ +    void pop_elem() { +        ai_assert(history.size()); +        debug_trace.push_back("POP "+ history.back().first); +        history.pop_back(); +    } + + +    /* push current chunk length and start offset on top of stack */ +    void push_length(uint32_t nl, uint32_t start) { +        lengths.push(std::make_pair(nl,start)); +        ++cnt_chunks; +    } + +    /* pop the chunk length stack */ +    void pop_length() { +        ai_assert(lengths.size()); +        lengths.pop(); +    } + +    /* access the current chunk length */ +    uint32_t get_latest_chunk_length() { +        ai_assert(lengths.size()); +        return lengths.top().first; +    } + +    /* access the current chunk start offset */ +    uint32_t get_latest_chunk_start() { +        ai_assert(lengths.size()); +        return lengths.top().second; +    } + +    /* total number of chunk headers passed so far*/ +    uint32_t get_num_chunks() { +        return cnt_chunks; +    } + + +    /* get ACTUAL file desc. != NULL */ +    FILE* get_actual() const { +        return actual; +    } + +    /* get EXPECT file desc. != NULL */ +    FILE* get_expect() const { +        return expect; +    } + + +    /* compare next T from both streams, name occurs in error messages */ +    template<typename T> T cmp(const std::string& name) { +        T a,e; +        read(a,e); + +        if(a != e) { +            std::stringstream ss; +            failure((ss<< "Expected " << e << ", but actual is " << a, +                ss.str()),name); +        } +    //  std::cout << name << " " << std::hex << a << std::endl; +        return a; +    } + +    /* compare next num T's from both streams, name occurs in error messages */ +    template<typename T> void cmp(size_t num,const std::string& name) { +        for(size_t n = 0; n < num; ++n) { +            std::stringstream ss; +            cmp<T>((ss<<name<<"["<<n<<"]",ss.str())); +    //      std::cout << name << " " << std::hex << a << std::endl; +        } +    } + +    /* Bounds of an aiVector3D array (separate function +     *  because partial specializations of member functions are illegal--)*/ +    template<typename T> void cmp_bounds(const std::string& name) { +        cmp<T> (name+".<minimum-value>"); +        cmp<T> (name+".<maximum-value>"); +    } + +private: + +    /* Report failure */ +    AI_WONT_RETURN void failure(const std::string& err, const std::string& name) AI_WONT_RETURN_SUFFIX { +        std::stringstream ss; +        throw compare_fails_exception((ss +            << "Files are different at " +            << history.back().first +            << "." +            << name +            << ".\nError is: " +            << err +            << ".\nCurrent position in scene hierarchy is " +            << print_hierarchy(),ss.str().c_str() +            )); +    } + +    /** print our 'stack' */ +    std::string print_hierarchy() { +        std::stringstream ss; +        ss << "\n"; + +        const char* last = history.back().first.c_str(); +        std::string pad; + +        for(ChunkHistory::reverse_iterator rev = history.rbegin(), +            end = history.rend(); rev != end; ++rev, pad += "  ") +        { +            ss << pad << (*rev).first << "(Index: " << (*rev).second[last] << ")" << "\n"; +            last = (*rev).first.c_str(); +        } + +        ss << std::endl << "Debug trace: "<< "\n"; +        for (std::vector<std::string>::const_iterator it = debug_trace.begin(); it != debug_trace.end(); ++it) { +            ss << *it << "\n"; +        } +        ss << std::flush; + +        return ss.str(); +    } + + +    /* read from both streams at the same time */ +    template <typename T> void read(T& filla,T& fille) { +        if(1 != fread(&filla,sizeof(T),1,actual)) { +            EOFActual(); +        } +        if(1 != fread(&fille,sizeof(T),1,expect)) { +            EOFExpect(); +        } +    } + +private: + +    void EOFActual() { +        std::stringstream ss; +        throw compare_fails_exception((ss +            << "Unexpected EOF reading ACTUAL.\nCurrent position in scene hierarchy is " +            << print_hierarchy(),ss.str().c_str() +            )); +    } + +    void EOFExpect() { +        std::stringstream ss; +        throw compare_fails_exception((ss +            << "Unexpected EOF reading EXPECT.\nCurrent position in scene hierarchy is " +            << print_hierarchy(),ss.str().c_str() +            )); +    } + + +    FILE *const actual, *const expect; + +    typedef std::map<std::string,unsigned int> PerChunkCounter; +    typedef std::pair<std::string,PerChunkCounter> HistoryEntry; + +    typedef std::deque<HistoryEntry> ChunkHistory; +    ChunkHistory history; + +    std::vector<std::string> debug_trace; + +    typedef std::stack<std::pair<uint32_t,uint32_t> > LengthStack; +    LengthStack lengths; + +    uint32_t cnt_chunks; +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* specialization for aiString (it needs separate handling because its on-disk representation + * differs from its binary representation in memory and can't be treated as an array of n T's.*/ +template <> void comparer_context :: read<aiString>(aiString& filla,aiString& fille) { +    uint32_t lena,lene; +    read(lena,lene); + +    if(lena && 1 != fread(&filla.data,lena,1,actual)) { +        EOFActual(); +    } +    if(lene && 1 != fread(&fille.data,lene,1,expect)) { +        EOFExpect(); +    } + +    fille.data[fille.length=static_cast<unsigned int>(lene)] = '\0'; +    filla.data[filla.length=static_cast<unsigned int>(lena)] = '\0'; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for float, uses epsilon for comparisons*/ +template<> float comparer_context :: cmp<float>(const std::string& name) +{ +    float a,e,t; +    read(a,e); + +    if((t=fabs(a-e)) > MY_FLT_EPSILON) { +        std::stringstream ss; +        failure((ss<< "Expected " << e << ", but actual is " +            << a << " (delta is " << t << ")", ss.str()),name); +    } +    return a; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for double, uses epsilon for comparisons*/ +template<> double comparer_context :: cmp<double>(const std::string& name) +{ +    double a,e,t; +    read(a,e); + +    if((t=fabs(a-e)) > MY_DBL_EPSILON) { +        std::stringstream ss; +        failure((ss<< "Expected " << e << ", but actual is " +            << a << " (delta is " << t << ")", ss.str()),name); +    } +    return a; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiVector3D */ +template<> aiVector3D comparer_context :: cmp<aiVector3D >(const std::string& name) +{ +    const float x = cmp<float>(name+".x"); +    const float y = cmp<float>(name+".y"); +    const float z = cmp<float>(name+".z"); + +    return aiVector3D(x,y,z); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiColor4D */ +template<> aiColor4D comparer_context :: cmp<aiColor4D >(const std::string& name) +{ +    const float r = cmp<float>(name+".r"); +    const float g = cmp<float>(name+".g"); +    const float b = cmp<float>(name+".b"); +    const float a = cmp<float>(name+".a"); + +    return aiColor4D(r,g,b,a); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiQuaternion */ +template<> aiQuaternion comparer_context :: cmp<aiQuaternion >(const std::string& name) +{ +    const float w = cmp<float>(name+".w"); +    const float x = cmp<float>(name+".x"); +    const float y = cmp<float>(name+".y"); +    const float z = cmp<float>(name+".z"); + +    return aiQuaternion(w,x,y,z); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiQuatKey */ +template<> aiQuatKey comparer_context :: cmp<aiQuatKey >(const std::string& name) +{ +    const double mTime = cmp<double>(name+".mTime"); +    const aiQuaternion mValue = cmp<aiQuaternion>(name+".mValue"); + +    return aiQuatKey(mTime,mValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiVectorKey */ +template<> aiVectorKey comparer_context :: cmp<aiVectorKey >(const std::string& name) +{ +    const double mTime = cmp<double>(name+".mTime"); +    const aiVector3D mValue = cmp<aiVector3D>(name+".mValue"); + +    return aiVectorKey(mTime,mValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiMatrix4x4 */ +template<> aiMatrix4x4 comparer_context :: cmp<aiMatrix4x4 >(const std::string& name) +{ +    aiMatrix4x4 res; +    for(unsigned int i = 0; i < 4; ++i) { +        for(unsigned int j = 0; j < 4; ++j) { +            std::stringstream ss; +            res[i][j] = cmp<float>(name+(ss<<".m"<<i<<j,ss.str())); +        } +    } + +    return res; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiVertexWeight */ +template<> aiVertexWeight comparer_context :: cmp<aiVertexWeight >(const std::string& name) +{ +    const unsigned int mVertexId = cmp<unsigned int>(name+".mVertexId"); +    const float mWeight = cmp<float>(name+".mWeight"); + +    return aiVertexWeight(mVertexId,mWeight); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// @class  sliced_chunk_iterator +/// +/// @brief  Helper to iterate easily through corresponding chunks of two dumps simultaneously. +/// +/// Not a *real* iterator, doesn't fully conform to the isocpp iterator spec +//////////////////////////////////////////////////////////////////////////////////////////////////// +class sliced_chunk_iterator { + +    friend class sliced_chunk_reader; +    sliced_chunk_iterator(comparer_context& ctx, long end) +        : ctx(ctx) +        , endit(false) +        , next(std::numeric_limits<long>::max()) +        , end(end) +    { +        load_next(); +    } + +public: + +    ~sliced_chunk_iterator() { +        fseek(ctx.get_actual(),end,SEEK_SET); +        fseek(ctx.get_expect(),end,SEEK_SET); +    } + +public: + +    /* get current chunk head */ +    typedef std::pair<uint32_t,uint32_t> Chunk; +    const Chunk& operator*() { +        return current; +    } + +    /* get to next chunk head */ +    const sliced_chunk_iterator& operator++() { +        cleanup(); +        load_next(); +        return *this; +    } + +    /* */ +    bool is_end() const { +        return endit; +    } + +private: + +    /* get to the end of *this* chunk */ +    void cleanup() { +        if(next != std::numeric_limits<long>::max()) { +            fseek(ctx.get_actual(),next,SEEK_SET); +            fseek(ctx.get_expect(),next,SEEK_SET); + +            ctx.pop_length(); +        } +    } + +    /* advance to the next chunk */ +    void load_next() { + +        Chunk actual; +        size_t res=0; + +        const long cur = ftell(ctx.get_expect()); +        if(end-cur<8) { +            current = std::make_pair(0u,0u); +            endit = true; +            return; +        } + +        res|=fread(¤t.first,4,1,ctx.get_expect()); +        res|=fread(¤t.second,4,1,ctx.get_expect())    <<1u; +        res|=fread(&actual.first,4,1,ctx.get_actual())      <<2u; +        res|=fread(&actual.second,4,1,ctx.get_actual())     <<3u; + +        if(res!=0xf) { +            ctx.failure("IO Error reading chunk head, dumps are malformed","<ChunkHead>"); +        } + +        if (current.first != actual.first) { +            std::stringstream ss; +            ctx.failure((ss +                <<"Chunk headers do not match. EXPECT: " +                << std::hex << current.first +                <<" ACTUAL: " +                << /*std::hex */actual.first, +                ss.str()), +                "<ChunkHead>"); +        } + +        if (current.first != actual.first) { +            std::stringstream ss; +            ctx.failure((ss +                <<"Chunk lengths do not match. EXPECT: " +                <<current.second +                <<" ACTUAL: " +                << actual.second, +                ss.str()), +                "<ChunkHead>"); +        } + +        next = cur+current.second+8; +        ctx.push_length(current.second,cur+8); +    } + +    comparer_context& ctx; +    Chunk current; +    bool endit; +    long next,end; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// @class  sliced_chunk_reader +/// +/// @brief  Helper to iterate easily through corresponding chunks of two dumps simultaneously. +//////////////////////////////////////////////////////////////////////////////////////////////////// +class sliced_chunk_reader  { +public: + +    // +    sliced_chunk_reader(comparer_context& ctx) +        : ctx(ctx) +    {} + +    // +    ~sliced_chunk_reader() { +    } + +public: + +    sliced_chunk_iterator begin() const { +        return sliced_chunk_iterator(ctx,ctx.get_latest_chunk_length()+ +            ctx.get_latest_chunk_start()); +    } + +private: + +    comparer_context& ctx; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// @class  scoped_chunk +/// +/// @brief  Utility to simplify usage of comparer_context.push_elem/pop_elem +//////////////////////////////////////////////////////////////////////////////////////////////////// +class scoped_chunk { +public: + +    // +    scoped_chunk(comparer_context& ctx,const char* msg) +        : ctx(ctx) +    { +        ctx.push_elem(msg); +    } + +    // +    ~scoped_chunk() +    { +        ctx.pop_elem(); +    } + +private: + +    comparer_context& ctx; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyMaterialProperty(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiMaterialProperty"); + +    comp.cmp<aiString>("mKey"); +    comp.cmp<uint32_t>("mSemantic"); +    comp.cmp<uint32_t>("mIndex"); +    const uint32_t length = comp.cmp<uint32_t>("mDataLength"); +    const aiPropertyTypeInfo type = static_cast<aiPropertyTypeInfo>( +        comp.cmp<uint32_t>("mType")); + +    switch (type) +    { +        case aiPTI_Float: +            comp.cmp<float>(length/4,"mData"); +            break; + +        case aiPTI_String: +            comp.cmp<aiString>("mData"); +            break; + +        case aiPTI_Integer: +            comp.cmp<uint32_t>(length/4,"mData"); +            break; + +        case aiPTI_Buffer: +            comp.cmp<uint8_t>(length,"mData"); +            break; + +        default: +            break; +    }; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyMaterial(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiMaterial"); + +    comp.cmp<uint32_t>("aiMaterial::mNumProperties"); +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AIMATERIALPROPERTY) { +            CompareOnTheFlyMaterialProperty(comp); +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyBone(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiBone"); +    comp.cmp<aiString>("mName"); +    comp.cmp<uint32_t>("mNumWeights"); +    comp.cmp<aiMatrix4x4>("mOffsetMatrix"); + +    comp.cmp_bounds<aiVertexWeight>("mWeights"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyNodeAnim(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiNodeAnim"); + +    comp.cmp<aiString>("mNodeName"); +    comp.cmp<uint32_t>("mNumPositionKeys"); +    comp.cmp<uint32_t>("mNumRotationKeys"); +    comp.cmp<uint32_t>("mNumScalingKeys"); +    comp.cmp<uint32_t>("mPreState"); +    comp.cmp<uint32_t>("mPostState"); + +    comp.cmp_bounds<aiVectorKey>("mPositionKeys"); +    comp.cmp_bounds<aiQuatKey>("mRotationKeys"); +    comp.cmp_bounds<aiVectorKey>("mScalingKeys"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyMesh(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiMesh"); + +    comp.cmp<uint32_t>("mPrimitiveTypes"); +    comp.cmp<uint32_t>("mNumVertices"); +    const uint32_t nf = comp.cmp<uint32_t>("mNumFaces"); +    comp.cmp<uint32_t>("mNumBones"); +    comp.cmp<uint32_t>("mMaterialIndex"); + +    const uint32_t present = comp.cmp<uint32_t>("<vertex-components-present>"); +    if(present & ASSBIN_MESH_HAS_POSITIONS) { +        comp.cmp_bounds<aiVector3D>("mVertices"); +    } + +    if(present & ASSBIN_MESH_HAS_NORMALS) { +        comp.cmp_bounds<aiVector3D>("mNormals"); +    } + +    if(present & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) { +        comp.cmp_bounds<aiVector3D>("mTangents"); +        comp.cmp_bounds<aiVector3D>("mBitangents"); +    } + +    for(unsigned int i = 0; present & ASSBIN_MESH_HAS_COLOR(i); ++i) { +        std::stringstream ss; +        comp.cmp_bounds<aiColor4D>((ss<<"mColors["<<i<<"]",ss.str())); +    } + +    for(unsigned int i = 0; present & ASSBIN_MESH_HAS_TEXCOORD(i); ++i) { +        std::stringstream ss; +        comp.cmp<uint32_t>((ss<<"mNumUVComponents["<<i<<"]",ss.str())); +        comp.cmp_bounds<aiVector3D>((ss.clear(),ss<<"mTextureCoords["<<i<<"]",ss.str())); +    } + +    for(unsigned int i = 0; i< ((nf+511)/512); ++i) { +        std::stringstream ss; +        comp.cmp<uint32_t>((ss<<"mFaces["<<i*512<<"-"<<std::min(static_cast< +            uint32_t>((i+1)*512),nf)<<"]",ss.str())); +    } + +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AIBONE) { +            CompareOnTheFlyBone(comp); +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyCamera(comparer_context& comp)  { +    scoped_chunk chunk(comp,"aiCamera"); + +    comp.cmp<aiString>("mName"); + +    comp.cmp<aiVector3D>("mPosition"); +    comp.cmp<aiVector3D>("mLookAt"); +    comp.cmp<aiVector3D>("mUp"); + +    comp.cmp<float>("mHorizontalFOV"); +    comp.cmp<float>("mClipPlaneNear"); +    comp.cmp<float>("mClipPlaneFar"); +    comp.cmp<float>("mAspect"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyLight(comparer_context& comp)   { +    scoped_chunk chunk(comp,"aiLight"); + +    comp.cmp<aiString>("mName"); +    const aiLightSourceType type = static_cast<aiLightSourceType>( +        comp.cmp<uint32_t>("mType")); + +    if(type!=aiLightSource_DIRECTIONAL) { +        comp.cmp<float>("mAttenuationConstant"); +        comp.cmp<float>("mAttenuationLinear"); +        comp.cmp<float>("mAttenuationQuadratic"); +    } + +    comp.cmp<aiVector3D>("mColorDiffuse"); +    comp.cmp<aiVector3D>("mColorSpecular"); +    comp.cmp<aiVector3D>("mColorAmbient"); + +    if(type==aiLightSource_SPOT) { +        comp.cmp<float>("mAngleInnerCone"); +        comp.cmp<float>("mAngleOuterCone"); +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyAnimation(comparer_context& comp)   { +    scoped_chunk chunk(comp,"aiAnimation"); + +    comp.cmp<aiString>("mName"); +    comp.cmp<double>("mDuration"); +    comp.cmp<double>("mTicksPerSecond"); +    comp.cmp<uint32_t>("mNumChannels"); + +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AINODEANIM) { +            CompareOnTheFlyNodeAnim(comp); +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyTexture(comparer_context& comp) { +    scoped_chunk chunk(comp,"aiTexture"); + +    const uint32_t w = comp.cmp<uint32_t>("mWidth"); +    const uint32_t h = comp.cmp<uint32_t>("mHeight"); +    (void)w; (void)h; +    comp.cmp<char>("achFormatHint[0]"); +    comp.cmp<char>("achFormatHint[1]"); +    comp.cmp<char>("achFormatHint[2]"); +    comp.cmp<char>("achFormatHint[3]"); +    comp.cmp<char>("achFormatHint[4]"); +    comp.cmp<char>("achFormatHint[5]"); +    comp.cmp<char>("achFormatHint[6]"); +    comp.cmp<char>("achFormatHint[7]"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyNode(comparer_context& comp)    { +    scoped_chunk chunk(comp,"aiNode"); +    comp.cmp<aiString>("mName"); +    comp.cmp<aiMatrix4x4>("mTransformation"); +    comp.cmp<uint32_t>("mNumChildren"); +    comp.cmp<uint32_t>(comp.cmp<uint32_t>("mNumMeshes"),"mMeshes"); + +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AINODE) { +            CompareOnTheFlyNode(comp); +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyScene(comparer_context& comp)   { +    scoped_chunk chunk(comp,"aiScene"); + +    comp.cmp<uint32_t>("mFlags"); +    comp.cmp<uint32_t>("mNumMeshes"); +    comp.cmp<uint32_t>("mNumMaterials"); +    comp.cmp<uint32_t>("mNumAnimations"); +    comp.cmp<uint32_t>("mNumTextures"); +    comp.cmp<uint32_t>("mNumLights"); +    comp.cmp<uint32_t>("mNumCameras"); + +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AIMATERIAL) { +            CompareOnTheFlyMaterial(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AITEXTURE) { +            CompareOnTheFlyTexture(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AIMESH) { +            CompareOnTheFlyMesh(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AIANIMATION) { +            CompareOnTheFlyAnimation(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AICAMERA) { +            CompareOnTheFlyCamera(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AILIGHT) { +            CompareOnTheFlyLight(comp); +        } +        else if ((*it).first == ASSBIN_CHUNK_AINODE) { +            CompareOnTheFlyNode(comp); +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFly(comparer_context& comp) +{ +    sliced_chunk_reader reader(comp); +    for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) { +        if ((*it).first == ASSBIN_CHUNK_AISCENE) { +            CompareOnTheFlyScene(comp); +            break; +        } +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CheckHeader(comparer_context& comp) +{ +    fseek(comp.get_actual(),ASSBIN_HEADER_LENGTH,SEEK_CUR); +    fseek(comp.get_expect(),ASSBIN_HEADER_LENGTH,SEEK_CUR); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +int Assimp_CompareDump (const char* const* params, unsigned int num) +{ +    // --help +    if ((num == 1 && !strcmp( params[0], "-h")) || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) { +        printf("%s",AICMD_MSG_CMPDUMP_HELP); +        return AssimpCmdError::Success; +    } + +    // assimp cmpdump actual expected +    if (num < 2) { +        std::cout << "assimp cmpdump: Invalid number of arguments. " +            "See \'assimp cmpdump --help\'\r\n" << std::endl; +        return AssimpCmdError::InvalidNumberOfArguments; +    } + +    if(!strcmp(params[0],params[1])) { +        std::cout << "assimp cmpdump: same file, same content." << std::endl; +        return AssimpCmdError::Success; +    } + +    class file_ptr +    { +    public: +        file_ptr(FILE *p) +            : m_file(p) +        {} +        ~file_ptr() +        { +            if (m_file) +            { +                fclose(m_file); +                m_file = NULL; +            } +        } + +        operator FILE *() { return m_file; } + +    private: +        FILE *m_file; +    }; +    file_ptr actual(fopen(params[0],"rb")); +    if (!actual) { +        std::cout << "assimp cmpdump: Failure reading ACTUAL data from " << +            params[0]  << std::endl; +        return AssimpCmdError::FailedToLoadInputFile; +    } +    file_ptr expected(fopen(params[1],"rb")); +    if (!expected) { +        std::cout << "assimp cmpdump: Failure reading EXPECT data from " << +            params[1]  << std::endl; +        return AssimpCmdCompareDumpError::FailedToLoadExpectedInputFile; +    } + +    comparer_context comp(actual,expected); +    try { +        CheckHeader(comp); +        CompareOnTheFly(comp); +    } +    catch(const compare_fails_exception& ex) { +        printf("%s",ex.what()); +        return AssimpCmdCompareDumpError::FileComparaisonFailure; +    } +    catch(...) { +        // we don't bother checking too rigourously here, so +        // we might end up here ... +        std::cout << "Unknown failure, are the input files well-defined?"; +        return AssimpCmdCompareDumpError::UnknownFailure; +    } + +    std::cout << "Success (totally " << std::dec << comp.get_num_chunks() << +        " chunks)" << std::endl; + +    return AssimpCmdError::Success; +} diff --git a/libs/assimp/tools/assimp_cmd/Export.cpp b/libs/assimp/tools/assimp_cmd/Export.cpp new file mode 100644 index 0000000..fd9fc76 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/Export.cpp @@ -0,0 +1,166 @@ +/* +--------------------------------------------------------------------------- +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  Export.cpp + *  @brief Implementation of the 'assimp export' utility + */ + +#include "Main.h" +#include <assimp/ParsingUtils.h> +#include <assimp/StringUtils.h> + +#ifndef ASSIMP_BUILD_NO_EXPORT + +const char *AICMD_MSG_EXPORT_HELP_E = +        "assimp export <model> [<out>] [-f<h>] [common parameters]\n" +        "\t -f<h> Specify the file format. If omitted, the output format is \n" +        "\t\tderived from the file extension of the given output file  \n" +        "\t[See the assimp_cmd docs for a full list of all common parameters]  \n"; + +// ----------------------------------------------------------------------------------- +size_t GetMatchingFormat(const std::string &outf, bool byext = false) { +    for (size_t i = 0, end = globalExporter->GetExportFormatCount(); i < end; ++i) { +        const aiExportFormatDesc *const e = globalExporter->GetExportFormatDescription(i); +        if (outf == (byext ? e->fileExtension : e->id)) { +            return i; +        } +    } +    return SIZE_MAX; +} + +// ----------------------------------------------------------------------------------- +int Assimp_Export(const char *const *params, unsigned int num) { +    const char *const invalid = "assimp export: Invalid number of arguments. See \'assimp export --help\'\n"; +    if (num < 1) { +        printf(invalid); +        return AssimpCmdError::InvalidNumberOfArguments; +    } + +    // --help +    if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) { +        printf("%s", AICMD_MSG_EXPORT_HELP_E); +        return AssimpCmdError::Success; +    } + +    std::string in = std::string(params[0]); +    std::string out = (num > 1 ? std::string(params[1]) : "-"), outext; + +    // +    const std::string::size_type s = out.find_last_of('.'); +    if (s != std::string::npos) { +        outext = out.substr(s + 1); +        out = out.substr(0, s); +    } + +    // get import flags +    ImportData import; +    ProcessStandardArguments(import, params + 1, num - 1); + +    // process other flags +    std::string outf = ""; +    for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num; ++i) { +        if (!params[i]) { +            continue; +        } +        if (!strncmp(params[i], "-f", 2)) { +            if (strncmp(params[i], "-fi", 3)) +                outf = std::string(params[i] + 2); +        } else if (!strncmp(params[i], "--format=", 9)) { +            outf = std::string(params[i] + 9); +        } +    } + +    std::transform(outf.begin(), outf.end(), outf.begin(), ai_tolower<char>); + +    // convert the output format to a format id +    size_t outfi = GetMatchingFormat(outf); +    if (outfi == SIZE_MAX) { +        if (outf.length()) { +            printf("assimp export: warning, format id \'%s\' is unknown\n", outf.c_str()); +        } + +        // retry to see if we know it as file extension +        outfi = GetMatchingFormat(outf, true); +        if (outfi == SIZE_MAX) { +            // retry to see if we know the file extension of the output file +            outfi = GetMatchingFormat(outext, true); + +            if (outfi == SIZE_MAX) { +                // still no match -> failure +                printf("assimp export: no output format specified and I failed to guess it\n"); +                return -23; +            } +        } else { +            outext = outf; +        } +    } + +    // if no output file is specified, take the file name from input file +    if (out[0] == '-') { +        std::string::size_type pos = in.find_last_of('.'); +        if (pos == std::string::npos) { +            pos = in.length(); +        } + +        out = in.substr(0, pos); +    } + +    const aiExportFormatDesc *const e = globalExporter->GetExportFormatDescription(outfi); +    printf("assimp export: select file format: \'%s\' (%s)\n", e->id, e->description); + +    // import the  model +    const aiScene *scene = ImportModel(import, in); +    if (!scene) { +        return AssimpCmdExportError::FailedToImportModel; +    } + +    // derive the final file name +    out += "." + outext; + +    // and call the export routine +    if (!ExportModel(scene, import, out, e->id)) { +        return AssimpCmdExportError::FailedToExportModel; +    } +    printf("assimp export: wrote output file: %s\n", out.c_str()); +    return AssimpCmdError::Success; +} + +#endif // no export diff --git a/libs/assimp/tools/assimp_cmd/ImageExtractor.cpp b/libs/assimp/tools/assimp_cmd/ImageExtractor.cpp new file mode 100644 index 0000000..49edf97 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/ImageExtractor.cpp @@ -0,0 +1,361 @@ +/* +--------------------------------------------------------------------------- +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  ImageExtractor.cpp + *  @brief Implementation of the 'assimp extract' utility + */ + +#include "Main.h" +#include <assimp/ParsingUtils.h> +#include <assimp/StringComparison.h> +#include <assimp/fast_atof.h> + +static const char *AICMD_MSG_DUMP_HELP_E = +        "assimp extract <model> [<out>] [-t<n>] [-f<fmt>] [-ba] [-s] [common parameters]\n" +        "\t -ba   Writes BMP's with alpha channel\n" +        "\t -t<n> Zero-based index of the texture to be extracted \n" +        "\t -f<f> Specify the file format if <out> is omitted  \n" +        "\t[See the assimp_cmd docs for a full list of all common parameters]  \n" +        "\t -cfast    Fast post processing preset, runs just a few important steps \n" +        "\t -cdefault Default post processing: runs all recommended steps\n" +        "\t -cfull    Fires almost all post processing steps \n"; + +#define AI_EXTRACT_WRITE_BMP_ALPHA 0x1 +#include <assimp/Compiler/pushpack1.h> + +// ----------------------------------------------------------------------------------- +// Data structure for the first header of a BMP +struct BITMAPFILEHEADER { +    uint16_t bfType; +    uint32_t bfSize; +    uint16_t bfReserved1; +    uint16_t bfReserved2; +    uint32_t bfOffBits; +} PACK_STRUCT; + +// ----------------------------------------------------------------------------------- +// Data structure for the second header of a BMP +struct BITMAPINFOHEADER { +    int32_t biSize; +    int32_t biWidth; +    int32_t biHeight; +    int16_t biPlanes; +    int16_t biBitCount; +    uint32_t biCompression; +    int32_t biSizeImage; +    int32_t biXPelsPerMeter; +    int32_t biYPelsPerMeter; +    int32_t biClrUsed; +    int32_t biClrImportant; + +    // pixel data follows header +} PACK_STRUCT; + +// ----------------------------------------------------------------------------------- +// Data structure for the header of a TGA +struct TGA_HEADER { +    uint8_t identsize; // size of ID field that follows 18 byte header (0 usually) +    uint8_t colourmaptype; // type of colour map 0=none, 1=has palette +    uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=gray,+8=rle packed + +    uint16_t colourmapstart; // first colour map entry in palette +    uint16_t colourmaplength; // number of colors in palette +    uint8_t colourmapbits; // number of bits per palette entry 15,16,24,32 + +    uint16_t xstart; // image x origin +    uint16_t ystart; // image y origin +    uint16_t width; // image width in pixels +    uint16_t height; // image height in pixels +    uint8_t bits; // image bits per pixel 8,16,24,32 +    uint8_t descriptor; // image descriptor bits (vh flip bits) + +    // pixel data follows header +} PACK_STRUCT; + +#include <assimp/Compiler/poppack1.h> + +// ----------------------------------------------------------------------------------- +// Save a texture as bitmap +int SaveAsBMP(FILE *file, const aiTexel *data, unsigned int width, unsigned int height, bool SaveAlpha = false) { +    if (!file || !data) { +        return 1; +    } + +    const unsigned int numc = (SaveAlpha ? 4 : 3); +    unsigned char *buffer = new unsigned char[width * height * numc]; + +    for (unsigned int y = 0; y < height; ++y) { +        for (unsigned int x = 0; x < width; ++x) { + +            unsigned char *s = &buffer[(y * width + x) * numc]; +            const aiTexel *t = &data[y * width + x]; +            s[0] = t->b; +            s[1] = t->g; +            s[2] = t->r; +            if (4 == numc) { +                s[3] = t->a; +            } +        } +    } + +    BITMAPFILEHEADER header; +    header.bfType = 'B' | (int('M') << 8u); +    header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); +    header.bfSize = header.bfOffBits + width * height * numc; +    header.bfReserved1 = header.bfReserved2 = 0; + +    fwrite(&header, sizeof(BITMAPFILEHEADER), 1, file); + +    BITMAPINFOHEADER info; +    info.biSize = 40; +    info.biWidth = width; +    info.biHeight = height; +    info.biPlanes = 1; +    info.biBitCount = (int16_t)numc << 3; +    info.biCompression = 0; +    info.biSizeImage = width * height * numc; +    info.biXPelsPerMeter = 1; // dummy +    info.biYPelsPerMeter = 1; // dummy +    info.biClrUsed = 0; +    info.biClrImportant = 0; + +    fwrite(&info, sizeof(BITMAPINFOHEADER), 1, file); + +    unsigned char *temp = buffer + info.biSizeImage; +    const unsigned int row = width * numc; + +    for (int y = 0; temp -= row, y < info.biHeight; ++y) { +        fwrite(temp, row, 1, file); +    } + +    // delete the buffer +    delete[] buffer; +    return 0; +} + +// ----------------------------------------------------------------------------------- +// Save a texture as tga +int SaveAsTGA(FILE *file, const aiTexel *data, unsigned int width, unsigned int height) { +    if (!file || !data) { +        return 1; +    } + +    TGA_HEADER head; +    memset(&head, 0, sizeof(head)); +    head.bits = 32; +    head.height = (uint16_t)height; +    head.width = (uint16_t)width; +    head.descriptor |= (1u << 5); + +    head.imagetype = 2; // actually it's RGBA +    fwrite(&head, sizeof(TGA_HEADER), 1, file); + +    for (unsigned int y = 0; y < height; ++y) { +        for (unsigned int x = 0; x < width; ++x) { +            fwrite(data + y * width + x, 4, 1, file); +        } +    } + +    return 0; +} + +// ----------------------------------------------------------------------------------- +// Do the texture import for a given aiTexture +int DoExport(const aiTexture *tx, FILE *p, const std::string &extension, unsigned int flags) { +    // export the image to the appropriate decoder +    if (extension == "bmp") { +        SaveAsBMP(p, tx->pcData, tx->mWidth, tx->mHeight, +                (0 != (flags & AI_EXTRACT_WRITE_BMP_ALPHA))); +    } else if (extension == "tga") { +        SaveAsTGA(p, tx->pcData, tx->mWidth, tx->mHeight); +    } else { +        printf("assimp extract: No available texture encoder found for %s\n", extension.c_str()); +        return AssimpCmdExtractError::NoAvailableTextureEncoderFound; +    } +    return AssimpCmdError::Success; +} + +// ----------------------------------------------------------------------------------- +// Implementation of the assimp extract utility +int Assimp_Extract(const char *const *params, unsigned int num) { +    const char *const invalid = "assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n"; +    // assimp extract in out [options] +    if (num < 1) { +        printf(invalid); +        return AssimpCmdError::InvalidNumberOfArguments; +    } + +    // --help +    if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) { +        printf("%s", AICMD_MSG_DUMP_HELP_E); +        return AssimpCmdError::Success; +    } + +    std::string in = std::string(params[0]); +    std::string out = (num > 1 ? std::string(params[1]) : "-"); + +    // get import flags +    ImportData import; +    ProcessStandardArguments(import, params + 1, num - 1); + +    bool nosuffix = false; +    unsigned int texIdx = 0xffffffff, flags = 0; + +    // process other flags +    std::string extension = "bmp"; +    for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num; ++i) { +        if (!params[i]) { +            continue; +        } + +        if (!strncmp(params[i], "-f", 2)) { +            extension = std::string(params[i] + 2); +        } else if (!strncmp(params[i], "--format=", 9)) { +            extension = std::string(params[i] + 9); +        } else if (!strcmp(params[i], "--nosuffix") || !strcmp(params[i], "-s")) { +            nosuffix = true; +        } else if (!strncmp(params[i], "--texture=", 10)) { +            texIdx = Assimp::strtoul10(params[i] + 10); +        } else if (!strncmp(params[i], "-t", 2)) { +            texIdx = Assimp::strtoul10(params[i] + 2); +        } else if (!strcmp(params[i], "-ba") || !strcmp(params[i], "--bmp-with-alpha")) { +            flags |= AI_EXTRACT_WRITE_BMP_ALPHA; +        } +#if 0 +        else { +            printf("Unknown parameter: %s\n",params[i]); +            return 10; +        } +#endif +    } + +    std::transform(extension.begin(), extension.end(), extension.begin(), ai_tolower<char>); + +    if (out[0] == '-') { +        // take file name from input file +        std::string::size_type s = in.find_last_of('.'); +        if (s == std::string::npos) +            s = in.length(); + +        out = in.substr(0, s); +    } + +    // take file extension from file name, if given +    std::string::size_type s = out.find_last_of('.'); +    if (s != std::string::npos) { +        extension = out.substr(s + 1, in.length() - (s + 1)); +        out = out.substr(0, s); +    } + +    // import the main model +    const aiScene *scene = ImportModel(import, in); +    if (!scene) { +        printf("assimp extract: Unable to load input file %s\n", in.c_str()); +        return AssimpCmdError::FailedToLoadInputFile; +    } + +    // get the texture(s) to be exported +    if (texIdx != 0xffffffff) { + +        // check whether the requested texture is existing +        if (texIdx >= scene->mNumTextures) { +            ::printf("assimp extract: Texture %u requested, but there are just %i textures\n", +                    texIdx, scene->mNumTextures); +            return AssimpCmdExtractError::TextureIndexIsOutOfRange; +        } +    } else { +        ::printf("assimp extract: Exporting %i textures\n", scene->mNumTextures); +    } + +    // now write all output textures +    for (unsigned int i = 0; i < scene->mNumTextures; ++i) { +        if (texIdx != 0xffffffff && texIdx != i) { +            continue; +        } + +        const aiTexture *tex = scene->mTextures[i]; +        std::string out_cpy = out, out_ext = extension; + +        // append suffix if necessary - always if all textures are exported +        if (!nosuffix || (texIdx == 0xffffffff)) { +            out_cpy.append("_img"); +            char tmp[10]; +            Assimp::ASSIMP_itoa10(tmp, i); + +            out_cpy.append(std::string(tmp)); +        } + +        // if the texture is a compressed one, we'll export +        // it to its native file format +        if (!tex->mHeight) { +            printf("assimp extract: Texture %u is compressed (%s). Writing native file format.\n", +                    i, tex->achFormatHint); + +            // modify file extension +            out_ext = std::string(tex->achFormatHint); +        } +        out_cpy.append("." + out_ext); + +        // open output file +        FILE *p = ::fopen(out_cpy.c_str(), "wb"); +        if (!p) { +            printf("assimp extract: Unable to open output file %s\n", out_cpy.c_str()); +            return AssimpCmdError::FailedToOpenOutputFile; +        } +        int m; + +        if (!tex->mHeight) { +            m = (1 != fwrite(tex->pcData, tex->mWidth, 1, p)) ? +                        static_cast<int>(AssimpCmdError::Success) : +                        static_cast<int>(AssimpCmdExtractError::FailedToExportCompressedTexture); +        } else { +            m = DoExport(tex, p, extension, flags); +        } +        ::fclose(p); + +        printf("assimp extract: Wrote texture %u to %s\n", i, out_cpy.c_str()); +        if (texIdx != 0xffffffff) { +            return m; +        } +    } + +    return AssimpCmdError::Success; +} diff --git a/libs/assimp/tools/assimp_cmd/Info.cpp b/libs/assimp/tools/assimp_cmd/Info.cpp new file mode 100644 index 0000000..c43a783 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/Info.cpp @@ -0,0 +1,483 @@ +/* +--------------------------------------------------------------------------- +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  Info.cpp + *  @brief Implementation of the 'assimp info' utility  */ + +#include "Main.h" + +#include <cstdio> +#include <iostream> +#include <string> + +const char* AICMD_MSG_INFO_HELP_E = +    "assimp info <file> [-r] [-v]\n" +    "\tPrint basic structure of a 3D model\n" +    "\t-r,--raw: No postprocessing, do a raw import\n" +    "\t-v,--verbose: Print verbose info such as node transform data\n" +    "\t-s, --silent: Print only minimal info\n"; + +const char *TREE_BRANCH_ASCII = "|-"; +const char *TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4"; +const char *TREE_STOP_ASCII = "'-"; +const char *TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4"; +const char *TREE_CONTINUE_ASCII = "| "; +const char *TREE_CONTINUE_UTF8 = "\xe2\x94\x82 "; + +// note: by default this is using utf-8 text. +// this is well supported on pretty much any linux terminal. +// if this causes problems on some platform, +// put an #ifdef to use the ascii version for that platform. +const char *TREE_BRANCH = TREE_BRANCH_UTF8; +const char *TREE_STOP = TREE_STOP_UTF8; +const char *TREE_CONTINUE = TREE_CONTINUE_UTF8; + +// ----------------------------------------------------------------------------------- +unsigned int CountNodes(const aiNode* root) +{ +	unsigned int i = 0; +	for (unsigned int a = 0; a < root->mNumChildren; ++a ) { +		i += CountNodes(root->mChildren[a]); +	} +	return 1+i; +} + +// ----------------------------------------------------------------------------------- +unsigned int GetMaxDepth(const aiNode* root) +{ +	unsigned int cnt = 0; +	for (unsigned int i = 0; i < root->mNumChildren; ++i ) { +		cnt = std::max(cnt,GetMaxDepth(root->mChildren[i])); +	} +	return cnt+1; +} + +// ----------------------------------------------------------------------------------- +unsigned int CountVertices(const aiScene* scene) +{ +	unsigned int cnt = 0; +	for(unsigned int i = 0; i < scene->mNumMeshes; ++i) { +		cnt += scene->mMeshes[i]->mNumVertices; +	} +	return cnt; +} + +// ----------------------------------------------------------------------------------- +unsigned int CountFaces(const aiScene* scene) +{ +	unsigned int cnt = 0; +	for(unsigned int i = 0; i < scene->mNumMeshes; ++i) { +		cnt += scene->mMeshes[i]->mNumFaces; +	} +	return cnt; +} + +// ----------------------------------------------------------------------------------- +unsigned int CountBones(const aiScene* scene) +{ +	unsigned int cnt = 0; +	for(unsigned int i = 0; i < scene->mNumMeshes; ++i) { +		cnt += scene->mMeshes[i]->mNumBones; +	} +	return cnt; +} + +// ----------------------------------------------------------------------------------- +unsigned int CountAnimChannels(const aiScene* scene) +{ +	unsigned int cnt = 0; +	for(unsigned int i = 0; i < scene->mNumAnimations; ++i) { +		cnt += scene->mAnimations[i]->mNumChannels; +	} +	return cnt; +} + +// ----------------------------------------------------------------------------------- +unsigned int GetAvgFacePerMesh(const aiScene* scene) { +	return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene)/scene->mNumMeshes) : 0; +} + +// ----------------------------------------------------------------------------------- +unsigned int GetAvgVertsPerMesh(const aiScene* scene) { +	return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene)/scene->mNumMeshes) : 0; +} + +// ----------------------------------------------------------------------------------- +void FindSpecialPoints(const aiScene* scene,const aiNode* root,aiVector3D special_points[3],const aiMatrix4x4& mat=aiMatrix4x4()) +{ +	// XXX that could be greatly simplified by using code from code/ProcessHelper.h +	// XXX I just don't want to include it here. +	const aiMatrix4x4 trafo = root->mTransformation*mat; +	for(unsigned int i = 0; i < root->mNumMeshes; ++i) { +		const aiMesh* mesh = scene->mMeshes[root->mMeshes[i]]; + +		for(unsigned int a = 0; a < mesh->mNumVertices; ++a) { +			aiVector3D v = trafo*mesh->mVertices[a]; + +			special_points[0].x = std::min(special_points[0].x,v.x); +			special_points[0].y = std::min(special_points[0].y,v.y); +			special_points[0].z = std::min(special_points[0].z,v.z); + +			special_points[1].x = std::max(special_points[1].x,v.x); +			special_points[1].y = std::max(special_points[1].y,v.y); +			special_points[1].z = std::max(special_points[1].z,v.z); +		} +	} + +	for(unsigned int i = 0; i < root->mNumChildren; ++i) { +		FindSpecialPoints(scene,root->mChildren[i],special_points,trafo); +	} +} + +// ----------------------------------------------------------------------------------- +void FindSpecialPoints(const aiScene* scene,aiVector3D special_points[3]) +{ +	special_points[0] = aiVector3D(1e10,1e10,1e10); +	special_points[1] = aiVector3D(-1e10,-1e10,-1e10); + +	FindSpecialPoints(scene,scene->mRootNode,special_points); +	special_points[2] = (special_points[0]+special_points[1])*(ai_real)0.5; +} + +// ----------------------------------------------------------------------------------- +std::string FindPTypes(const aiScene* scene) +{ +	bool haveit[4] = {0}; +	for(unsigned int i = 0; i < scene->mNumMeshes; ++i) { +		const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes; +		if (pt & aiPrimitiveType_POINT) { +			haveit[0]=true; +		} +		if (pt & aiPrimitiveType_LINE) { +			haveit[1]=true; +		} +		if (pt & aiPrimitiveType_TRIANGLE) { +			haveit[2]=true; +		} +		if (pt & aiPrimitiveType_POLYGON) { +			haveit[3]=true; +		} +	} +	return (haveit[0]?std::string("points"):"")+(haveit[1]?"lines":"")+ +		(haveit[2]?"triangles":"")+(haveit[3]?"n-polygons":""); +} + +// ----------------------------------------------------------------------------------- +// Prettily print the node graph to stdout +void PrintHierarchy( +	const aiNode* node, +	const std::string &indent, +	bool verbose, +	bool last = false, +	bool first = true +){ +	// tree visualization +	std::string branchchar; +	if (first) { branchchar = ""; } +	else if (last) { branchchar = TREE_STOP; } // "'-" +	else { branchchar = TREE_BRANCH; } // "|-" + +	// print the indent and the branch character and the name +	std::cout << indent << branchchar << node->mName.C_Str(); + +	// if there are meshes attached, indicate this +	if (node->mNumMeshes) { +		std::cout << " (mesh "; +		bool sep = false; +		for (size_t i=0; i < node->mNumMeshes; ++i) { +			unsigned int mesh_index = node->mMeshes[i]; +			if (sep) { std::cout << ", "; } +			std::cout << mesh_index; +			sep = true; +		} +		std::cout << ")"; +	} + +	// finish the line +	std::cout << std::endl; + +	// in verbose mode, print the transform data as well +	if (verbose) { +		// indent to use +		std::string indentadd; +		if (last) { indentadd += "  "; } +		else { indentadd += TREE_CONTINUE; } // "| ".. +		if (node->mNumChildren == 0) { indentadd += "  "; } +		else { indentadd += TREE_CONTINUE; } // .."| " +		aiVector3D s, r, t; +		node->mTransformation.Decompose(s, r, t); +		if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) { +			std::cout << indent << indentadd; +			printf("  S:[%f %f %f]\n", s.x, s.y, s.z); +		} +		if (r.x || r.y || r.z) { +			std::cout << indent << indentadd; +			printf("  R:[%f %f %f]\n", r.x, r.y, r.z); +		} +		if (t.x || t.y || t.z) { +			std::cout << indent << indentadd; +			printf("  T:[%f %f %f]\n", t.x, t.y, t.z); +		} +	} + +	// and recurse +	std::string nextIndent; +	if (first) { nextIndent = indent; } +	else if (last) { nextIndent = indent + "  "; } +	else { nextIndent = indent + TREE_CONTINUE; } // "| " +	for (size_t i = 0; i < node->mNumChildren; ++i) { +		bool lastone = (i == node->mNumChildren - 1); +		PrintHierarchy( +			node->mChildren[i], +			nextIndent, +			verbose, +			lastone, +			false +		); +	} +} + +// ----------------------------------------------------------------------------------- +// Implementation of the assimp info utility to print basic file info +int Assimp_Info (const char* const* params, unsigned int num) { +	// --help +	if (!strcmp( params[0],"-h")||!strcmp( params[0],"--help")||!strcmp( params[0],"-?") ) { +		printf("%s",AICMD_MSG_INFO_HELP_E); +		return AssimpCmdError::Success; +	} + +	// asssimp info <file> [-r] +	if (num < 1) { +		printf("assimp info: Invalid number of arguments. " +			"See \'assimp info --help\'\n"); +		return AssimpCmdError::InvalidNumberOfArguments; +	} + +	const std::string in  = std::string(params[0]); + +	// get -r and -v arguments +	bool raw = false; +	bool verbose = false; +	bool silent = false; +	for(unsigned int i = 1; i < num; ++i) { +		if (!strcmp(params[i],"--raw")||!strcmp(params[i],"-r")) { +			raw = true; +		} +		if (!strcmp(params[i],"--verbose")||!strcmp(params[i],"-v")) { +			verbose = true; +		} +		if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) { +			silent = true; +		} +	} + +	// Verbose and silent at the same time are not allowed +	if ( verbose && silent ) { +		printf("assimp info: Invalid arguments, verbose and silent at the same time are forbidden. "); +		return AssimpCmdInfoError::InvalidCombinaisonOfArguments; +	} + +	// Parse post-processing flags unless -r was specified +	ImportData import; +	if (!raw) { +		// get import flags +		ProcessStandardArguments(import, params + 1, num - 1); + +		//No custom post process flags defined, we set all the post process flags active +		if(import.ppFlags == 0) +			import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; +	} + +	// import the main model +	const aiScene* scene = ImportModel(import,in); +	if (!scene) { +		printf("assimp info: Unable to load input file %s\n", +			in.c_str()); +		return AssimpCmdError::FailedToLoadInputFile; +	} + +	aiMemoryInfo mem; +	globalImporter->GetMemoryRequirements(mem); + + +	static const char* format_string = +		"Memory consumption: %i B\n" +		"Nodes:              %i\n" +		"Maximum depth       %i\n" +		"Meshes:             %i\n" +		"Animations:         %i\n" +		"Textures (embed.):  %i\n" +		"Materials:          %i\n" +		"Cameras:            %i\n" +		"Lights:             %i\n" +		"Vertices:           %i\n" +		"Faces:              %i\n" +		"Bones:              %i\n" +		"Animation Channels: %i\n" +		"Primitive Types:    %s\n" +		"Average faces/mesh  %i\n" +		"Average verts/mesh  %i\n" +		"Minimum point      (%f %f %f)\n" +		"Maximum point      (%f %f %f)\n" +		"Center point       (%f %f %f)\n" + +		; + +	aiVector3D special_points[3]; +	FindSpecialPoints(scene,special_points); +	printf(format_string, +		mem.total, +		CountNodes(scene->mRootNode), +		GetMaxDepth(scene->mRootNode), +		scene->mNumMeshes, +		scene->mNumAnimations, +		scene->mNumTextures, +		scene->mNumMaterials, +		scene->mNumCameras, +		scene->mNumLights, +		CountVertices(scene), +		CountFaces(scene), +		CountBones(scene), +		CountAnimChannels(scene), +		FindPTypes(scene).c_str(), +		GetAvgFacePerMesh(scene), +		GetAvgVertsPerMesh(scene), +		special_points[0][0],special_points[0][1],special_points[0][2], +		special_points[1][0],special_points[1][1],special_points[1][2], +		special_points[2][0],special_points[2][1],special_points[2][2] +		) +	; + +	if (silent) +	{ +		printf("\n"); +		return AssimpCmdError::Success; +	} + +	// meshes +	if (scene->mNumMeshes) { +		printf("\nMeshes:  (name) [vertices / bones / faces | primitive_types]\n"); +	} +	for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { +		const aiMesh* mesh = scene->mMeshes[i]; +		printf("    %d (%s)", i, mesh->mName.C_Str()); +		printf( +			": [%d / %d / %d |", +			mesh->mNumVertices, +			mesh->mNumBones, +			mesh->mNumFaces +		); +		const unsigned int ptypes = mesh->mPrimitiveTypes; +		if (ptypes & aiPrimitiveType_POINT) { printf(" point"); } +		if (ptypes & aiPrimitiveType_LINE) { printf(" line"); } +		if (ptypes & aiPrimitiveType_TRIANGLE) { printf(" triangle"); } +		if (ptypes & aiPrimitiveType_POLYGON) { printf(" polygon"); } +		printf("]\n"); +	} + +	// materials +	unsigned int total=0; +	for(unsigned int i = 0;i < scene->mNumMaterials; ++i) { +		aiString name; +		if (AI_SUCCESS==aiGetMaterialString(scene->mMaterials[i],AI_MATKEY_NAME,&name)) { +			printf("%s\n    \'%s\'",(total++?"":"\nNamed Materials:" ),name.data); +		} +	} +	if(total) { +		printf("\n"); +	} + +	// textures +	total=0; +	for(unsigned int i = 0;i < scene->mNumMaterials; ++i) { +		aiString name; +		static const aiTextureType types[] = { +			aiTextureType_NONE, +			aiTextureType_DIFFUSE, +			aiTextureType_SPECULAR, +			aiTextureType_AMBIENT, +			aiTextureType_EMISSIVE, +			aiTextureType_HEIGHT, +			aiTextureType_NORMALS, +			aiTextureType_SHININESS, +			aiTextureType_OPACITY, +			aiTextureType_DISPLACEMENT, +			aiTextureType_LIGHTMAP, +			aiTextureType_REFLECTION, +			aiTextureType_BASE_COLOR, +			aiTextureType_NORMAL_CAMERA, +			aiTextureType_EMISSION_COLOR, +			aiTextureType_METALNESS, +			aiTextureType_DIFFUSE_ROUGHNESS, +			aiTextureType_AMBIENT_OCCLUSION, +			aiTextureType_UNKNOWN +		}; +		for(unsigned int type = 0; type < sizeof(types)/sizeof(types[0]); ++type) { +			for(unsigned int idx = 0;AI_SUCCESS==aiGetMaterialString(scene->mMaterials[i], +				AI_MATKEY_TEXTURE(types[type],idx),&name); ++idx) { +				printf("%s\n    \'%s\'",(total++?"":"\nTexture Refs:" ),name.data); +			} +		} +	} +	if(total) { +		printf("\n"); +	} + +	// animations +	total=0; +	for(unsigned int i = 0;i < scene->mNumAnimations; ++i) { +		if (scene->mAnimations[i]->mName.length) { +			printf("%s\n     \'%s\'",(total++?"":"\nNamed Animations:" ),scene->mAnimations[i]->mName.data); +		} +	} +	if(total) { +		printf("\n"); +	} + +	// node hierarchy +	printf("\nNode hierarchy:\n"); +	PrintHierarchy(scene->mRootNode,"",verbose); + +	printf("\n"); +	return AssimpCmdError::Success; +} diff --git a/libs/assimp/tools/assimp_cmd/Main.cpp b/libs/assimp/tools/assimp_cmd/Main.cpp new file mode 100644 index 0000000..31b92b0 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/Main.cpp @@ -0,0 +1,564 @@ +/* +--------------------------------------------------------------------------- +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  Main.cpp + *  @brief main() function of assimp_cmd + */ + +#include "Main.h" + +#include <assimp/ProgressHandler.hpp> +#include <iostream> + +class ConsoleProgressHandler : public ProgressHandler { +public: +	ConsoleProgressHandler() : +			ProgressHandler() { +		// empty +	} + +	~ConsoleProgressHandler() override { +		// empty +	} + +	bool Update(float percentage) override { +        std::cout << percentage * 100.0f << " %\n"; +		return true; +    } +}; +const char* AICMD_MSG_ABOUT = +"------------------------------------------------------ \n" +"Open Asset Import Library (\"Assimp\", https://github.com/assimp/assimp) \n" +" -- Commandline toolchain --\n" +"------------------------------------------------------ \n\n" + +"Version %i.%i %s%s%s%s%s(GIT commit %x)\n\n"; + +const char* AICMD_MSG_HELP = +"assimp <verb> <parameters>\n\n" +" verbs:\n" +" \tinfo       - Quick file stats\n" +" \tlistext    - List all known file extensions available for import\n" +" \tknowext    - Check whether a file extension is recognized by Assimp\n" +#ifndef ASSIMP_BUILD_NO_EXPORT +" \texport     - Export a file to one of the supported output formats\n" +" \tlistexport - List all supported export formats\n" +" \texportinfo - Show basic information on a specific export format\n" +#endif +" \textract    - Extract embedded texture images\n" +" \tdump       - Convert models to a binary or textual dump (ASSBIN/ASSXML)\n" +" \tcmpdump    - Compare dumps created using \'assimp dump <file> -s ...\'\n" +" \tversion    - Display Assimp version\n" +"\n Use \'assimp <verb> --help\' for detailed help on a command.\n" +; + +/*extern*/ Assimp::Importer* globalImporter = nullptr; + +#ifndef ASSIMP_BUILD_NO_EXPORT +/*extern*/ Assimp::Exporter* globalExporter = nullptr; +#endif + +// ------------------------------------------------------------------------------ +// Application entry point +int main (int argc, char* argv[]) +{ +	if (argc <= 1)	{ +		printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n"); +		return AssimpCmdError::Success; +	} + +	// assimp version +	// Display version information +	if (! strcmp(argv[1], "version")) { +		const unsigned int flags = aiGetCompileFlags(); +		printf(AICMD_MSG_ABOUT, +			aiGetVersionMajor(), +			aiGetVersionMinor(), +			(flags & ASSIMP_CFLAGS_DEBUG ?			"-debug "   : ""), +			(flags & ASSIMP_CFLAGS_NOBOOST ?		"-noboost " : ""), +			(flags & ASSIMP_CFLAGS_SHARED ?			"-shared "  : ""), +			(flags & ASSIMP_CFLAGS_SINGLETHREADED ? "-st "      : ""), +			(flags & ASSIMP_CFLAGS_STLPORT ?		"-stlport " : ""), +			aiGetVersionRevision()); + +		return AssimpCmdError::Success; +	} + +	// assimp help +	// Display some basic help (--help and -h work as well +	// because people could try them intuitively) +	if (!strcmp(argv[1], "help") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { +		printf("%s",AICMD_MSG_HELP); +		return AssimpCmdError::Success; +	} + +	// assimp cmpdump +	// Compare two mini model dumps (regression suite) +	if (! strcmp(argv[1], "cmpdump")) { +		return Assimp_CompareDump (&argv[2],argc-2); +	} + +	// construct global importer and exporter instances +	Assimp::Importer imp; +	imp.SetPropertyBool("GLOB_MEASURE_TIME",true); +	globalImporter = &imp; + +#ifndef ASSIMP_BUILD_NO_EXPORT +	// +	Assimp::Exporter exp; +	globalExporter = &exp; +#endif + +	// assimp listext +	// List all file extensions supported by Assimp +	if (! strcmp(argv[1], "listext")) { +		aiString s; +		imp.GetExtensionList(s); + +		printf("%s\n",s.data); +		return AssimpCmdError::Success; +	} + +#ifndef ASSIMP_BUILD_NO_EXPORT +	// assimp listexport +	// List all export file formats supported by Assimp (not the file extensions, just the format identifiers!) +	if (! strcmp(argv[1], "listexport")) { +		aiString s; + +		for(size_t i = 0, end = exp.GetExportFormatCount(); i < end; ++i) { +			const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i); +			s.Append( e->id ); +			if (i!=end-1) { +				s.Append("\n"); +			} +		} + +		printf("%s\n",s.data); +		return AssimpCmdError::Success; +	} + + +	// assimp exportinfo +	// stat an export format +	if (! strcmp(argv[1], "exportinfo")) { +		aiString s; + +		if (argc<3) { +			printf("Expected file format id\n"); +			return AssimpCmdError::NoFileFormatSpecified; +		} + +		for(size_t i = 0, end = exp.GetExportFormatCount(); i < end; ++i) { +			const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i); +			if (!strcmp(e->id,argv[2])) { +				printf("%s\n%s\n%s\n",e->id,e->fileExtension,e->description); +				return AssimpCmdError::Success; +			} +		} + +		printf("Unknown file format id: \'%s\'\n",argv[2]); +		return AssimpCmdError::UnknownFileFormat; +	} + +	// assimp export +	// Export a model to a file +	if (! strcmp(argv[1], "export")) { +		return Assimp_Export (&argv[2],argc-2); +	} + +#endif + +	// assimp knowext +	// Check whether a particular file extension is known by us, return 0 on success +	if (! strcmp(argv[1], "knowext")) { +		if (argc<3) { +			printf("Expected file extension"); +			return AssimpCmdError::NoFileExtensionSpecified; +		} +		const bool b = imp.IsExtensionSupported(argv[2]); +		printf("File extension \'%s\'  is %sknown\n",argv[2],(b?"":"not ")); +		return b? AssimpCmdError::Success : AssimpCmdError::UnknownFileExtension; +	} + +	// assimp info +	// Print basic model statistics +	if (! strcmp(argv[1], "info")) { +		return Assimp_Info ((const char**)&argv[2],argc-2); +	} + +	// assimp dump +	// Dump a model to a file +	if (! strcmp(argv[1], "dump")) { +		return Assimp_Dump (&argv[2],argc-2); +	} + +	// assimp extract +	// Extract an embedded texture from a file +	if (! strcmp(argv[1], "extract")) { +		return Assimp_Extract (&argv[2],argc-2); +	} + +	// assimp testbatchload +	// Used by /test/other/streamload.py to load a list of files +	// using the same importer instance to check for incompatible +	// importers. +	if (! strcmp(argv[1], "testbatchload")) { +		return Assimp_TestBatchLoad (&argv[2],argc-2); +	} + +	printf("Unrecognized command. Use \'assimp help\' for a detailed command list\n"); +	return AssimpCmdError::UnrecognizedCommand; +} + + +// ------------------------------------------------------------------------------ +void SetLogStreams(const ImportData& imp) +{ +	printf("\nAttaching log stream   ...           OK\n"); + +	unsigned int flags = 0; +	if (imp.logFile.length()) { +		flags |= aiDefaultLogStream_FILE; +	} +	if (imp.showLog) { +		flags |= aiDefaultLogStream_STDERR; +	} +	DefaultLogger::create(imp.logFile.c_str(),imp.verbose ? Logger::VERBOSE : Logger::NORMAL,flags); +} + + +// ------------------------------------------------------------------------------ +void FreeLogStreams() +{ +	DefaultLogger::kill(); +} + + +// ------------------------------------------------------------------------------ +void PrintHorBar() +{ +	printf("-----------------------------------------------------------------\n"); +} + +// ------------------------------------------------------------------------------ +// Import a specific file +const aiScene* ImportModel( +	const ImportData& imp, +	const std::string& path) +{ +	// Attach log streams +	if (imp.log) { +		SetLogStreams(imp); +	} +	printf("Launching asset import ...           OK\n"); + +	// Now validate this flag combination +	if(!globalImporter->ValidateFlags(imp.ppFlags)) { +		printf("ERROR: Unsupported post-processing flags \n"); +		return NULL; +	} +	printf("Validating postprocessing flags ...  OK\n"); +	if (imp.showLog) { +		PrintHorBar(); +	} + + +	// do the actual import, measure time +	const clock_t first = clock(); +    ConsoleProgressHandler *ph = new ConsoleProgressHandler; +    globalImporter->SetProgressHandler(ph); +     +	const aiScene* scene = globalImporter->ReadFile(path,imp.ppFlags); + +	if (imp.showLog) { +		PrintHorBar(); +	} +	if (!scene) { +		printf("ERROR: Failed to load file: %s\n", globalImporter->GetErrorString()); +		return NULL; +	} + +	const clock_t second = ::clock(); +	const double seconds = static_cast<double>(second-first) / CLOCKS_PER_SEC; + +	printf("Importing file ...                   OK \n   import took approx. %.5f seconds\n" +		"\n",seconds); + +	if (imp.log) { +		FreeLogStreams(); +	} +    globalImporter->SetProgressHandler(nullptr); +    delete ph; + +	return scene; +} + +#ifndef ASSIMP_BUILD_NO_EXPORT +// ------------------------------------------------------------------------------ +bool ExportModel(const aiScene* pOut, +	const ImportData& imp, +	const std::string& path, +	const char* pID) +{ +	// Attach log streams +	if (imp.log) { +		SetLogStreams(imp); +	} +	printf("Launching asset export ...           OK\n"); + +	if (imp.showLog) { +		PrintHorBar(); +	} + +	aiMatrix4x4 rx, ry, rz; +    aiMatrix4x4::RotationX(imp.rot.x, rx); +    aiMatrix4x4::RotationY(imp.rot.y, ry); +    aiMatrix4x4::RotationZ(imp.rot.z, rz); +	pOut->mRootNode->mTransformation *= rx; +    pOut->mRootNode->mTransformation *= ry; +    pOut->mRootNode->mTransformation *= rz; + +	// do the actual export, measure time +	const clock_t first = clock(); +	const aiReturn res = globalExporter->Export(pOut,pID,path); + +	if (imp.showLog) { +		PrintHorBar(); +	} +	if (res != AI_SUCCESS) { +		printf("Failed to write file\n"); +		printf("ERROR: %s\n", globalExporter->GetErrorString()); +		return false; +	} + +	const clock_t second = ::clock(); +	const double seconds = static_cast<double>(second-first) / CLOCKS_PER_SEC; + +	printf("Exporting file ...                   OK \n   export took approx. %.5f seconds\n" +		"\n",seconds); + +	if (imp.log) { +		FreeLogStreams(); +	} + +	return true; +} +#endif + +// ------------------------------------------------------------------------------ +// Process standard arguments +int ProcessStandardArguments( +	ImportData& fill, +	const char* const * params, +	unsigned int num) +{ +	// -ptv    --pretransform-vertices +	// -gsn    --gen-smooth-normals +	// -gn     --gen-normals +	// -cts    --calc-tangent-space +	// -jiv    --join-identical-vertices +	// -rrm    --remove-redundant-materials +	// -fd     --find-degenerates +	// -slm    --split-large-meshes +	// -lbw    --limit-bone-weights +	// -vds    --validate-data-structure +	// -icl    --improve-cache-locality +	// -sbpt   --sort-by-ptype +	// -lh     --convert-to-lh +	// -fuv    --flip-uv +	// -fwo    --flip-winding-order +	// -tuv    --transform-uv-coords +	// -guv    --gen-uvcoords +	// -fid    --find-invalid-data +	// -fixn   --fix normals +	// -tri    --triangulate +	// -fi     --find-instances +	// -og     --optimize-graph +	// -om     --optimize-meshes +	// -db     --debone +	// -sbc    --split-by-bone-count +	// -gs	   --global-scale +	// +	// -c<file> --config-file=<file> + +	for (unsigned int i = 0; i < num;++i) +	{ +        const char *param = params[ i ]; +        printf( "param = %s\n", param ); +		if (! strcmp( param, "-ptv") || ! strcmp( param, "--pretransform-vertices")) { +			fill.ppFlags |= aiProcess_PreTransformVertices; +		} +		else if (! strcmp( param, "-gsn") || ! strcmp( param, "--gen-smooth-normals")) { +			fill.ppFlags |= aiProcess_GenSmoothNormals; +		} +    else if (! strcmp( param, "-dn") || ! strcmp( param, "--drop-normals")) { +			fill.ppFlags |= aiProcess_DropNormals; +		} +		else if (! strcmp( param, "-gn") || ! strcmp( param, "--gen-normals")) { +			fill.ppFlags |= aiProcess_GenNormals; +		} +		else if (! strcmp( param, "-jiv") || ! strcmp( param, "--join-identical-vertices")) { +			fill.ppFlags |= aiProcess_JoinIdenticalVertices; +		} +		else if (! strcmp( param, "-rrm") || ! strcmp( param, "--remove-redundant-materials")) { +			fill.ppFlags |= aiProcess_RemoveRedundantMaterials; +		} +		else if (! strcmp( param, "-fd") || ! strcmp( param, "--find-degenerates")) { +			fill.ppFlags |= aiProcess_FindDegenerates; +		} +		else if (! strcmp( param, "-slm") || ! strcmp( param, "--split-large-meshes")) { +			fill.ppFlags |= aiProcess_SplitLargeMeshes; +		} +		else if (! strcmp( param, "-lbw") || ! strcmp( param, "--limit-bone-weights")) { +			fill.ppFlags |= aiProcess_LimitBoneWeights; +		} +		else if (! strcmp( param, "-vds") || ! strcmp( param, "--validate-data-structure")) { +			fill.ppFlags |= aiProcess_ValidateDataStructure; +		} +		else if (! strcmp( param, "-icl") || ! strcmp( param, "--improve-cache-locality")) { +			fill.ppFlags |= aiProcess_ImproveCacheLocality; +		} +		else if (! strcmp( param, "-sbpt") || ! strcmp( param, "--sort-by-ptype")) { +			fill.ppFlags |= aiProcess_SortByPType; +		} +		else if (! strcmp( param, "-lh") || ! strcmp( param, "--left-handed")) { +			fill.ppFlags |= aiProcess_ConvertToLeftHanded; +		} +		else if (! strcmp( param, "-fuv") || ! strcmp( param, "--flip-uv")) { +			fill.ppFlags |= aiProcess_FlipUVs; +		} +		else if (! strcmp( param, "-fwo") || ! strcmp( param, "--flip-winding-order")) { +			fill.ppFlags |= aiProcess_FlipWindingOrder; +		} +		else if (! strcmp( param, "-tuv") || ! strcmp( param, "--transform-uv-coords")) { +			fill.ppFlags |= aiProcess_TransformUVCoords; +		} +		else if (! strcmp( param, "-guv") || ! strcmp( param, "--gen-uvcoords")) { +			fill.ppFlags |= aiProcess_GenUVCoords; +		} +		else if (! strcmp( param, "-fid") || ! strcmp( param, "--find-invalid-data")) { +			fill.ppFlags |= aiProcess_FindInvalidData; +		} +		else if (! strcmp( param, "-fixn") || ! strcmp( param, "--fix-normals")) { +			fill.ppFlags |= aiProcess_FixInfacingNormals; +		} +		else if (! strcmp( param, "-tri") || ! strcmp( param, "--triangulate")) { +			fill.ppFlags |= aiProcess_Triangulate; +		} +		else if (! strcmp( param, "-cts") || ! strcmp( param, "--calc-tangent-space")) { +			fill.ppFlags |= aiProcess_CalcTangentSpace; +		} +		else if (! strcmp( param, "-fi") || ! strcmp( param, "--find-instances")) { +			fill.ppFlags |= aiProcess_FindInstances; +		} +		else if (! strcmp( param, "-og") || ! strcmp( param, "--optimize-graph")) { +			fill.ppFlags |= aiProcess_OptimizeGraph; +		} +		else if (! strcmp( param, "-om") || ! strcmp( param, "--optimize-meshes")) { +			fill.ppFlags |= aiProcess_OptimizeMeshes; +		} +		else if (! strcmp( param, "-db") || ! strcmp( param, "--debone")) { +			fill.ppFlags |= aiProcess_Debone; +		} +		else if (! strcmp( param, "-sbc") || ! strcmp( param, "--split-by-bone-count")) { +			fill.ppFlags |= aiProcess_SplitByBoneCount; +		} +		else if (!strcmp(param, "-embtex") || ! strcmp(param, "--embed-textures")) { +			fill.ppFlags |= aiProcess_EmbedTextures; +		} +		else if (!strcmp(param, "-gs") || ! strcmp(param, "--global-scale")) { +			fill.ppFlags |= aiProcess_GlobalScale; +		} +		else if (! strncmp( param, "-c",2) || ! strncmp( param, "--config=",9)) { +			const unsigned int ofs = (params[i][1] == '-' ? 9 : 2); + +			// use default configurations +            if (!strncmp( param + ofs, "full", 4 )) { +                fill.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; +            } else if (!strncmp( param + ofs, "default", 7 )) { +				fill.ppFlags |= aiProcessPreset_TargetRealtime_Quality; +			} else if (! strncmp( param +ofs,"fast",4)) { +				fill.ppFlags |= aiProcessPreset_TargetRealtime_Fast; +			} +		} else if (! strcmp( param, "-l") || ! strcmp( param, "--show-log")) { +			fill.showLog = true; +		} +		else if (! strcmp( param, "-v") || ! strcmp( param, "--verbose")) { +			fill.verbose = true; +		} +		else if (!strncmp(params[i], "-rx=", 4) || !strncmp(params[i], "--rotation-x=", 13)) { +            std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4)); +            fill.rot.x = std::stof(value); +		} +		else if (!strncmp(params[i], "-ry=", 4) || !strncmp(params[i], "--rotation-y=", 13)) { +            std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4)); +            fill.rot.y = std::stof(value); +        } +		else if (!strncmp(params[i], "-rz=", 4) || !strncmp(params[i], "--rotation-z=", 13)) { +            std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4)); +            fill.rot.z = std::stof(value); +        } +		else if (! strncmp( param, "--log-out=",10) || ! strncmp( param, "-lo",3)) { +			fill.logFile = std::string(params[i]+(params[i][1] == '-' ? 10 : 3)); +			if (!fill.logFile.length()) { +				fill.logFile = "assimp-log.txt"; +			} +		} +	} + +	if (fill.logFile.length() || fill.showLog || fill.verbose) { +		fill.log = true; +	} + +	return AssimpCmdError::Success; +} + +// ------------------------------------------------------------------------------ +int Assimp_TestBatchLoad ( +	const char* const* params, +	unsigned int num) +{ +	for(unsigned int i = 0; i < num; ++i) { +		globalImporter->ReadFile(params[i],aiProcessPreset_TargetRealtime_MaxQuality); +		// we're totally silent. scene destructs automatically. +	} +	return AssimpCmdError::Success; +} diff --git a/libs/assimp/tools/assimp_cmd/Main.h b/libs/assimp/tools/assimp_cmd/Main.h new file mode 100644 index 0000000..1d3dd8f --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/Main.h @@ -0,0 +1,273 @@ +/* +--------------------------------------------------------------------------- +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  Main.h + *  @brief Utility declarations for assimp_cmd + */ + +#ifndef AICMD_MAIN_INCLUDED +#define AICMD_MAIN_INCLUDED + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <limits> + +#include <assimp/postprocess.h> +#include <assimp/version.h> +#include <assimp/scene.h> +#include <assimp/Importer.hpp> +#include <assimp/DefaultLogger.hpp> + +#ifndef ASSIMP_BUILD_NO_EXPORT +#	include <assimp/Exporter.hpp> +#endif + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +#include <zlib.h> +#else +#include <../contrib/zlib/zlib.h> +#endif + + +#ifndef SIZE_MAX +#	define SIZE_MAX (std::numeric_limits<size_t>::max()) +#endif + + +using namespace Assimp; + + +// Global assimp importer instance +extern Assimp::Importer* globalImporter; + +#ifndef ASSIMP_BUILD_NO_EXPORT +// Global assimp exporter instance +extern Assimp::Exporter* globalExporter; +#endif + +// ------------------------------------------------------------------------------ +/// Defines common import parameters +struct ImportData { +	ImportData() +		:	ppFlags	(0) +		,	showLog (false) +		,	verbose (false) +		,	log	    (false) +        ,   rot     (aiVector3D(0.f, 0.f, 0.f)) +	{} + +	/// Post-processing flags +	unsigned int ppFlags; + +	// Log to std::err? +	bool showLog; + +	// Log file +	std::string logFile; + +	// Verbose log mode? +	bool verbose; + +	// Need to log? +	bool log; + +	// Export With Rotation +	aiVector3D rot; +}; + +/// \enum AssimpCmdError +/// \brief General error codes used among assimp_cmd's utilities. +enum AssimpCmdError { +	Success = 0, +	InvalidNumberOfArguments, +	UnrecognizedCommand, +	FailedToLoadInputFile, +	FailedToOpenOutputFile, +	NoFileFormatSpecified, +	UnknownFileFormat, +	NoFileExtensionSpecified, +	UnknownFileExtension, +	ExceptionWasRaised, + +	// Add new error codes here... + +	LastAssimpCmdError, // Must be last. +}; + +// ------------------------------------------------------------------------------ +/** Process standard arguments + * + *  @param fill Filled by function + *  @param params Command line parameters to be processed + *  @param num NUmber of params + *  @return An #AssimpCmdError value. */ +int ProcessStandardArguments(ImportData& fill, +	const char* const* params, +	unsigned int num); + +// ------------------------------------------------------------------------------ +/** Import a specific model file + *  @param imp Import configuration to be used + *  @param path Path to the file to be read */ +const aiScene* ImportModel( +	const ImportData& imp, +	const std::string& path); + +#ifndef ASSIMP_BUILD_NO_EXPORT + +// ------------------------------------------------------------------------------ +/** Export a specific model file + *  @param imp Import configuration to be used + *  @param path Path to the file to be written + *  @param format Format id*/ +bool ExportModel(const aiScene* pOut, +	const ImportData& imp, +	const std::string& path, +	const char* pID); + +#endif + +// ------------------------------------------------------------------------------ +/** assimp_dump utility + *  @param params Command line parameters to 'assimp dump' + *  @param Number of params + *  @return An #AssimpCmdError value.*/ +int Assimp_Dump ( +	const char* const* params, +	unsigned int num); + +/// \enum AssimpCmdExportError +/// \brief Error codes used by the 'Export' utility. +enum AssimpCmdExportError { +	FailedToImportModel = AssimpCmdError::LastAssimpCmdError, +	FailedToExportModel, + +	// Add new error codes here... + +	LastAssimpCmdExportError, // Must be last. +}; + +// ------------------------------------------------------------------------------ +/** assimp_export utility + *  @param params Command line parameters to 'assimp export' + *  @param Number of params + *  @return Either an #AssimpCmdError or #AssimpCmdExportError value. */ +int Assimp_Export ( +	const char* const* params, +	unsigned int num); + +/// \enum AssimpCmdExtractError +/// \brief Error codes used by the 'Image Extractor' utility. +enum AssimpCmdExtractError { +	TextureIndexIsOutOfRange = AssimpCmdError::LastAssimpCmdError, +	NoAvailableTextureEncoderFound, +	FailedToExportCompressedTexture, + +	// Add new error codes here... + +	LastAssimpCmdExtractError, // Must be last. +}; + +// ------------------------------------------------------------------------------ +/** assimp_extract utility + *  @param params Command line parameters to 'assimp extract' + *  @param Number of params + *  @return Either an #AssimpCmdError or #AssimpCmdExtractError value. */ +int Assimp_Extract ( +	const char* const* params, +	unsigned int num); + +/// \enum AssimpCmdCompareDumpError +/// \brief Error codes used by the 'Compare Dump' utility. +enum AssimpCmdCompareDumpError { +	FailedToLoadExpectedInputFile = AssimpCmdError::LastAssimpCmdError, +	FileComparaisonFailure, +	UnknownFailure, + +	// Add new error codes here... + +	LastAssimpCmdCompareDumpError, // Must be last. +}; + +// ------------------------------------------------------------------------------ +/** assimp_cmpdump utility + *  @param params Command line parameters to 'assimp cmpdump' + *  @param Number of params + *  @return Either an #AssimpCmdError or #AssimpCmdCompareDumpError. */ +int Assimp_CompareDump ( +	const char* const* params, +	unsigned int num); + +/// \enum AssimpCmdInfoError +/// \brief Error codes used by the 'Info' utility. +enum AssimpCmdInfoError { +	InvalidCombinaisonOfArguments = AssimpCmdError::LastAssimpCmdError, + +	// Add new error codes here... + +	LastAssimpCmdInfoError, // Must be last. +}; + +// ------------------------------------------------------------------------------ +/** @brief assimp info utility + *  @param params Command line parameters to 'assimp info' + *  @param Number of params + *  @return Either an #AssimpCmdError or #AssimpCmdInfoError value. */ +int Assimp_Info ( +	const char* const* params, +	unsigned int num); + +// ------------------------------------------------------------------------------ +/** @brief assimp testbatchload utility + *  @param params Command line parameters to 'assimp testbatchload' + *  @param Number of params + *  @return An #AssimpCmdError value. */ +int Assimp_TestBatchLoad ( +	const char* const* params, +	unsigned int num); + + +#endif // !! AICMD_MAIN_INCLUDED diff --git a/libs/assimp/tools/assimp_cmd/WriteDump.cpp b/libs/assimp/tools/assimp_cmd/WriteDump.cpp new file mode 100644 index 0000000..4ada408 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/WriteDump.cpp @@ -0,0 +1,172 @@ +/* +--------------------------------------------------------------------------- +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  WriteDump.cpp + *  @brief Implementation of the 'assimp dump' utility + */ + +#include "Main.h" +#include "PostProcessing/ProcessHelper.h" + +const char *AICMD_MSG_DUMP_HELP = +        "assimp dump <model> [<out>] [-b] [-s] [-z] [common parameters]\n" +        "\t -b Binary output \n" +        "\t -s Shortened  \n" +        "\t -z Compressed  \n" +        "\t[See the assimp_cmd docs for a full list of all common parameters]  \n" +        "\t -cfast    Fast post processing preset, runs just a few important steps \n" +        "\t -cdefault Default post processing: runs all recommended steps\n" +        "\t -cfull    Fires almost all post processing steps \n"; + +#include "Common/assbin_chunks.h" +#include <assimp/DefaultIOSystem.h> +#include "AssetLib/Assbin/AssbinFileWriter.h" +#include "AssetLib/Assxml/AssxmlFileWriter.h" + +#include <memory> + +FILE *out = nullptr; +bool shortened = false; + +#ifndef ASSIMP_BUILD_NO_EXPORT + +// ----------------------------------------------------------------------------------- +int Assimp_Dump(const char *const *params, unsigned int num) { +    const char *fail = "assimp dump: Invalid number of arguments. " +                       "See \'assimp dump --help\'\r\n"; + +    // --help +    if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) { +        printf("%s", AICMD_MSG_DUMP_HELP); +        return AssimpCmdError::Success; +    } + +    // asssimp dump in out [options] +    if (num < 1) { +        printf("%s", fail); +        return AssimpCmdError::InvalidNumberOfArguments; +    } + +    std::string in = std::string(params[0]); +    std::string cur_out = (num > 1 ? std::string(params[1]) : std::string("-")); + +    // store full command line +    std::string cmd; +    for (unsigned int i = (cur_out[0] == '-' ? 1 : 2); i < num; ++i) { +        if (!params[i]) continue; +        cmd.append(params[i]); +        cmd.append(" "); +    } + +    // get import flags +    ImportData import; +    ProcessStandardArguments(import, params + 1, num - 1); + +    bool binary = false, cur_shortened = false, compressed = false; + +    // process other flags +    for (unsigned int i = 1; i < num; ++i) { +        if (!params[i]) { +            continue; +        } +        if (!strcmp(params[i], "-b") || !strcmp(params[i], "--binary")) { +            binary = true; +        } else if (!strcmp(params[i], "-s") || !strcmp(params[i], "--short")) { +            cur_shortened = true; +        } else if (!strcmp(params[i], "-z") || !strcmp(params[i], "--compressed")) { +            compressed = true; +        } +#if 0 +		else if (i > 2 || params[i][0] == '-') { +			::printf("Unknown parameter: %s\n",params[i]); +			return 10; +		} +#endif +    } + +    if (cur_out[0] == '-') { +        // take file name from input file +        std::string::size_type pos = in.find_last_of('.'); +        if (pos == std::string::npos) { +            pos = in.length(); +        } + +        cur_out = in.substr(0, pos); +        cur_out.append((binary ? ".assbin" : ".assxml")); +        if (cur_shortened && binary) { +            cur_out.append(".regress"); +        } +    } + +    // import the main model +    const aiScene *scene = ImportModel(import, in); +    if (!scene) { +        printf("assimp dump: Unable to load input file %s\n", in.c_str()); +        return AssimpCmdError::FailedToLoadInputFile; +    } + +    try { +        // Dump the main model, using the appropriate method. +        std::unique_ptr<IOSystem> pIOSystem(new DefaultIOSystem()); +        if (binary) { +            DumpSceneToAssbin(cur_out.c_str(), cmd.c_str(), pIOSystem.get(), +                    scene, shortened, compressed); +        } else { +            DumpSceneToAssxml(cur_out.c_str(), cmd.c_str(), pIOSystem.get(), +                    scene, shortened); +        } +    } catch (const std::exception &e) { +        printf("%s", ("assimp dump: " + std::string(e.what())).c_str()); +        return AssimpCmdError::ExceptionWasRaised; +    } catch (...) { +        printf("assimp dump: An unknown exception occurred.\n"); +        return AssimpCmdError::ExceptionWasRaised; +    } + +    printf("assimp dump: Wrote output dump %s\n", cur_out.c_str()); +    return AssimpCmdError::Success; +} +#else +int Assimp_Dump(const char *const *, unsigned int ) { +    printf("assimp dump: Export disabled.\n"); +    return AssimpCmdError::UnrecognizedCommand; +} +#endif
\ No newline at end of file diff --git a/libs/assimp/tools/assimp_cmd/assimp_cmd.rc b/libs/assimp/tools/assimp_cmd/assimp_cmd.rc new file mode 100644 index 0000000..e671006 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/assimp_cmd.rc @@ -0,0 +1,51 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "../../revision.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (Deutschland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ASSIMP_VIEW         ICON                    "../shared/assimp_tools_icon.ico" + + + + + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif    // not APSTUDIO_INVOKED +#endif diff --git a/libs/assimp/tools/assimp_cmd/generic_inserter.hpp b/libs/assimp/tools/assimp_cmd/generic_inserter.hpp new file mode 100644 index 0000000..8053219 --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/generic_inserter.hpp @@ -0,0 +1,113 @@ +/* Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ + + +#ifndef HEADER_GENERIC_INSERTER_HPP_INCLUDED +#define HEADER_GENERIC_INSERTER_HPP_INCLUDED + + +#include <ostream> +#include <new> // bad_alloc + + +template <typename char_type, typename traits_type, typename argument_type> +std::basic_ostream<char_type, traits_type>& generic_inserter(void (*print)(std::basic_ostream<char_type, traits_type>& os, argument_type const& arg), std::basic_ostream<char_type, traits_type>& os, argument_type const& arg) +{ +    using namespace ::std; + +    ios_base::iostate err = ios_base::goodbit; +    try +    { +        typename basic_ostream<char_type, traits_type>::sentry sentry(os); +        if (sentry) +        { +            print(os, arg); +            err = os.rdstate(); +            os.width(0); // Reset width in case the user didn't do it. +        } +    } +    catch (bad_alloc const&) +    { +        err |= ios_base::badbit; // bad_alloc is considered fatal +        ios_base::iostate const exception_mask = os.exceptions(); + +        // Two cases: 1.) badbit is not set; 2.) badbit is set +        if (((exception_mask & ios_base::failbit) != 0) && // failbit shall throw +            ((exception_mask & ios_base::badbit) == 0))    // badbit shall not throw +        { +            // Do not throw unless failbit is set. +            // If it is set throw ios_base::failure because we don't know what caused the failbit to be set. +            os.setstate(err); +        } +        else if (exception_mask & ios_base::badbit) +        { +            try +            { +                // This will set the badbit and throw ios_base::failure. +                os.setstate(err); +            } +            catch (ios_base::failure const&) +            { +                // Do nothing since we want bad_alloc to be rethrown. +            } +            throw; +        } +        // else: no exception must get out! +    } +    catch (...) +    { +        err |= ios_base::failbit; // Any other exception is considered "only" as a failure. +        ios_base::iostate const exception_mask = os.exceptions(); + +        // badbit is considered more important +        if (((exception_mask & ios_base::badbit) != 0) && // badbit shall throw +            ((err & ios_base::badbit) != 0))              // badbit is set +        { +            // Throw ios_base::failure because we don't know what caused the badbit to be set. +            os.setstate(err); +        } +        else if ((exception_mask & ios_base::failbit) != 0) +        { +            try +            { +                // This will set the failbit and throw the exception ios_base::failure. +                os.setstate(err); +            } +            catch (ios_base::failure const&) +            { +                // Do nothing since we want the original exception to be rethrown. +            } +            throw; +        } +        // else: no exception must get out! +    } + +    // Needed in the case that no exception has been thrown but the stream state has changed. +    if (err) +        os.setstate(err); +    return os; +} + + +#endif // HEADER_GENERIC_INSERTER_HPP_INCLUDED diff --git a/libs/assimp/tools/assimp_cmd/resource.h b/libs/assimp/tools/assimp_cmd/resource.h new file mode 100644 index 0000000..caf3a0a --- /dev/null +++ b/libs/assimp/tools/assimp_cmd/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by assimp_view.rc +// +#define IDC_MYICON                      2 +#define IDD_ASSIMP_VIEW_DIALOG          102 +#define IDD_ABOUTBOX                    103 +#define IDI_ASSIMP_VIEW                 107 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC                     1 +#define _APS_NEXT_RESOURCE_VALUE        159 +#define _APS_NEXT_COMMAND_VALUE         32831 +#define _APS_NEXT_CONTROL_VALUE         1052 +#define _APS_NEXT_SYMED_VALUE           110 +#endif +#endif  | 
