From ff53e847495dfd7978c05b1ede550fb339de5760 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sat, 13 Mar 2010 00:04:21 +0000 Subject: [PATCH] - Update XML output written by assimp dump. cameras & lights missing, document scheme as well. No guarantees that I won't change it in future without further notice (currently WIP, format to be freezed with our next release). - Add dump comparison tool to assimp_cmd. It serves as the workhorse of the regression suite. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@598 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- tools/assimp_cmd/CompareDump.cpp | 893 ++++++++++++++++ tools/assimp_cmd/ImageExtractor.cpp | 48 +- tools/assimp_cmd/Main.cpp | 43 +- tools/assimp_cmd/Main.h | 48 +- tools/assimp_cmd/WriteDumb.cpp | 1405 ++++++++++++++----------- tools/assimp_cmd/generic_inserter.hpp | 113 ++ 6 files changed, 1900 insertions(+), 650 deletions(-) create mode 100644 tools/assimp_cmd/generic_inserter.hpp diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp index d3f5a12fa..ee4b57edd 100644 --- a/tools/assimp_cmd/CompareDump.cpp +++ b/tools/assimp_cmd/CompareDump.cpp @@ -1 +1,894 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- +Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 \n" +"\tCompare two short dumps produced with \'assimp dump <..> -s\' for equality.\n" +; + +#include "../../code/assbin_chunks.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +#include "generic_inserter.hpp" + +// get << for aiString +template +void mysprint(std::basic_ostream& os, const aiString& vec) { + os << "[length: \'" << std::dec << vec.length << "\' content: \'" << vec.data << "\']"; +} + +template +std::basic_ostream& operator<< (std::basic_ostream& os, const aiString& vec) { + return generic_inserter(mysprint, 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) + { + assert(actual); + assert(expect); + + fseek(actual,0,SEEK_END); + lengths.push(std::make_pair(static_cast(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] = 1; + + history.push_back(HistoryEntry(s,PerChunkCounter())); + + } + + /* leave current scope */ + void pop_elem() { + assert(history.size()); + 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() { + assert(lengths.size()); + lengths.pop(); + } + + /* access the current chunk length */ + uint32_t get_latest_chunk_length() { + assert(lengths.size()); + return lengths.top().first; + } + + /* access the current chunk start offset */ + uint32_t get_latest_chunk_start() { + 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 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 void cmp(size_t num,const std::string& name) { + for(size_t n = 0; n < num; ++n) { + std::stringstream ss; + cmp((ss< void cmp_bounds(const std::string& name) { + cmp (name+"."); + cmp (name+"."); + } + +private: + + /* Report failure */ + void failure(const std::string& err, const std::string& name) { + 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 << std::endl; + + 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]-1 << ")" << std::endl; + last = (*rev).first.c_str(); + } + + return ss.str(); + } + + + /* read from both streams simult.*/ + template void read(T& filla,T& fille) { + if(1 != fread(&filla,sizeof(T),1,actual)) { + throw compare_fails_exception("Unexpected EOF reading ACTUAL"); + } + if(1 != fread(&fille,sizeof(T),1,expect)) { + throw compare_fails_exception("Unexpected EOF reading EXPECT"); + } + } + + +private: + + FILE *const actual, *const expect; + + typedef std::map PerChunkCounter; + typedef std::pair HistoryEntry; + + typedef std::deque ChunkHistory; + ChunkHistory history; + + typedef std::stack > 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& filla,aiString& fille) { + uint32_t lena,lene; + read(lena,lene); + + if(lena && 1 != fread(&filla.data,lena,1,actual)) { + throw compare_fails_exception("Unexpected EOF reading ACTUAL"); + } + if(lene && 1 != fread(&fille.data,lene,1,expect)) { + throw compare_fails_exception("Unexpected EOF reading ACTUAL"); + } + + fille.data[fille.length=static_cast(lene)] = '\0'; + filla.data[filla.length=static_cast(lena)] = '\0'; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for float, uses epsilon for comparisons*/ +template<> float comparer_context :: cmp(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(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(const std::string& name) +{ + const float x = cmp(name+".x"); + const float y = cmp(name+".y"); + const float z = cmp(name+".z"); + + return aiVector3D(x,y,z); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiColor4D */ +template<> aiColor4D comparer_context :: cmp(const std::string& name) +{ + const float r = cmp(name+".r"); + const float g = cmp(name+".g"); + const float b = cmp(name+".b"); + const float a = cmp(name+".a"); + + return aiColor4D(r,g,b,a); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiQuaternion */ +template<> aiQuaternion comparer_context :: cmp(const std::string& name) +{ + const float w = cmp(name+".w"); + const float x = cmp(name+".x"); + const float y = cmp(name+".y"); + const float z = cmp(name+".z"); + + return aiQuaternion(w,x,y,z); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiQuatKey */ +template<> aiQuatKey comparer_context :: cmp(const std::string& name) +{ + const double mTime = cmp(name+".mTime"); + const aiQuaternion mValue = cmp(name+".mValue"); + + return aiQuatKey(mTime,mValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiVectorKey */ +template<> aiVectorKey comparer_context :: cmp(const std::string& name) +{ + const double mTime = cmp(name+".mTime"); + const aiVector3D mValue = cmp(name+".mValue"); + + return aiVectorKey(mTime,mValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/* Specialization for aiMatrix4x4 */ +template<> aiMatrix4x4 comparer_context :: cmp(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(name+(ss<<".m"< aiVertexWeight comparer_context :: cmp(const std::string& name) +{ + const unsigned int mVertexId = cmp(name+".mVertexId"); + const float mWeight = cmp(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::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 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::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("I/OError reading chunk head, dumps are not well-defined",""); + } + + 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()), + ""); + } + + if (current.first != actual.first) { + std::stringstream ss; + ctx.failure((ss + <<"Chunk lenghts do not match. EXPECT: " + <"); + } + + 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("mKey"); + comp.cmp("mSemantic"); + comp.cmp("mIndex"); + const uint32_t length = comp.cmp("mDataLength"); + const aiPropertyTypeInfo type = static_cast( + comp.cmp("mType")); + + switch (type) + { + case aiPTI_Float: + comp.cmp(length/4,"mData"); + break; + + case aiPTI_String: + comp.cmp("mData"); + break; + + case aiPTI_Integer: + comp.cmp(length/4,"mData"); + break; + + case aiPTI_Buffer: + comp.cmp(length,"mData"); + break; + }; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyMaterial(comparer_context& comp) { + scoped_chunk chunk(comp,"aiMaterial"); + + comp.cmp("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("mName"); + comp.cmp("mNumWeights"); + comp.cmp("mOffsetMatrix"); + + comp.cmp_bounds("mWeights"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyNodeAnim(comparer_context& comp) { + scoped_chunk chunk(comp,"aiNodeAnim"); + + comp.cmp("mNodeName"); + comp.cmp("mNumPositionKeys"); + comp.cmp("mNumRotationKeys"); + comp.cmp("mNumScalingKeys"); + comp.cmp("mPreState"); + comp.cmp("mPostState"); + + comp.cmp_bounds("mPositionKeys"); + comp.cmp_bounds("mRotationKeys"); + comp.cmp_bounds("mScalingKeys"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyMesh(comparer_context& comp) { + scoped_chunk chunk(comp,"aiMesh"); + + comp.cmp("mPrimitiveTypes"); + comp.cmp("mNumVertices"); + const uint32_t nf = comp.cmp("mNumFaces"); + comp.cmp("mNumBones"); + comp.cmp("mMaterialIndex"); + + const uint32_t present = comp.cmp(""); + if(present & ASSBIN_MESH_HAS_POSITIONS) { + comp.cmp_bounds("mVertices"); + } + + if(present & ASSBIN_MESH_HAS_NORMALS) { + comp.cmp_bounds("mNormals"); + } + + if(present & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) { + comp.cmp_bounds("mTangents"); + comp.cmp_bounds("mBitangents"); + } + + for(unsigned int i = 0; present & ASSBIN_MESH_HAS_COLOR(i); ++i) { + std::stringstream ss; + comp.cmp_bounds((ss<<"mColors["<((ss<<"mNumUVComponents["<((ss.clear(),ss<<"mTextureCoords["<((ss<<"mFaces["<((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("mName"); + + comp.cmp("mPosition"); + comp.cmp("mLookAt"); + comp.cmp("mUp"); + + comp.cmp("mHorizontalFOV"); + comp.cmp("mClipPlaneNear"); + comp.cmp("mClipPlaneFar"); + comp.cmp("mAspect"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyLight(comparer_context& comp) { + scoped_chunk chunk(comp,"aiLight"); + + comp.cmp("mName"); + const aiLightSourceType type = static_cast( + comp.cmp("mType")); + + if(type==aiLightSource_DIRECTIONAL) { + comp.cmp("mAttenuationConstant"); + comp.cmp("mAttenuationLinear"); + comp.cmp("mAttenuationQuadratic"); + } + + comp.cmp("mColorDiffuse"); + comp.cmp("mColorSpecular"); + comp.cmp("mColorAmbient"); + + if(type==aiLightSource_SPOT) { + comp.cmp("mAngleInnerCone"); + comp.cmp("mAngleOuterCone"); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyAnimation(comparer_context& comp) { + scoped_chunk chunk(comp,"aiAnimation"); + + comp.cmp("mName"); + comp.cmp("mDuration"); + comp.cmp("mTicksPerSecond"); + comp.cmp("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("mWidth"); + const uint32_t h = comp.cmp("mHeight"); + comp.cmp("achFormatHint[0]"); + comp.cmp("achFormatHint[1]"); + comp.cmp("achFormatHint[2]"); + comp.cmp("achFormatHint[3]"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CompareOnTheFlyNode(comparer_context& comp) { + scoped_chunk chunk(comp,"aiNode"); + comp.cmp("mName"); + comp.cmp("mTransformation"); + comp.cmp("mNumChildren"); + comp.cmp(comp.cmp("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("mFlags"); + comp.cmp("mNumMeshes"); + comp.cmp("mNumMaterials"); + comp.cmp("mNumAnimations"); + comp.cmp("mNumTextures"); + comp.cmp("mNumLights"); + comp.cmp("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 0; + } + + // assimp cmpdump actual expected + if (num < 1) { + std::cout << "assimp cmpdump: Invalid number of arguments. " + "See \'assimp cmpdump --help\'\r\n" << std::endl; + return 1; + } + + if(!strcmp(params[0],params[1])) { + std::cout << "assimp cmpdump: same file, same content." << std::endl; + return 0; + } + + FILE* actual = fopen(params[0],"rb"), *expected = fopen(params[1],"rb"); + if (!actual) { + std::cout << "assimp cmpdump: Failure reading ACTUAL data from " << + params[0] << std::endl; + return -5; + } + if (!expected) { + std::cout << "assimp cmpdump: Failure reading EXPECT data from " << + params[1] << std::endl; + return -6; + } + + comparer_context comp(actual,expected); + try { + CheckHeader(comp); + CompareOnTheFly(comp); + } + catch(const compare_fails_exception& ex) { + printf("%s",ex.what()); + return -1; + } + 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 -3; + } + + std::cout << "Success (totally " << std::dec << comp.get_num_chunks() << + " chunks)" << std::endl; + + return 0; +} diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp index eacc6df47..34800ac11 100644 --- a/tools/assimp_cmd/ImageExtractor.cpp +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -46,11 +46,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Main.h" const char* AICMD_MSG_DUMP_HELP_E = -"todo assimp extract help"; - +"assimp extract [] [-t] [-f] [-ba] [-s] [common parameters]\n" +"\t -ba Writes BMP's with alpha channel\n" +"\t -t Zero-based index of the texture to be extracted \n" +"\t -f Specify the file format if is ommitted \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 "Compiler/pushpack1.h" // ----------------------------------------------------------------------------------- @@ -136,7 +142,7 @@ int SaveAsBMP (FILE* file, const aiTexel* data, unsigned int width, unsigned int header.bfSize = header.bfOffBits+width*height*numc; header.bfReserved1 = header.bfReserved2 = 0; - ::fwrite(&header,sizeof(BITMAPFILEHEADER),1,file); + fwrite(&header,sizeof(BITMAPFILEHEADER),1,file); BITMAPINFOHEADER info; info.biSize = 40; @@ -151,13 +157,13 @@ int SaveAsBMP (FILE* file, const aiTexel* data, unsigned int width, unsigned int info.biClrUsed = 0; info.biClrImportant = 0; - ::fwrite(&info,sizeof(BITMAPINFOHEADER),1,file); + 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); + fwrite(temp,row,1,file); } // delete the buffer @@ -179,11 +185,11 @@ int SaveAsTGA (FILE* file, const aiTexel* data, unsigned int width, unsigned int head.descriptor |= (1u<<5); head.imagetype = 2; // actually it's RGBA - ::fwrite(&head,sizeof(TGA_HEADER),1,file); + 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); + fwrite(data + y*width+x,4,1,file); } } @@ -212,7 +218,7 @@ int DoExport(const aiTexture* tx, FILE* p, const std::string& extension, // ----------------------------------------------------------------------------------- // Implementation of the assimp extract utility -int Assimp_Extract (const char** params, unsigned int num) +int Assimp_Extract (const char* const* params, unsigned int num) { if (num < 1) { printf("assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n"); @@ -220,7 +226,7 @@ int Assimp_Extract (const char** params, unsigned int num) } // --help - if (!::strcmp( params[0], "-h") || !::strcmp( params[0], "--help") || !::strcmp( params[0], "-?") ) { + if (!strcmp( params[0], "-h") || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) { printf("%s",AICMD_MSG_DUMP_HELP_E); return 0; } @@ -246,28 +252,30 @@ int Assimp_Extract (const char** params, unsigned int num) 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], "-f",2)) { extension = std::string(params[i]+2); } - else if ( !::strncmp( params[i], "--format=",9)) { + else if ( !strncmp( params[i], "--format=",9)) { extension = std::string(params[i]+9); } - else if ( !::strcmp( params[i], "--nosuffix") || !::strcmp(params[i],"-s")) { + else if ( !strcmp( params[i], "--nosuffix") || !strcmp(params[i],"-s")) { nosuffix = true; } - else if ( !::strncmp( params[i], "--texture=",10)) { + else if ( !strncmp( params[i], "--texture=",10)) { texIdx = ::strtol10(params[i]+10); } - else if ( !::strncmp( params[i], "-t",2)) { + else if ( !strncmp( params[i], "-t",2)) { texIdx = ::strtol10(params[i]+2); } - else if ( !::strcmp( params[i], "-ba") || !::strcmp( params[i], "--bmp-with-alpha")) { + 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 } for (std::string::iterator it = extension.begin();it != extension.end();++it) *it = ::tolower(*it); @@ -310,10 +318,10 @@ int Assimp_Extract (const char** params, unsigned int num) } // now write all output textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) - { - if (texIdx != 0xffffffff && texIdx != i) + 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; @@ -347,7 +355,7 @@ int Assimp_Extract (const char** params, unsigned int num) int m; if (!tex->mHeight) { - m = (1 != ::fwrite(tex->pcData,tex->mWidth,1,p)); + m = (1 != fwrite(tex->pcData,tex->mWidth,1,p)); } else m = DoExport(tex,p,extension,flags); ::fclose(p); diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 5fd90ade8..3c8ab0ad3 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -63,6 +63,7 @@ const char* AICMD_MSG_HELP = "\t\tknowext - Check whether a file extension is recognized by Assimp\n" "\t\textract - Extract an embedded texture from a model\n" "\t\tdump - Convert a model to binary or XML dumps (ASSBIN/ASSXML)\n" +"\t\tcmpdump - Compare two file dumps produced with \'assimp dump -s ...\'\n" "\n\n\tUse \'assimp --help\' to get detailed help for a command.\n" ; @@ -73,14 +74,13 @@ const char* AICMD_MSG_HELP = int main (int argc, char* argv[]) { if (argc <= 1) { - printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n"); return 0; } // assimp version // Display version information - if (! ::strcmp(argv[1], "version")) { + if (! strcmp(argv[1], "version")) { const unsigned int flags = aiGetCompileFlags(); printf(AICMD_MSG_ABOUT, aiGetVersionMajor(), @@ -103,7 +103,14 @@ int main (int argc, char* argv[]) return 0; } + // assimp cmpdump + // Compare two mini model dumps (regression suite) + if (! strcmp(argv[1], "cmpdump")) { + return Assimp_CompareDump (&argv[2],argc-2); + } + // construct a global Assimp::Importer instance + // because all further tools rely on it Assimp::Importer imp; globalImporter = &imp; @@ -138,13 +145,13 @@ int main (int argc, char* argv[]) // assimp dump // Dump a model to a file if (! strcmp(argv[1], "dump")) { - return Assimp_Dump ((const char**)&argv[2],argc-2); + return Assimp_Dump (&argv[2],argc-2); } // assimp extract // Extract an embedded texture from a file if (! strcmp(argv[1], "extract")) { - return Assimp_Extract ((const char**)&argv[2],argc-2); + return Assimp_Extract (&argv[2],argc-2); } printf("Unrecognized command. Use \'assimp help\' for a detailed command list\n"); @@ -153,7 +160,9 @@ int main (int argc, char* argv[]) // ------------------------------------------------------------------------------ // Import a specific file -const aiScene* ImportModel(const ImportData& imp, const std::string& path) +const aiScene* ImportModel( + const ImportData& imp, + const std::string& path) { // Attach log streams if (imp.log) { @@ -172,12 +181,12 @@ const aiScene* ImportModel(const ImportData& imp, const std::string& path) // Now validate this flag combination if(!globalImporter->ValidateFlags(imp.ppFlags)) { - ::printf("ERROR: Unsupported post-processing flags \n"); + printf("ERROR: Unsupported post-processing flags \n"); return NULL; } printf("Validating postprocessing flags ... OK\n"); if (imp.showLog) - ::printf("-----------------------------------------------------------------\n"); + printf("-----------------------------------------------------------------\n"); // do the actual import, measure time const clock_t first = clock(); @@ -205,7 +214,9 @@ const aiScene* ImportModel(const ImportData& imp, const std::string& path) // ------------------------------------------------------------------------------ // Process standard arguments -int ProcessStandardArguments(ImportData& fill, const char** params, +int ProcessStandardArguments( + ImportData& fill, + const char* const * params, unsigned int num) { // -ptv --pretransform-vertices @@ -237,11 +248,11 @@ int ProcessStandardArguments(ImportData& fill, const char** params, for (unsigned int i = 0; i < num;++i) { - if (!params[i]) { // could happen if some args have already been processed - continue; - } + //if (!params[i]) { // could happen if some args have already been processed + // continue; + //} - bool has = true; + // bool has = true; if (! strcmp(params[i], "-ptv") || ! strcmp(params[i], "--pretransform-vertices")) { fill.ppFlags |= aiProcess_PreTransformVertices; } @@ -350,10 +361,10 @@ int ProcessStandardArguments(ImportData& fill, const char** params, fill.logFile = "assimp-log.txt"; } - else has = false; - if (has) { - params[i] = NULL; - } + //else has = false; + //if (has) { + // params[i] = NULL; + //} } if (fill.logFile.length() || fill.showLog || fill.verbose) diff --git a/tools/assimp_cmd/Main.h b/tools/assimp_cmd/Main.h index cd44d7e39..ef2028a6e 100644 --- a/tools/assimp_cmd/Main.h +++ b/tools/assimp_cmd/Main.h @@ -71,8 +71,7 @@ using namespace Assimp; extern Assimp::Importer* globalImporter; // ------------------------------------------------------------------------------ -/** @brief Defines common import parameters - */ +/** Defines common import parameters */ struct ImportData { ImportData() @@ -101,39 +100,52 @@ struct ImportData }; // ------------------------------------------------------------------------------ -/** @brief Process standard arguments +/** Process standard arguments * * @param fill Filled by function * @param params Command line parameters to be processed * @param num NUmber of params - * @return 0 for success - */ -int ProcessStandardArguments(ImportData& fill, const char** params, + * @return 0 for success */ +int ProcessStandardArguments(ImportData& fill, + const char* const* params, unsigned int num); // ------------------------------------------------------------------------------ -/** @brief Import a specific model file +/** Import a specific model file * @param imp Import configuration to be used - * @param path Path to the file to be opened - */ -const aiScene* ImportModel(const ImportData& imp, const std::string& path); + * @param path Path to the file to be opened */ +const aiScene* ImportModel( + const ImportData& imp, + const std::string& path); // ------------------------------------------------------------------------------ -/** @brief assimp dump utility +/** assimp_dump utility * @param params Command line parameters to 'assimp dumb' * @param Number of params - * @return 0 for success - */ -int Assimp_Dump (const char** params, unsigned int num); + * @return 0 for success*/ +int Assimp_Dump ( + const char* const* params, + unsigned int num); // ------------------------------------------------------------------------------ -/** @brief assimp extract utility +/** assimp_extract utility * @param params Command line parameters to 'assimp extract' * @param Number of params - * @return 0 for success - */ -int Assimp_Extract (const char** params, unsigned int num); + * @return 0 for success*/ +int Assimp_Extract ( + const char* const* params, + unsigned int num); + +// ------------------------------------------------------------------------------ +/** assimp_cmpdump utility + * @param params Command line parameters to 'assimp cmpdump' + * @param Number of params + * @return 0 for success*/ +int Assimp_CompareDump ( + const char* const* params, + unsigned int num); + // ------------------------------------------------------------------------------ /** @brief assimp info utility diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index 0b1e14512..5d0852254 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -47,411 +47,577 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../code/ProcessHelper.h" const char* AICMD_MSG_DUMP_HELP = -"todo assimp dumb help"; +"assimp dump [] [-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 "../../code/assbin_chunks.h" + +FILE* out = NULL; +bool shortened = false; // ----------------------------------------------------------------------------------- // Compress a binary dump file (beginning at offset head_size) void CompressBinaryDump(const char* file, unsigned int head_size) { // for simplicity ... copy the file into memory again and compress it there - FILE* p = ::fopen(file,"r"); - ::fseek(p,0,SEEK_END); - const unsigned int size = (unsigned int)::ftell(p); - ::fseek(p,0,SEEK_SET); + FILE* p = fopen(file,"r"); + fseek(p,0,SEEK_END); + const uint32_t size = ftell(p); + fseek(p,0,SEEK_SET); if (sizemName,out); - WriteMat4x4(node->mTransformation,out); - - WriteInteger(node->mNumMeshes,out); - for (unsigned int i = 0; i < node->mNumMeshes;++i) - WriteInteger(node->mMeshes[i],out); - - WriteInteger(node->mNumChildren,out); - for (unsigned int i = 0; i < node->mNumChildren;++i) - WriteBinaryNode(node->mChildren[i],out); + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + WriteFloat(m[i][i2]); + } + } + return 64; } // ----------------------------------------------------------------------------------- // Write the min/max values of an array of Ts to the file template -inline void WriteBounds(const T* in, unsigned int size, FILE* out) +inline uint32_t WriteBounds(const T* in, unsigned int size) { T minc,maxc; ArrayBounds(in,size,minc,maxc); - ::fwrite(&minc,sizeof(T),1,out); - ::fwrite(&maxc,sizeof(T),1,out); + fwrite(&minc,sizeof(T),1,out); + fwrite(&maxc,sizeof(T),1,out); + return sizeof(T)*2; } // ----------------------------------------------------------------------------------- -// Write a binary model dump -void WriteBinaryDump(const aiScene* scene, FILE* out, const char* src, const char* cmd, - bool shortened, bool compressed, ImportData& imp) +void ChangeInteger(uint32_t ofs,uint32_t n) { - time_t tt = ::time(NULL); - tm* p = ::gmtime(&tt); + const uint32_t cur = ftell(out); + fseek(out,ofs,SEEK_SET); + fwrite(&n,4,1,out); + fseek(out,cur,SEEK_SET); +} - // header - ::fprintf(out,"ASSIMP.binary-dump.%s.",::asctime(p)); - // == 45 bytes +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryNode(const aiNode* node) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AINODE); + len += WriteAiString(node->mName); + len += WriteMat4x4(node->mTransformation); + len += WriteInteger(node->mNumChildren); + len += WriteInteger(node->mNumMeshes); - WriteInteger(aiGetVersionMajor(),out); - WriteInteger(aiGetVersionMinor(),out); - WriteInteger(aiGetVersionRevision(),out); - WriteInteger(aiGetCompileFlags(),out); - WriteShort(shortened,out); - WriteShort(compressed,out); - // == 20 bytes + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + len += WriteInteger(node->mMeshes[i]); + } - char buff[256]; - ::strncpy(buff,src,256); - ::fwrite(buff,256,1,out); + for (unsigned int i = 0; i < node->mNumChildren;++i) { + len += WriteBinaryNode(node->mChildren[i])+8; + } - ::strncpy(buff,cmd,128); - ::fwrite(buff,128,1,out); + ChangeInteger(old,len); + return len; +} - // leave 41 bytes free for future extensions - ::memset(buff,0xcd,41); - ::fwrite(buff,32,1,out); - // == 435 bytes +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryTexture(const aiTexture* tex) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AITEXTURE); + + len += WriteInteger(tex->mWidth); + len += WriteInteger(tex->mHeight); + len += fwrite(tex->achFormatHint,1,4,out); + + if(!shortened) { + if (!tex->mHeight) { + len += fwrite(tex->pcData,1,tex->mWidth,out); + } + else { + len += fwrite(tex->pcData,1,tex->mWidth*tex->mHeight*4,out); + } + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryBone(const aiBone* b) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AIBONE); + + len += WriteAiString(b->mName); + len += WriteInteger(b->mNumWeights); + len += WriteMat4x4(b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + len += WriteBounds(b->mWeights,b->mNumWeights); + } // else write as usual + else len += fwrite(b->mWeights,1,b->mNumWeights*sizeof(aiVertexWeight),out); + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryMesh(const aiMesh* mesh) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AIMESH); + + len += WriteInteger(mesh->mPrimitiveTypes); + len += WriteInteger(mesh->mNumVertices); + len += WriteInteger(mesh->mNumFaces); + len += WriteInteger(mesh->mNumBones); + len += WriteInteger(mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + len += WriteInteger(c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + len += WriteBounds(mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else len += fwrite(mesh->mVertices,1,12*mesh->mNumVertices,out); + } + if (mesh->mNormals) { + if (shortened) { + len += WriteBounds(mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else len += fwrite(mesh->mNormals,1,12*mesh->mNumVertices,out); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + len += WriteBounds(mesh->mTangents,mesh->mNumVertices); + len += WriteBounds(mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + len += fwrite(mesh->mTangents,1,12*mesh->mNumVertices,out); + len += fwrite(mesh->mBitangents,1,12*mesh->mNumVertices,out); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + len += WriteBounds(mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else len += fwrite(mesh->mColors[n],16*mesh->mNumVertices,1,out); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + len += WriteInteger(mesh->mNumUVComponents[n]); + + if (shortened) { + len += WriteBounds(mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else len += fwrite(mesh->mTextureCoords[n],12*mesh->mNumVertices,1,out); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;job = std::min(mesh->mNumFaces-processed,512u);processed += job) { + + unsigned int hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + hash = SuperFastHash((const char*)&f.mNumIndices,sizeof(unsigned int),hash); + hash = SuperFastHash((const char*) f.mIndices,f.mNumIndices*sizeof(unsigned int),hash); + } + len += WriteInteger(hash); + } + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + if (f.mNumIndices >= (1u<<16)) { + printf("The assbin format doesn't support polygons with more than 65536 vertices"); + return -1; + } + + len += WriteShort(f.mNumIndices); + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + len += WriteShort(f.mIndices[a]); + } + else len += WriteInteger(f.mIndices[a]); + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + len += WriteBinaryBone(b)+8; + } + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryMaterialProperty(const aiMaterialProperty* prop) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AIMATERIALPROPERTY); + + len += WriteAiString(prop->mKey); + len += WriteInteger(prop->mSemantic); + len += WriteInteger(prop->mIndex); + + len += WriteInteger(prop->mDataLength); + len += WriteInteger((unsigned int)prop->mType); + len += fwrite(prop->mData,1,prop->mDataLength,out); + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryMaterial(const aiMaterial* mat) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AIMATERIAL); + + len += WriteInteger(mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + len += WriteBinaryMaterialProperty(mat->mProperties[i])+8; + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryNodeAnim(const aiNodeAnim* nd) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AINODEANIM); + + len += WriteAiString(nd->mNodeName); + len += WriteInteger(nd->mNumPositionKeys); + len += WriteInteger(nd->mNumRotationKeys); + len += WriteInteger(nd->mNumScalingKeys); + len += WriteInteger(nd->mPreState); + len += WriteInteger(nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + len += WriteBounds(nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else len += fwrite(nd->mPositionKeys,1,nd->mNumPositionKeys*sizeof(aiVectorKey),out); + } + if (nd->mRotationKeys) { + if (shortened) { + len += WriteBounds(nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else len += fwrite(nd->mRotationKeys,1,nd->mNumRotationKeys*sizeof(aiQuatKey),out); + } + if (nd->mScalingKeys) { + if (shortened) { + len += WriteBounds(nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else len += fwrite(nd->mScalingKeys,1,nd->mNumScalingKeys*sizeof(aiVectorKey),out); + } + + ChangeInteger(old,len); + return len; +} + + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryAnim(const aiAnimation* anim) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AIANIMATION); + + len += WriteAiString (anim->mName); + len += WriteDouble (anim->mDuration); + len += WriteDouble (anim->mTicksPerSecond); + len += WriteInteger(anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + len += WriteBinaryNodeAnim(nd)+8; + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryLight(const aiLight* l) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AILIGHT); + + len += WriteAiString(l->mName); + len += WriteInteger(l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + len += WriteFloat(l->mAttenuationConstant); + len += WriteFloat(l->mAttenuationLinear); + len += WriteFloat(l->mAttenuationQuadratic); + } + + len += WriteVec3((const aiVector3D&)l->mColorDiffuse); + len += WriteVec3((const aiVector3D&)l->mColorSpecular); + len += WriteVec3((const aiVector3D&)l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + len += WriteFloat(l->mAngleInnerCone); + len += WriteFloat(l->mAngleOuterCone); + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryCamera(const aiCamera* cam) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AICAMERA); + + len += WriteAiString(cam->mName); + len += WriteVec3(cam->mPosition); + len += WriteVec3(cam->mLookAt); + len += WriteVec3(cam->mUp); + len += WriteFloat(cam->mHorizontalFOV); + len += WriteFloat(cam->mClipPlaneNear); + len += WriteFloat(cam->mClipPlaneFar); + len += WriteFloat(cam->mAspect); + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +uint32_t WriteBinaryScene(const aiScene* scene) +{ + uint32_t len = 0, old = WriteMagic(ASSBIN_CHUNK_AISCENE); - // ==== total header size: 500 bytes - // Up to here the data is uncompressed. For compressed files, the rest - // is compressed using standard DEFLATE from zlib. - // basic scene information - WriteInteger(scene->mFlags,out); - WriteInteger(scene->mNumAnimations,out); - WriteInteger(scene->mNumTextures,out); - WriteInteger(scene->mNumMaterials,out); - WriteInteger(scene->mNumCameras,out); - WriteInteger(scene->mNumLights,out); - WriteInteger(scene->mNumMeshes,out); - + len += WriteInteger(scene->mFlags); + len += WriteInteger(scene->mNumMeshes); + len += WriteInteger(scene->mNumMaterials); + len += WriteInteger(scene->mNumAnimations); + len += WriteInteger(scene->mNumTextures); + len += WriteInteger(scene->mNumLights); + len += WriteInteger(scene->mNumCameras); + // write node graph - WriteBinaryNode(scene->mRootNode,out); + len += WriteBinaryNode(scene->mRootNode)+8; + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + len += WriteBinaryMesh(mesh)+8; + } // write materials for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { const aiMaterial* mat = scene->mMaterials[i]; - - WriteMagic("#MA",out); - WriteInteger(mat->mNumProperties,out); - - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - const aiMaterialProperty* prop = mat->mProperties[a]; - - WriteMagic("#MP",out); - WriteAiString(prop->mKey,out); - WriteInteger(prop->mSemantic,out); - WriteInteger(prop->mIndex,out); - - WriteInteger(prop->mDataLength,out); - ::fwrite(prop->mData,prop->mDataLength,1,out); - } - } - - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - - WriteMagic("#CA",out); - WriteAiString(cam->mName,out); - WriteVec3(cam->mPosition,out); - WriteVec3(cam->mLookAt,out); - WriteVec3(cam->mUp,out); - WriteFloat(cam->mClipPlaneNear,out); - WriteFloat(cam->mClipPlaneFar,out); - WriteFloat(cam->mHorizontalFOV,out); - WriteFloat(cam->mAspect,out); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - - WriteMagic("#LI",out); - WriteAiString(l->mName,out); - WriteInteger(l->mType,out); - - WriteVec3((const aiVector3D&)l->mColorDiffuse,out); - WriteVec3((const aiVector3D&)l->mColorSpecular,out); - WriteVec3((const aiVector3D&)l->mColorAmbient,out); - - if (l->mType != aiLightSource_DIRECTIONAL) { - WriteVec3(l->mPosition,out); - WriteFloat(l->mAttenuationLinear,out); - WriteFloat(l->mAttenuationConstant,out); - WriteFloat(l->mAttenuationQuadratic,out); - } - - if (l->mType != aiLightSource_POINT) { - WriteVec3(l->mDirection,out); - } - - if (l->mType == aiLightSource_SPOT) { - WriteFloat(l->mAttenuationConstant,out); - WriteFloat(l->mAttenuationQuadratic,out); - } + len += WriteBinaryMaterial(mat)+8; } // write all animations for (unsigned int i = 0; i < scene->mNumAnimations;++i) { const aiAnimation* anim = scene->mAnimations[i]; - - WriteMagic("#AN",out); - WriteAiString (anim->mName,out); - WriteDouble (anim->mTicksPerSecond,out); - WriteDouble (anim->mDuration,out); - WriteInteger(anim->mNumChannels,out); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - - WriteMagic("#NA",out); - WriteAiString(nd->mNodeName,out); - WriteInteger(nd->mPreState,out); - WriteInteger(nd->mPostState,out); - WriteInteger(nd->mNumPositionKeys,out); - WriteInteger(nd->mNumRotationKeys,out); - WriteInteger(nd->mNumScalingKeys,out); - - if (nd->mPositionKeys) { - if (shortened) { - WriteBounds(nd->mPositionKeys,nd->mNumPositionKeys,out); - - } // else write as usual - else ::fwrite(nd->mPositionKeys,sizeof(aiVectorKey),nd->mNumPositionKeys,out); - } - if (nd->mRotationKeys) { - if (shortened) { - WriteBounds(nd->mRotationKeys,nd->mNumRotationKeys,out); - - } // else write as usual - else ::fwrite(nd->mRotationKeys,sizeof(aiQuatKey),nd->mNumRotationKeys,out); - } - if (nd->mScalingKeys) { - if (shortened) { - WriteBounds(nd->mScalingKeys,nd->mNumScalingKeys,out); - - } // else write as usual - else ::fwrite(nd->mScalingKeys,sizeof(aiVectorKey),nd->mNumScalingKeys,out); - } - } + len += WriteBinaryAnim(anim)+8; } - // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteMagic("#ME",out); - WriteInteger(mesh->mPrimitiveTypes,out); - WriteInteger(mesh->mNumBones,out); - WriteInteger(mesh->mNumFaces,out); - WriteInteger(mesh->mNumVertices,out); - WriteInteger(mesh->mMaterialIndex,out); - - // write bones - if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - - WriteMagic("#BN",out); - WriteAiString(b->mName,out); - WriteMat4x4(b->mOffsetMatrix,out); - WriteInteger(b->mNumWeights,out); - - // for the moment we write dumb min/max values for the bones, too. - // maybe I'll add a better, hash-like solution later - if (shortened) { - WriteBounds(b->mWeights,b->mNumWeights,out); - } // else write as usual - else ::fwrite(b->mWeights,sizeof(aiVertexWeight),b->mNumWeights,out); - } - } - - // write faces. There are no floating-point calculations involved - // in these, so we can write a simple hash over the face data - // to the dump file. We generate a single 32 Bit hash for 512 faces - // using Assimp's standard hashing function. - if (shortened) { - unsigned int processed = 0; - for (unsigned int job;job = std::min(mesh->mNumFaces-processed,512u);processed += job) { - - unsigned int hash = 0; - for (unsigned int a = 0; a < job;++a) { - - const aiFace& f = mesh->mFaces[processed+a]; - hash = SuperFastHash((const char*)&f.mNumIndices,sizeof(unsigned int),hash); - hash = SuperFastHash((const char*) f.mIndices,f.mNumIndices*sizeof(unsigned int),hash); - } - WriteInteger(hash,out); - } - } - else // else write as usual - { - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; - - WriteInteger(f.mNumIndices,out); - for (unsigned int a = 0; a < f.mNumIndices;++a) - WriteInteger(f.mIndices[a],out); - } - } - - // first of all, write bits for all existent vertex components - unsigned int c = 0; - if (mesh->mVertices) - c |= 1; - if (mesh->mNormals) - c |= 2; - if (mesh->mTangents && mesh->mBitangents) - c |= 4; - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n])break; - c |= (8 << n); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n])break; - c |= (16 << n); - } - WriteInteger(c,out); - - aiVector3D minVec, maxVec; - if (mesh->mVertices) { - if (shortened) { - WriteBounds(mesh->mVertices,mesh->mNumVertices,out); - } // else write as usual - else ::fwrite(mesh->mVertices,12*mesh->mNumVertices,1,out); - } - if (mesh->mNormals) { - if (shortened) { - WriteBounds(mesh->mNormals,mesh->mNumVertices,out); - } // else write as usual - else ::fwrite(mesh->mNormals,12*mesh->mNumVertices,1,out); - } - if (mesh->mTangents && mesh->mBitangents) { - if (shortened) { - WriteBounds(mesh->mTangents,mesh->mNumVertices,out); - WriteBounds(mesh->mBitangents,mesh->mNumVertices,out); - } // else write as usual - else { - ::fwrite(mesh->mTangents,12*mesh->mNumVertices,1,out); - ::fwrite(mesh->mBitangents,12*mesh->mNumVertices,1,out); - } - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n])break; - - // write number of UV components - WriteInteger(mesh->mNumUVComponents[n],out); - - if (shortened) { - WriteBounds(mesh->mTextureCoords[n],mesh->mNumVertices,out); - } // else write as usual - else ::fwrite(mesh->mTextureCoords[n],12*mesh->mNumVertices,1,out); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) - break; - - if (shortened) { - WriteBounds(mesh->mColors[n],mesh->mNumVertices,out); - } // else write as usual - else ::fwrite(mesh->mColors[n],16*mesh->mNumVertices,1,out); - } + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + const aiTexture* mesh = scene->mTextures[i]; + len += WriteBinaryTexture(mesh)+8; } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + len += WriteBinaryLight(l)+8; + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + len += WriteBinaryCamera(cam)+8; + } + + ChangeInteger(old,len); + return len; +} + +// ----------------------------------------------------------------------------------- +// Write a binary model dump +void WriteBinaryDump(const aiScene* scene, FILE* _out, const char* src, const char* cmd, + bool _shortened, bool compressed, ImportData& imp) +{ + out = _out; + shortened = _shortened; + + time_t tt = time(NULL); + tm* p = gmtime(&tt); + + // header + fprintf(out,"ASSIMP.binary-dump.%s",asctime(p)); + // == 44 bytes + + WriteInteger(ASSBIN_VERSION_MAJOR); + WriteInteger(ASSBIN_VERSION_MINOR); + WriteInteger(aiGetVersionRevision()); + WriteInteger(aiGetCompileFlags()); + WriteShort(shortened); + WriteShort(compressed); + // == 20 bytes + + char buff[256]; + strncpy(buff,src,256); + fwrite(buff,256,1,out); + + strncpy(buff,cmd,128); + fwrite(buff,128,1,out); + + // leave 64 bytes free for future extensions + memset(buff,0xcd,64); + fwrite(buff,64,1,out); + // == 435 bytes + + // ==== total header size: 512 bytes + assert(ftell(out)==ASSBIN_HEADER_LENGTH); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + WriteBinaryScene(scene); } // ----------------------------------------------------------------------------------- @@ -491,8 +657,8 @@ void WriteNode(const aiNode* node, FILE* out, unsigned int depth) aiString name; ConvertName(name,node->mName); - ::fprintf(out,"%s \n" - "%s\t \n" + fprintf(out,"%s \n" + "%s\t \n" "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" @@ -505,22 +671,25 @@ void WriteNode(const aiNode* node, FILE* out, unsigned int depth) prefix,m.d1,m.d2,m.d3,m.d4,prefix); if (node->mNumMeshes) { - ::fprintf(out, "%s\t\n%s\t", + fprintf(out, "%s\t\n%s\t", prefix,node->mNumMeshes,prefix); for (unsigned int i = 0; i < node->mNumMeshes;++i) { - ::fprintf(out,"%i ",node->mMeshes[i]); + fprintf(out,"%i ",node->mMeshes[i]); } - ::fprintf(out,"\n%s\t\n",prefix); + fprintf(out,"\n%s\t\n",prefix); } - ::fprintf(out,"%s\t%i\n", - prefix,node->mNumChildren); + if (node->mNumChildren) { + fprintf(out,"%s\t\n", + prefix,node->mNumChildren); - for (unsigned int i = 0; i < node->mNumChildren;++i) - WriteNode(node->mChildren[i],out,depth+1); - - ::fprintf(out,"%s\n",prefix); + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteNode(node->mChildren[i],out,depth+2); + } + fprintf(out,"%s\t\n",prefix); + } + fprintf(out,"%s\n",prefix); } // ----------------------------------------------------------------------------------- @@ -533,9 +702,9 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd aiString name; // write header - ::fprintf(out, + fprintf(out, "\n" - "\n\n" + "\n\n" "" " \n\n" - "\n", + "\n", - aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),src,cmd,::asctime(p), - scene->mNumMeshes, scene->mNumMaterials,scene->mNumTextures, - scene->mNumCameras,scene->mNumLights,scene->mNumAnimations); + aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),src,cmd,asctime(p), + scene->mFlags, + 0 /*globalImporter->GetEffectivePostProcessing()*/); // write the node graph - WriteNode(scene->mRootNode, out, 1); + WriteNode(scene->mRootNode, out, 0); +#if 0 // write cameras for (unsigned int i = 0; i < scene->mNumCameras;++i) { aiCamera* cam = scene->mCameras[i]; ConvertName(name,cam->mName); // camera header - ::fprintf(out,"\t\n" + fprintf(out,"\t\n" "\t\t %0 8f %0 8f %0 8f \n" "\t\t %0 8f %0 8f %0 8f \n" "\t\t %0 8f %0 8f %0 8f \n" @@ -581,7 +751,7 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd ConvertName(name,l->mName); // light header - ::fprintf(out,"\t type=\"%s\"\n" + fprintf(out,"\t type=\"%s\"\n" "\t\t %0 8f %0 8f %0 8f \n" "\t\t %0 8f %0 8f %0 8f \n" "\t\t %0 8f %0 8f %0 8f \n", @@ -593,7 +763,7 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); if (l->mType != aiLightSource_DIRECTIONAL) { - ::fprintf(out, + fprintf(out, "\t\t %0 8f %0 8f %0 8f \n" "\t\t %f \n" "\t\t %f \n" @@ -603,339 +773,379 @@ void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd } if (l->mType != aiLightSource_POINT) { - ::fprintf(out, + fprintf(out, "\t\t %0 8f %0 8f %0 8f \n", l->mDirection.x,l->mDirection.y,l->mDirection.z); } if (l->mType == aiLightSource_SPOT) { - ::fprintf(out, + fprintf(out, "\t\t %f \n" "\t\t %f \n", l->mAngleOuterCone,l->mAngleInnerCone); } - ::fprintf(out,"\t\n"); + fprintf(out,"\t\n"); } +#endif // write textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - aiTexture* tex = scene->mTextures[i]; - bool compressed = (tex->mHeight == 0); + if (scene->mNumTextures) { + fprintf(out,"\n",scene->mNumTextures); + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + aiTexture* tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); - // mesh header - ::fprintf(out,"\t \n" - "\t\t %i \n" - "\t\t %i \n" - "\t\t %s \n", - (compressed ? -1 : tex->mWidth), - (compressed ? -1 : tex->mHeight), - (compressed ? "true" : "false")); + // mesh header + fprintf(out,"\t \n", + (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); - if (compressed) { - ::fprintf(out,"\t\t\n",tex->mWidth); + if (compressed) { + fprintf(out,"\t\t \n",tex->mWidth); - if (!shortened) { - const uint8_t* dat = reinterpret_cast(tex->pcData); - for (unsigned int n = 0; n < tex->mWidth;++n) { - ::fprintf(out,"\t\t\t%2x",dat[n]); - if (n && !(n % 50)) { - ::fprintf(out,"\n"); + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth;++n) { + fprintf(out,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); + if (n && !(n % 50)) { + fprintf(out,"\n"); + } } } } - } - else if (!shortened){ - ::fprintf(out,"\t\t \n",tex->mWidth*tex->mHeight*4); + else if (!shortened){ + fprintf(out,"\t\t \n",tex->mWidth*tex->mHeight*4); - const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1; - for (unsigned int y = 0; y < tex->mHeight;++y) { - for (unsigned int x = 0; x < tex->mWidth;++x) { - aiTexel* tx = tex->pcData + y*tex->mWidth+x; - unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; - ::fprintf(out,"\t\t\t%2x %2x %2x %2x",r,g,b,a); + const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight;++y) { + for (unsigned int x = 0; x < tex->mWidth;++x) { + aiTexel* tx = tex->pcData + y*tex->mWidth+x; + unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; + fprintf(out,"\t\t\t%2x %2x %2x %2x",r,g,b,a); - // group by four for readibility - if (0 == (x+y*tex->mWidth) % 4) - ::fprintf(out,"\n"); + // group by four for readibility + if (0 == (x+y*tex->mWidth) % 4) + fprintf(out,"\n"); + } } } + fprintf(out,"\t\t\n\t\n"); } - ::fprintf(out,"\t\t\n\t\n"); + fprintf(out,"\n"); } // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; + if (scene->mNumMaterials) { + fprintf(out,"\n",scene->mNumMaterials); + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; - ::fprintf(out, - "\t\n",mat->mNumProperties); + fprintf(out,"\t\n"); + fprintf(out,"\t\t\n",mat->mNumProperties); + for (unsigned int n = 0; n < mat->mNumProperties;++n) { - for (unsigned int n = 0; n < mat->mNumProperties;++n) { - const aiMaterialProperty* prop = mat->mProperties[n]; - - const char* sz = ""; - if (prop->mType == aiPTI_Float) - sz = "float"; - else if (prop->mType == aiPTI_Integer) - sz = "integer"; - else if (prop->mType == aiPTI_String) - sz = "string"; - else if (prop->mType == aiPTI_Buffer) - sz = "binary_buffer"; - - ::fprintf(out, - "\t\tmKey.data, sz, - TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); - - if (prop->mType == aiPTI_Float) { - ::fprintf(out, - " size=\"%i\">\n\t\t\t", - static_cast(prop->mDataLength/sizeof(float))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) - ::fprintf(out,"%f ",*((float*)(prop->mData+p*sizeof(float)))); - } - else if (prop->mType == aiPTI_Integer) { - ::fprintf(out, - " size=\"%i\">\n\t\t\t", - static_cast(prop->mDataLength/sizeof(int))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) - ::fprintf(out,"%i ",*((int*)(prop->mData+p*sizeof(int)))); - } - else if (prop->mType == aiPTI_Buffer) { - ::fprintf(out, - " size=\"%i\">\n\t\t\t", - prop->mDataLength); - - for (unsigned int p = 0; p < prop->mDataLength;++p) { - ::fprintf(out,"%2x ",prop->mData[p]); - if (p && 0 == p%30) - ::fprintf(out,"\n\t\t\t"); + const aiMaterialProperty* prop = mat->mProperties[n]; + const char* sz = ""; + if (prop->mType == aiPTI_Float) { + sz = "float"; } + else if (prop->mType == aiPTI_Integer) { + sz = "integer"; + } + else if (prop->mType == aiPTI_String) { + sz = "string"; + } + else if (prop->mType == aiPTI_Buffer) { + sz = "binary_buffer"; + } + + fprintf(out,"\t\t\tmKey.data, sz, + TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); + + if (prop->mType == aiPTI_Float) { + fprintf(out," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(float))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { + fprintf(out,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + } + } + else if (prop->mType == aiPTI_Integer) { + fprintf(out," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(int))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { + fprintf(out,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + } + } + else if (prop->mType == aiPTI_Buffer) { + fprintf(out," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength)); + + for (unsigned int p = 0; p < prop->mDataLength;++p) { + fprintf(out,"%2x ",prop->mData[p]); + if (p && 0 == p%30) { + fprintf(out,"\n\t\t\t\t"); + } + } + } + else if (prop->mType == aiPTI_String) { + fprintf(out,">\n\t\t\t\"%s\"",prop->mData+4 /* skip length */); + } + fprintf(out,"\n\t\t\t\n"); } - else if (prop->mType == aiPTI_String) { - ::fprintf(out,">\n\t\t\t\"%s\"",prop->mData+4 /* skip length */); - } - ::fprintf(out,"\n\t\t\n"); + fprintf(out,"\t\t\n"); + fprintf(out,"\t\n"); } - ::fprintf(out,"\t\n"); + fprintf(out,"\n"); } // write animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - aiAnimation* anim = scene->mAnimations[i]; + if (scene->mNumAnimations) { + fprintf(out,"\n",scene->mNumAnimations); + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + aiAnimation* anim = scene->mAnimations[i]; - // anim header - ConvertName(name,anim->mName); - ::fprintf(out,"\t\n" - "\t\t %i \n" - "\t\t %e \n" - "\t\t %e \n", - name.data, anim->mNumChannels,anim->mDuration, anim->mTicksPerSecond); + // anim header + ConvertName(name,anim->mName); + fprintf(out,"\t\n", + name.data, anim->mDuration, anim->mTicksPerSecond); - // write bone animation channels - for (unsigned int n = 0; n < anim->mNumChannels;++n) { - aiNodeAnim* nd = anim->mChannels[n]; + // write bone animation channels + if (anim->mNumChannels) { + fprintf(out,"\t\t\n",anim->mNumChannels); + for (unsigned int n = 0; n < anim->mNumChannels;++n) { + aiNodeAnim* nd = anim->mChannels[n]; - // node anim header - ConvertName(name,nd->mNodeName); - ::fprintf(out,"\t\t\n" - "\t\t\t %i \n" - "\t\t\t %i \n" - "\t\t\t %i \n", - name.data,nd->mNumPositionKeys,nd->mNumScalingKeys,nd->mNumRotationKeys); + // node anim header + ConvertName(name,nd->mNodeName); + fprintf(out,"\t\t\t\n",name.data); - if (!shortened) { - // write position keys - for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { - aiVectorKey* vc = nd->mPositionKeys+a; - ::fprintf(out,"\t\t\t\n" - "\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,a); - } - - // write scaling keys - for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { - aiVectorKey* vc = nd->mScalingKeys+a; - ::fprintf(out,"\t\t\t\n" - "\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,a); - } - - // write rotation keys - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { - aiQuatKey* vc = nd->mRotationKeys+a; - ::fprintf(out,"\t\t\t\n" - "\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w,a); + if (!shortened) { + // write position keys + if (nd->mNumPositionKeys) { + fprintf(out,"\t\t\t\t\n",nd->mNumPositionKeys); + for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { + aiVectorKey* vc = nd->mPositionKeys+a; + fprintf(out,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + fprintf(out,"\t\t\t\t\n"); + } + + // write scaling keys + if (nd->mNumScalingKeys) { + fprintf(out,"\t\t\t\t\n",nd->mNumScalingKeys); + for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { + aiVectorKey* vc = nd->mScalingKeys+a; + fprintf(out,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + fprintf(out,"\t\t\t\t\n"); + } + + // write rotation keys + if (nd->mNumRotationKeys) { + fprintf(out,"\t\t\t\t\n",nd->mNumRotationKeys); + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey* vc = nd->mRotationKeys+a; + fprintf(out,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); + } + fprintf(out,"\t\t\t\t\n"); + } + } + fprintf(out,"\t\t\t\n"); } + fprintf(out,"\t\t\n"); } - ::fprintf(out,"\t\t\n",n); + fprintf(out,"\t\n"); } - ::fprintf(out,"\t\n",i); + fprintf(out,"\n"); } // write meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - aiMesh* mesh = scene->mMeshes[i]; - const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1; + if (scene->mNumMeshes) { + fprintf(out,"\n",scene->mNumMeshes); + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + aiMesh* mesh = scene->mMeshes[i]; + const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1; - // mesh header - ::fprintf(out,"\t\n" - "\t\t %i \n" - "\t\t %i \n" - "\t\t %i \n", - (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), - mesh->mNumVertices,mesh->mNumFaces,mesh->mMaterialIndex); + // mesh header + fprintf(out,"\t\n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mMaterialIndex); - // bones - for (unsigned int n = 0; n < mesh->mNumBones;++n) { - aiBone* bone = mesh->mBones[n]; + // bones + if (mesh->mNumBones) { + fprintf(out,"\t\t\n",mesh->mNumBones); - ConvertName(name,bone->mName); - // bone header - ::fprintf(out,"\t\t\n" - "\t\t\t \n" - "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t \n" - "\t\t\t %i \n", - name.data, - bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, - bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, - bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, - bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4, - bone->mNumWeights); + for (unsigned int n = 0; n < mesh->mNumBones;++n) { + aiBone* bone = mesh->mBones[n]; - if (!shortened) { - // bone weights - for (unsigned int a = 0; a < bone->mNumWeights;++a) { - aiVertexWeight* wght = bone->mWeights+a; + ConvertName(name,bone->mName); + // bone header + fprintf(out,"\t\t\t\n" + "\t\t\t\t \n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t \n", + name.data, + bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); - ::fprintf(out,"\t\t\t\n\t\t\t\t%f\n\t\t\t\n", - wght->mVertexId,wght->mWeight); + if (!shortened && bone->mNumWeights) { + fprintf(out,"\t\t\t\t\n",bone->mNumWeights); + + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + aiVertexWeight* wght = bone->mWeights+a; + + fprintf(out,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", + wght->mVertexId,wght->mWeight); + } + fprintf(out,"\t\t\t\t\n"); + } + fprintf(out,"\t\t\t\n"); } + fprintf(out,"\t\t\n"); } - ::fprintf(out,"\t\t\n",n); - } - // faces - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { - aiFace& f = mesh->mFaces[n]; - ::fprintf(out,"\t\t\n" - "\t\t\t",f.mNumIndices); + // faces + if (!shortened && mesh->mNumFaces) { + fprintf(out,"\t\t\n",mesh->mNumFaces); + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace& f = mesh->mFaces[n]; + fprintf(out,"\t\t\t\n" + "\t\t\t\t",f.mNumIndices); - for (unsigned int j = 0; j < f.mNumIndices;++j) - ::fprintf(out,"%i ",f.mIndices[j]); + for (unsigned int j = 0; j < f.mNumIndices;++j) + fprintf(out,"%i ",f.mIndices[j]); - ::fprintf(out,"\n\t\t\n"); - } - } - - // vertex positions - if (mesh->HasPositions()) { - ::fprintf(out,"\t\t \n"); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mVertices[n].x, - mesh->mVertices[n].y, - mesh->mVertices[n].z); + fprintf(out,"\n\t\t\t\n"); } + fprintf(out,"\t\t\n"); } - else { - } - ::fprintf(out,"\t\t\n"); - } - // vertex normals - if (mesh->HasNormals()) { - ::fprintf(out,"\t\t \n"); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mNormals[n].x, - mesh->mNormals[n].y, - mesh->mNormals[n].z); + // vertex positions + if (mesh->HasPositions()) { + fprintf(out,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } } + fprintf(out,"\t\t\n"); } - else { - } - ::fprintf(out,"\t\t\n"); - } - // vertex tangents and bitangents - if (mesh->HasTangentsAndBitangents()) { - ::fprintf(out,"\t\t \n"); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ::fprintf(out,"\t\t%0 8f %0 8f %0 8f \t %0 8f %0 8f %0 8f\n", - mesh->mTangents[n].x, - mesh->mTangents[n].y, - mesh->mTangents[n].z, - mesh->mBitangents[n].x, - mesh->mBitangents[n].y, - mesh->mBitangents[n].z); + // vertex normals + if (mesh->HasNormals()) { + fprintf(out,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } } - } - else { - } - ::fprintf(out,"\t\t\n"); - } - - // texture coordinates - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - if (!mesh->mTextureCoords[a]) - break; - - ::fprintf(out,"\t\t \n",a,mesh->mNumUVComponents[a]); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mTextureCoords[a][n].x, - mesh->mTextureCoords[a][n].y, - mesh->mTextureCoords[a][n].z); + else { } + fprintf(out,"\t\t\n"); } - else { - } - ::fprintf(out,"\t\t\n"); - } - // vertex colors - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { - if (!mesh->mColors[a]) - break; - //::fprintf(out,"\t\t \n",a); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ::fprintf(out,"\t\t%0 8f %0 8f %0 8f %0 8f\n", - mesh->mColors[a][n].r, - mesh->mColors[a][n].g, - mesh->mColors[a][n].b, - mesh->mColors[a][n].a); + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + fprintf(out,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z); + } } + fprintf(out,"\t\t\n"); + + fprintf(out,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + fprintf(out,"\t\t\n"); } - else { + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + fprintf(out,"\t\t \n",mesh->mNumVertices, + a,mesh->mNumUVComponents[a]); + + if (!shortened) { + if (mesh->mNumUVComponents[a] == 3) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } + else { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y); + } + } + } + fprintf(out,"\t\t\n"); } - ::fprintf(out,"\t\t\n"); + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + fprintf(out,"\t\t \n",mesh->mNumVertices,a); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + fprintf(out,"\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + fprintf(out,"\t\t\n"); + } + fprintf(out,"\t\n"); } - ::fprintf(out,"\t\n"); + fprintf(out,"\n"); } - ::fprintf(out,"\n"); + fprintf(out,"\n"); } // ----------------------------------------------------------------------------------- -int Assimp_Dump (const char** params, unsigned int num) +int Assimp_Dump (const char* const* params, unsigned int num) { if (num < 1) { ::printf("assimp dump: Invalid number of arguments. " @@ -944,7 +1154,7 @@ int Assimp_Dump (const char** params, unsigned int num) } // --help - if (!::strcmp( params[0], "-h") || !::strcmp( params[0], "--help") || !::strcmp( params[0], "-?") ) { + if (!strcmp( params[0], "-h") || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) { printf("%s",AICMD_MSG_DUMP_HELP); return 0; } @@ -976,23 +1186,24 @@ int Assimp_Dump (const char** params, unsigned int num) // process other flags for (unsigned int i = 1; i < num;++i) { if (!params[i])continue; - if (!::strcmp( params[i],"-b") || !::strcmp( params[i],"--binary")) { + if (!strcmp( params[i], "-b") || !strcmp( params[i], "--binary")) { binary = true; } - else if (!::strcmp( params[i],"-s") || !::strcmp( params[i],"--short")) { + else if (!strcmp( params[i], "-s") || !strcmp( params[i], "--short")) { shortened = true; } - else if (!::strcmp( params[i],"-z") || !::strcmp( params[i],"--compressed")) { + 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 (out[0] == '-') { - // take file name from input file std::string::size_type s = in.find_last_of('.'); if (s == std::string::npos) @@ -1020,13 +1231,15 @@ int Assimp_Dump (const char** params, unsigned int num) return 12; } - if (binary) + if (binary) { WriteBinaryDump (scene,o,in.c_str(),cmd.c_str(),shortened,compressed,import); + } else WriteDump (scene,o,in.c_str(),cmd.c_str(),shortened); ::fclose(o); - if (compressed && binary) - CompressBinaryDump(out.c_str(),500); + if (compressed && binary) { + CompressBinaryDump(out.c_str(),ASSBIN_HEADER_LENGTH); + } ::printf("assimp dump: Wrote output dump %s\n",out.c_str()); return 0; diff --git a/tools/assimp_cmd/generic_inserter.hpp b/tools/assimp_cmd/generic_inserter.hpp new file mode 100644 index 000000000..805321995 --- /dev/null +++ b/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 +#include // bad_alloc + + +template +std::basic_ostream& generic_inserter(void (*print)(std::basic_ostream& os, argument_type const& arg), std::basic_ostream& os, argument_type const& arg) +{ + using namespace ::std; + + ios_base::iostate err = ios_base::goodbit; + try + { + typename basic_ostream::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