Quellcode durchsuchen

- 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

aramis_acg vor 15 Jahren
Ursprung
Commit
ff53e84749

+ 893 - 0
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 <actual> <expected>\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 <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)
+	{
+		assert(actual);
+		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] = 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<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 */
+	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 <typename T> 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<std::string,unsigned int> PerChunkCounter;
+	typedef std::pair<std::string,PerChunkCounter> HistoryEntry;
+
+	typedef std::deque<HistoryEntry> ChunkHistory;
+	ChunkHistory history;
+
+	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)) {
+		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<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(&current.first,4,1,ctx.get_expect());
+		res|=fread(&current.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","<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 lenghts 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;
+	};
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+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<aiVector3D>("mPositionKeys");
+	comp.cmp_bounds<aiVector3D>("mRotationKeys");
+	comp.cmp_bounds<aiVector3D>("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");
+	comp.cmp<char>("achFormatHint[0]");
+	comp.cmp<char>("achFormatHint[1]");
+	comp.cmp<char>("achFormatHint[2]");
+	comp.cmp<char>("achFormatHint[3]");
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+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 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;
+}

+ 28 - 20
tools/assimp_cmd/ImageExtractor.cpp

@@ -46,11 +46,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Main.h"
 #include "Main.h"
 
 
 const char* AICMD_MSG_DUMP_HELP_E = 
 const char* AICMD_MSG_DUMP_HELP_E = 
-"todo assimp extract help";
-
+"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 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
 #define AI_EXTRACT_WRITE_BMP_ALPHA 0x1
-
 #include "Compiler/pushpack1.h"
 #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.bfSize      = header.bfOffBits+width*height*numc;
 	header.bfReserved1 = header.bfReserved2 = 0;
 	header.bfReserved1 = header.bfReserved2 = 0;
 
 
-	::fwrite(&header,sizeof(BITMAPFILEHEADER),1,file);
+	fwrite(&header,sizeof(BITMAPFILEHEADER),1,file);
 
 
 	BITMAPINFOHEADER info;
 	BITMAPINFOHEADER info;
 	info.biSize     = 40;
 	info.biSize     = 40;
@@ -151,13 +157,13 @@ int SaveAsBMP (FILE* file, const aiTexel* data, unsigned int width, unsigned int
 	info.biClrUsed = 0;
 	info.biClrUsed = 0;
 	info.biClrImportant = 0;
 	info.biClrImportant = 0;
 
 
-	::fwrite(&info,sizeof(BITMAPINFOHEADER),1,file);
+	fwrite(&info,sizeof(BITMAPINFOHEADER),1,file);
 
 
 	unsigned char* temp = buffer+info.biSizeImage;
 	unsigned char* temp = buffer+info.biSizeImage;
 	const unsigned int row = width*numc;
 	const unsigned int row = width*numc;
 
 
 	for (int y = 0; temp -= row,y < info.biHeight;++y)	{
 	for (int y = 0; temp -= row,y < info.biHeight;++y)	{
-		::fwrite(temp,row,1,file);
+		fwrite(temp,row,1,file);
 	}
 	}
 
 
 	// delete the buffer
 	// delete the buffer
@@ -179,11 +185,11 @@ int SaveAsTGA (FILE* file, const aiTexel* data, unsigned int width, unsigned int
 	head.descriptor |= (1u<<5);
 	head.descriptor |= (1u<<5);
 
 
 	head.imagetype = 2; // actually it's RGBA
 	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 y = 0; y < height; ++y) {
 		for (unsigned int x = 0; x < width; ++x) {
 		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
 // 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) {
 	if (num < 1) {
 		printf("assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n");
 		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
 	// --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);
 		printf("%s",AICMD_MSG_DUMP_HELP_E);
 		return 0;
 		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)		{
 	for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num;++i)		{
 		if (!params[i])continue;
 		if (!params[i])continue;
 
 
-		if (!::strncmp( params[i], "-f",2)) {
+		if (!strncmp( params[i], "-f",2)) {
 			extension = std::string(params[i]+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);
 			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;
 			nosuffix = true;
 		}
 		}
-		else if ( !::strncmp( params[i], "--texture=",10)) {
+		else if ( !strncmp( params[i], "--texture=",10)) {
 			texIdx = ::strtol10(params[i]+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);
 			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;
 			flags |= AI_EXTRACT_WRITE_BMP_ALPHA;
 		}
 		}
+#if 0
 		else {
 		else {
 			printf("Unknown parameter: %s\n",params[i]);
 			printf("Unknown parameter: %s\n",params[i]);
 			return 10;
 			return 10;
 		}
 		}
+#endif
 	}
 	}
 	for (std::string::iterator it = extension.begin();it != extension.end();++it)
 	for (std::string::iterator it = extension.begin();it != extension.end();++it)
 		*it = ::tolower(*it); 
 		*it = ::tolower(*it); 
@@ -310,10 +318,10 @@ int Assimp_Extract (const char** params, unsigned int num)
 	}
 	}
 
 
 	// now write all output textures
 	// 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;
 			continue;
+		}
 
 
 		const aiTexture* tex = scene->mTextures[i];
 		const aiTexture* tex = scene->mTextures[i];
 		std::string out_cpy = out, out_ext = extension;
 		std::string out_cpy = out, out_ext = extension;
@@ -347,7 +355,7 @@ int Assimp_Extract (const char** params, unsigned int num)
 		int m;
 		int m;
 
 
 		if (!tex->mHeight) {
 		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);
 		else m = DoExport(tex,p,extension,flags);
 		::fclose(p);
 		::fclose(p);

+ 27 - 16
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\tknowext - Check whether a file extension is recognized by Assimp\n"
 "\t\textract - Extract an embedded texture from a model\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\tdump    - Convert a model to binary or XML dumps (ASSBIN/ASSXML)\n"
+"\t\tcmpdump - Compare two file dumps produced with \'assimp dump <file> -s ...\'\n"
 "\n\n\tUse \'assimp <verb> --help\' to get detailed help for a command.\n"
 "\n\n\tUse \'assimp <verb> --help\' to get detailed help for a command.\n"
 ;
 ;
 
 
@@ -73,14 +74,13 @@ const char* AICMD_MSG_HELP =
 int main (int argc, char* argv[])
 int main (int argc, char* argv[])
 {
 {
 	if (argc <= 1)	{
 	if (argc <= 1)	{
-
 		printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n");
 		printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n");
 		return 0;
 		return 0;
 	}
 	}
 
 
 	// assimp version
 	// assimp version
 	// Display version information
 	// Display version information
-	if (! ::strcmp(argv[1], "version")) {
+	if (! strcmp(argv[1], "version")) {
 		const unsigned int flags = aiGetCompileFlags();
 		const unsigned int flags = aiGetCompileFlags();
 		printf(AICMD_MSG_ABOUT,
 		printf(AICMD_MSG_ABOUT,
 			aiGetVersionMajor(),
 			aiGetVersionMajor(),
@@ -103,7 +103,14 @@ int main (int argc, char* argv[])
 		return 0;
 		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
 	// construct a global Assimp::Importer instance
+	// because all further tools rely on it
 	Assimp::Importer imp;
 	Assimp::Importer imp;
 	globalImporter = &imp;
 	globalImporter = &imp;
 
 
@@ -138,13 +145,13 @@ int main (int argc, char* argv[])
 	// assimp dump 
 	// assimp dump 
 	// Dump a model to a file 
 	// Dump a model to a file 
 	if (! strcmp(argv[1], "dump")) {
 	if (! strcmp(argv[1], "dump")) {
-		return Assimp_Dump ((const char**)&argv[2],argc-2);
+		return Assimp_Dump (&argv[2],argc-2);
 	}
 	}
 
 
 	// assimp extract 
 	// assimp extract 
 	// Extract an embedded texture from a file
 	// Extract an embedded texture from a file
 	if (! strcmp(argv[1], "extract")) {
 	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");
 	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
 // 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
 	// Attach log streams
 	if (imp.log) {
 	if (imp.log) {
@@ -172,12 +181,12 @@ const aiScene* ImportModel(const ImportData& imp, const std::string& path)
 
 
 	// Now validate this flag combination
 	// Now validate this flag combination
 	if(!globalImporter->ValidateFlags(imp.ppFlags)) {
 	if(!globalImporter->ValidateFlags(imp.ppFlags)) {
-		::printf("ERROR: Unsupported post-processing flags \n");
+		printf("ERROR: Unsupported post-processing flags \n");
 		return NULL;
 		return NULL;
 	}
 	}
 	printf("Validating postprocessing flags ...  OK\n");
 	printf("Validating postprocessing flags ...  OK\n");
 	if (imp.showLog) 
 	if (imp.showLog) 
-		::printf("-----------------------------------------------------------------\n");
+		printf("-----------------------------------------------------------------\n");
 
 
 	// do the actual import, measure time
 	// do the actual import, measure time
 	const clock_t first = clock();
 	const clock_t first = clock();
@@ -205,7 +214,9 @@ const aiScene* ImportModel(const ImportData& imp, const std::string& path)
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 // Process standard arguments
 // Process standard arguments
-int ProcessStandardArguments(ImportData& fill, const char** params,
+int ProcessStandardArguments(
+	ImportData& fill, 
+	const char* const * params,
 	unsigned int num)
 	unsigned int num)
 {
 {
 	// -ptv    --pretransform-vertices
 	// -ptv    --pretransform-vertices
@@ -237,11 +248,11 @@ int ProcessStandardArguments(ImportData& fill, const char** params,
 
 
 	for (unsigned int i = 0; i < num;++i) 
 	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")) {
 		if (! strcmp(params[i], "-ptv") || ! strcmp(params[i], "--pretransform-vertices")) {
 			fill.ppFlags |= aiProcess_PreTransformVertices;
 			fill.ppFlags |= aiProcess_PreTransformVertices;
 		}
 		}
@@ -350,10 +361,10 @@ int ProcessStandardArguments(ImportData& fill, const char** params,
 				fill.logFile = "assimp-log.txt";
 				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)
 	if (fill.logFile.length() || fill.showLog || fill.verbose)

+ 30 - 18
tools/assimp_cmd/Main.h

@@ -71,8 +71,7 @@ using namespace Assimp;
 extern Assimp::Importer* globalImporter;
 extern Assimp::Importer* globalImporter;
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
-/** @brief Defines common import parameters
- */
+/** Defines common import parameters */
 struct ImportData
 struct ImportData
 {
 {
 	ImportData()
 	ImportData()
@@ -101,39 +100,52 @@ struct ImportData
 };
 };
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
-/** @brief Process standard arguments
+/** Process standard arguments
  *
  *
  *  @param fill Filled by function
  *  @param fill Filled by function
  *  @param params Command line parameters to be processed
  *  @param params Command line parameters to be processed
  *  @param num NUmber of params
  *  @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);
 	unsigned int num);
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
-/** @brief Import a specific model file
+/** Import a specific model file
  *  @param imp Import configuration to be used
  *  @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 params Command line parameters to 'assimp dumb'
  *  @param Number of params
  *  @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 params Command line parameters to 'assimp extract'
  *  @param Number of params
  *  @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
 /** @brief assimp info utility

Datei-Diff unterdrückt, da er zu groß ist
+ 790 - 580
tools/assimp_cmd/WriteDumb.cpp


+ 113 - 0
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

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.