new stuff

This commit is contained in:
Tarion 2026-07-03 03:41:25 +02:00
parent 8998bc3936
commit 64c8492e5c
No known key found for this signature in database
6907 changed files with 3401899 additions and 0 deletions

View file

@ -0,0 +1,82 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
#
# Copyright (c) 2006-2026, assimp team
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
# with or without modification, are permitted provided that the
# following conditions are met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# * Neither the name of the assimp team, nor the names of its
# contributors may be used to endorse or promote products
# derived from this software without specific prior
# written permission of the assimp team.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#----------------------------------------------------------------------
cmake_minimum_required( VERSION 3.10 )
INCLUDE_DIRECTORIES(
${Assimp_SOURCE_DIR}/include
${Assimp_SOURCE_DIR}/code
${Assimp_BINARY_DIR}/tools/assimp_cmd
)
LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib )
if(WIN32)
set ( ASSIMP_CMD_RC assimp_cmd.rc)
endif()
ADD_EXECUTABLE( assimp_cmd
CompareDump.cpp
ImageExtractor.cpp
Main.cpp
Main.h
WriteDump.cpp
Info.cpp
Export.cpp
${ASSIMP_CMD_RC}
)
IF (ASSIMP_WARNINGS_AS_ERRORS)
IF (MSVC)
TARGET_COMPILE_OPTIONS(assimp_cmd PRIVATE /W4 /WX)
ELSE()
TARGET_COMPILE_OPTIONS(assimp_cmd PRIVATE -Wall -Werror)
ENDIF()
ENDIF()
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp_cmd)
SET_PROPERTY(TARGET assimp_cmd PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
TARGET_LINK_LIBRARIES( assimp_cmd assimp ${ZLIB_LIBRARIES} )
SET_TARGET_PROPERTIES( assimp_cmd PROPERTIES
OUTPUT_NAME assimp
)
INSTALL( TARGETS assimp_cmd
DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-bin
)

View file

@ -0,0 +1,955 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file CompareDump.cpp
* @brief Implementation of the 'assimp cmpdmp', which compares
* two model dumps for equality. It plays an important role
* in the regression test suite.
*/
#include "Main.h"
const char* AICMD_MSG_CMPDUMP_HELP =
"assimp cmpdump <actual> <expected>\n"
"\tCompare two short dumps produced with \'assimp dump <..> -s\' for equality.\n"
;
#include "Common/assbin_chunks.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
#include "generic_inserter.hpp"
#include <map>
#include <deque>
#include <stack>
#include <sstream>
#include <iostream>
#include <assimp/ai_assert.h>
// get << for aiString
template <typename char_t, typename traits_t>
void mysprint(std::basic_ostream<char_t, traits_t>& os, const aiString& vec) {
os << "[length: \'" << std::dec << vec.length << "\' content: \'" << vec.data << "\']";
}
template <typename char_t, typename traits_t>
std::basic_ostream<char_t, traits_t>& operator<< (std::basic_ostream<char_t, traits_t>& os, const aiString& vec) {
return generic_inserter(mysprint<char_t,traits_t>, os, vec);
}
class sliced_chunk_iterator;
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class compare_fails_exception
///
/// @brief Sentinel exception to return quickly from deeply nested control paths
////////////////////////////////////////////////////////////////////////////////////////////////////
class compare_fails_exception final : public virtual std::exception {
public:
enum {MAX_ERR_LEN = 4096};
/* public c'tors */
compare_fails_exception(const char* msg) {
strncpy(mywhat,msg,MAX_ERR_LEN-1);
strcat(mywhat,"\n");
}
/* public member functions */
const char* what() const throw() {
return mywhat;
}
private:
char mywhat[MAX_ERR_LEN+1];
};
#define MY_FLT_EPSILON 1e-1f
#define MY_DBL_EPSILON 1e-1
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class comparer_context
///
/// @brief Record our way through the files to be compared and dump useful information if we fail.
////////////////////////////////////////////////////////////////////////////////////////////////////
class comparer_context {
friend class sliced_chunk_iterator;
public:
/* construct given two file handles to compare */
comparer_context(FILE* actual,FILE* expect)
: actual(actual)
, expect(expect)
, cnt_chunks(0)
{
ai_assert(actual);
ai_assert(expect);
fseek(actual,0,SEEK_END);
lengths.emplace(static_cast<uint32_t>(ftell(actual)),0);
fseek(actual,0,SEEK_SET);
history.emplace_back("---",PerChunkCounter());
}
public:
/* set new scope */
void push_elem(const char* msg) {
const std::string s = msg;
PerChunkCounter::const_iterator it = history.back().second.find(s);
if(it != history.back().second.end()) {
++history.back().second[s];
}
else history.back().second[s] = 0;
history.emplace_back(s,PerChunkCounter());
debug_trace.push_back("PUSH " + s);
}
/* leave current scope */
void pop_elem() {
ai_assert(history.size());
debug_trace.push_back("POP "+ history.back().first);
history.pop_back();
}
/* push current chunk length and start offset on top of stack */
void push_length(uint32_t nl, uint32_t start) {
lengths.emplace(nl,start);
++cnt_chunks;
}
/* pop the chunk length stack */
void pop_length() {
ai_assert(lengths.size());
lengths.pop();
}
/* access the current chunk length */
uint32_t get_latest_chunk_length() {
ai_assert(lengths.size());
return lengths.top().first;
}
/* access the current chunk start offset */
uint32_t get_latest_chunk_start() {
ai_assert(lengths.size());
return lengths.top().second;
}
/* total number of chunk headers passed so far*/
uint32_t get_num_chunks() {
return cnt_chunks;
}
/* get ACTUAL file desc. != NULL */
FILE* get_actual() const {
return actual;
}
/* get EXPECT file desc. != NULL */
FILE* get_expect() const {
return expect;
}
/* compare next T from both streams, name occurs in error messages */
template<typename T> T cmp(const std::string& name) {
T a,e;
read(a,e);
if(a != e) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is " << a,
ss.str()),name);
}
// std::cout << name << " " << std::hex << a << std::endl;
return a;
}
/* compare next num T's from both streams, name occurs in error messages */
template<typename T> void cmp(size_t num,const std::string& name) {
for(size_t n = 0; n < num; ++n) {
std::stringstream ss;
cmp<T>((ss<<name<<"["<<n<<"]",ss.str()));
// std::cout << name << " " << std::hex << a << std::endl;
}
}
/* Bounds of an aiVector3D array (separate function
* because partial specializations of member functions are illegal--)*/
template<typename T> void cmp_bounds(const std::string& name) {
cmp<T> (name+".<minimum-value>");
cmp<T> (name+".<maximum-value>");
}
private:
/* Report failure */
AI_WONT_RETURN void failure(const std::string& err, const std::string& name) AI_WONT_RETURN_SUFFIX {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Files are different at "
<< history.back().first
<< "."
<< name
<< ".\nError is: "
<< err
<< ".\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
/** print our 'stack' */
std::string print_hierarchy() {
std::stringstream ss;
ss << "\n";
const char* last = history.back().first.c_str();
std::string pad;
for(ChunkHistory::reverse_iterator rev = history.rbegin(),
end = history.rend(); rev != end; ++rev, pad += " ")
{
ss << pad << (*rev).first << "(Index: " << (*rev).second[last] << ")" << "\n";
last = (*rev).first.c_str();
}
ss << std::endl << "Debug trace: "<< "\n";
for (std::vector<std::string>::const_iterator it = debug_trace.begin(); it != debug_trace.end(); ++it) {
ss << *it << "\n";
}
ss << std::flush;
return ss.str();
}
/* read from both streams at the same time */
template <typename T> void read(T& filla,T& fille) {
if(1 != fread(&filla,sizeof(T),1,actual)) {
EOFActual();
}
if(1 != fread(&fille,sizeof(T),1,expect)) {
EOFExpect();
}
}
private:
void EOFActual() {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Unexpected EOF reading ACTUAL.\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
void EOFExpect() {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Unexpected EOF reading EXPECT.\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
FILE *const actual, *const expect;
typedef std::map<std::string,unsigned int> PerChunkCounter;
typedef std::pair<std::string,PerChunkCounter> HistoryEntry;
typedef std::deque<HistoryEntry> ChunkHistory;
ChunkHistory history;
std::vector<std::string> debug_trace;
typedef std::stack<std::pair<uint32_t,uint32_t> > LengthStack;
LengthStack lengths;
uint32_t cnt_chunks;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/* specialization for aiString (it needs separate handling because its on-disk representation
* differs from its binary representation in memory and can't be treated as an array of n T's.*/
template <> void comparer_context :: read<aiString>(aiString& filla,aiString& fille) {
uint32_t lena,lene;
read(lena,lene);
if(lena && 1 != fread(&filla.data,lena,1,actual)) {
EOFActual();
}
if(lene && 1 != fread(&fille.data,lene,1,expect)) {
EOFExpect();
}
fille.data[fille.length=static_cast<unsigned int>(lene)] = '\0';
filla.data[filla.length=static_cast<unsigned int>(lena)] = '\0';
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for float, uses epsilon for comparisons*/
template<> float comparer_context :: cmp<float>(const std::string& name)
{
float a,e,t;
read(a,e);
if((t=fabs(a-e)) > MY_FLT_EPSILON) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is "
<< a << " (delta is " << t << ")", ss.str()),name);
}
return a;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for double, uses epsilon for comparisons*/
template<> double comparer_context :: cmp<double>(const std::string& name)
{
double a,e,t;
read(a,e);
if((t=fabs(a-e)) > MY_DBL_EPSILON) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is "
<< a << " (delta is " << t << ")", ss.str()),name);
}
return a;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVector3D */
template<> aiVector3D comparer_context :: cmp<aiVector3D >(const std::string& name)
{
const float x = cmp<float>(name+".x");
const float y = cmp<float>(name+".y");
const float z = cmp<float>(name+".z");
return aiVector3D(x,y,z);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiColor4D */
template<> aiColor4D comparer_context :: cmp<aiColor4D >(const std::string& name)
{
const float r = cmp<float>(name+".r");
const float g = cmp<float>(name+".g");
const float b = cmp<float>(name+".b");
const float a = cmp<float>(name+".a");
return aiColor4D(r,g,b,a);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiQuaternion */
template<> aiQuaternion comparer_context :: cmp<aiQuaternion >(const std::string& name)
{
const float w = cmp<float>(name+".w");
const float x = cmp<float>(name+".x");
const float y = cmp<float>(name+".y");
const float z = cmp<float>(name+".z");
return aiQuaternion(w,x,y,z);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiQuatKey */
template<> aiQuatKey comparer_context :: cmp<aiQuatKey >(const std::string& name)
{
const double mTime = cmp<double>(name+".mTime");
const aiQuaternion mValue = cmp<aiQuaternion>(name+".mValue");
return aiQuatKey(mTime,mValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVectorKey */
template<> aiVectorKey comparer_context :: cmp<aiVectorKey >(const std::string& name)
{
const double mTime = cmp<double>(name+".mTime");
const aiVector3D mValue = cmp<aiVector3D>(name+".mValue");
return aiVectorKey(mTime,mValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiMatrix4x4 */
template<> aiMatrix4x4 comparer_context :: cmp<aiMatrix4x4 >(const std::string& name)
{
aiMatrix4x4 res;
for(unsigned int i = 0; i < 4; ++i) {
for(unsigned int j = 0; j < 4; ++j) {
std::stringstream ss;
res[i][j] = cmp<float>(name+(ss<<".m"<<i<<j,ss.str()));
}
}
return res;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVertexWeight */
template<> aiVertexWeight comparer_context :: cmp<aiVertexWeight >(const std::string& name)
{
const unsigned int mVertexId = cmp<unsigned int>(name+".mVertexId");
const float mWeight = cmp<float>(name+".mWeight");
return aiVertexWeight(mVertexId,mWeight);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class sliced_chunk_iterator
///
/// @brief Helper to iterate easily through corresponding chunks of two dumps simultaneously.
///
/// Not a *real* iterator, doesn't fully conform to the isocpp iterator spec
////////////////////////////////////////////////////////////////////////////////////////////////////
class sliced_chunk_iterator {
friend class sliced_chunk_reader;
sliced_chunk_iterator(comparer_context& ctx, long end)
: ctx(ctx)
, endit(false)
, next(std::numeric_limits<long>::max())
, end(end)
{
load_next();
}
public:
~sliced_chunk_iterator() {
fseek(ctx.get_actual(),end,SEEK_SET);
fseek(ctx.get_expect(),end,SEEK_SET);
}
public:
/* get current chunk head */
typedef std::pair<uint32_t,uint32_t> Chunk;
const Chunk& operator*() {
return current;
}
/* get to next chunk head */
const sliced_chunk_iterator& operator++() {
cleanup();
load_next();
return *this;
}
/* */
bool is_end() const {
return endit;
}
private:
/* get to the end of *this* chunk */
void cleanup() {
if(next != std::numeric_limits<long>::max()) {
fseek(ctx.get_actual(),next,SEEK_SET);
fseek(ctx.get_expect(),next,SEEK_SET);
ctx.pop_length();
}
}
/* advance to the next chunk */
void load_next() {
Chunk actual;
size_t res=0;
const long cur = ftell(ctx.get_expect());
if(end-cur<8) {
current = std::make_pair(0u,0u);
endit = true;
return;
}
res|=fread(&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("IO Error reading chunk head, dumps are malformed","<ChunkHead>");
}
if (current.first != actual.first) {
std::stringstream ss;
ctx.failure((ss
<<"Chunk headers do not match. EXPECT: "
<< std::hex << current.first
<<" ACTUAL: "
<< /*std::hex */actual.first,
ss.str()),
"<ChunkHead>");
}
if (current.first != actual.first) {
std::stringstream ss;
ctx.failure((ss
<<"Chunk lengths do not match. EXPECT: "
<<current.second
<<" ACTUAL: "
<< actual.second,
ss.str()),
"<ChunkHead>");
}
next = cur+current.second+8;
ctx.push_length(current.second,cur+8);
}
comparer_context& ctx;
Chunk current;
bool endit;
long next,end;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class sliced_chunk_reader
///
/// @brief Helper to iterate easily through corresponding chunks of two dumps simultaneously.
////////////////////////////////////////////////////////////////////////////////////////////////////
class sliced_chunk_reader {
public:
//
sliced_chunk_reader(comparer_context& ctx)
: ctx(ctx)
{}
//
~sliced_chunk_reader() = default;
public:
sliced_chunk_iterator begin() const {
return sliced_chunk_iterator(ctx,ctx.get_latest_chunk_length()+
ctx.get_latest_chunk_start());
}
private:
comparer_context& ctx;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class scoped_chunk
///
/// @brief Utility to simplify usage of comparer_context.push_elem/pop_elem
////////////////////////////////////////////////////////////////////////////////////////////////////
class scoped_chunk {
public:
//
scoped_chunk(comparer_context& ctx,const char* msg)
: ctx(ctx)
{
ctx.push_elem(msg);
}
//
~scoped_chunk()
{
ctx.pop_elem();
}
private:
comparer_context& ctx;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyMaterialProperty(comparer_context& comp) {
scoped_chunk chunk(comp,"aiMaterialProperty");
comp.cmp<aiString>("mKey");
comp.cmp<uint32_t>("mSemantic");
comp.cmp<uint32_t>("mIndex");
const uint32_t length = comp.cmp<uint32_t>("mDataLength");
const aiPropertyTypeInfo type = static_cast<aiPropertyTypeInfo>(
comp.cmp<uint32_t>("mType"));
switch (type)
{
case aiPTI_Float:
comp.cmp<float>(length/4,"mData");
break;
case aiPTI_String:
comp.cmp<aiString>("mData");
break;
case aiPTI_Integer:
comp.cmp<uint32_t>(length/4,"mData");
break;
case aiPTI_Buffer:
comp.cmp<uint8_t>(length,"mData");
break;
default:
break;
};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyMaterial(comparer_context& comp) {
scoped_chunk chunk(comp,"aiMaterial");
comp.cmp<uint32_t>("aiMaterial::mNumProperties");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AIMATERIALPROPERTY) {
CompareOnTheFlyMaterialProperty(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyBone(comparer_context& comp) {
scoped_chunk chunk(comp,"aiBone");
comp.cmp<aiString>("mName");
comp.cmp<uint32_t>("mNumWeights");
comp.cmp<aiMatrix4x4>("mOffsetMatrix");
comp.cmp_bounds<aiVertexWeight>("mWeights");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyNodeAnim(comparer_context& comp) {
scoped_chunk chunk(comp,"aiNodeAnim");
comp.cmp<aiString>("mNodeName");
comp.cmp<uint32_t>("mNumPositionKeys");
comp.cmp<uint32_t>("mNumRotationKeys");
comp.cmp<uint32_t>("mNumScalingKeys");
comp.cmp<uint32_t>("mPreState");
comp.cmp<uint32_t>("mPostState");
comp.cmp_bounds<aiVectorKey>("mPositionKeys");
comp.cmp_bounds<aiQuatKey>("mRotationKeys");
comp.cmp_bounds<aiVectorKey>("mScalingKeys");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyMesh(comparer_context& comp) {
scoped_chunk chunk(comp,"aiMesh");
comp.cmp<uint32_t>("mPrimitiveTypes");
comp.cmp<uint32_t>("mNumVertices");
const uint32_t nf = comp.cmp<uint32_t>("mNumFaces");
comp.cmp<uint32_t>("mNumBones");
comp.cmp<uint32_t>("mMaterialIndex");
const uint32_t present = comp.cmp<uint32_t>("<vertex-components-present>");
if(present & ASSBIN_MESH_HAS_POSITIONS) {
comp.cmp_bounds<aiVector3D>("mVertices");
}
if(present & ASSBIN_MESH_HAS_NORMALS) {
comp.cmp_bounds<aiVector3D>("mNormals");
}
if(present & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
comp.cmp_bounds<aiVector3D>("mTangents");
comp.cmp_bounds<aiVector3D>("mBitangents");
}
for(unsigned int i = 0; present & ASSBIN_MESH_HAS_COLOR(i); ++i) {
std::stringstream ss;
comp.cmp_bounds<aiColor4D>((ss<<"mColors["<<i<<"]",ss.str()));
}
for(unsigned int i = 0; present & ASSBIN_MESH_HAS_TEXCOORD(i); ++i) {
std::stringstream ss;
comp.cmp<uint32_t>((ss<<"mNumUVComponents["<<i<<"]",ss.str()));
comp.cmp_bounds<aiVector3D>((ss.clear(),ss<<"mTextureCoords["<<i<<"]",ss.str()));
}
for(unsigned int i = 0; i< ((nf+511)/512); ++i) {
std::stringstream ss;
comp.cmp<uint32_t>((ss<<"mFaces["<<i*512<<"-"<<std::min(static_cast<
uint32_t>((i+1)*512),nf)<<"]",ss.str()));
}
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AIBONE) {
CompareOnTheFlyBone(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyCamera(comparer_context& comp) {
scoped_chunk chunk(comp,"aiCamera");
comp.cmp<aiString>("mName");
comp.cmp<aiVector3D>("mPosition");
comp.cmp<aiVector3D>("mLookAt");
comp.cmp<aiVector3D>("mUp");
comp.cmp<float>("mHorizontalFOV");
comp.cmp<float>("mClipPlaneNear");
comp.cmp<float>("mClipPlaneFar");
comp.cmp<float>("mAspect");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyLight(comparer_context& comp) {
scoped_chunk chunk(comp,"aiLight");
comp.cmp<aiString>("mName");
const aiLightSourceType type = static_cast<aiLightSourceType>(
comp.cmp<uint32_t>("mType"));
if(type!=aiLightSource_DIRECTIONAL) {
comp.cmp<float>("mAttenuationConstant");
comp.cmp<float>("mAttenuationLinear");
comp.cmp<float>("mAttenuationQuadratic");
}
comp.cmp<aiVector3D>("mColorDiffuse");
comp.cmp<aiVector3D>("mColorSpecular");
comp.cmp<aiVector3D>("mColorAmbient");
if(type==aiLightSource_SPOT) {
comp.cmp<float>("mAngleInnerCone");
comp.cmp<float>("mAngleOuterCone");
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyAnimation(comparer_context& comp) {
scoped_chunk chunk(comp,"aiAnimation");
comp.cmp<aiString>("mName");
comp.cmp<double>("mDuration");
comp.cmp<double>("mTicksPerSecond");
comp.cmp<uint32_t>("mNumChannels");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AINODEANIM) {
CompareOnTheFlyNodeAnim(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyTexture(comparer_context& comp) {
scoped_chunk chunk(comp,"aiTexture");
const uint32_t w = comp.cmp<uint32_t>("mWidth");
const uint32_t h = comp.cmp<uint32_t>("mHeight");
(void)w; (void)h;
comp.cmp<char>("achFormatHint[0]");
comp.cmp<char>("achFormatHint[1]");
comp.cmp<char>("achFormatHint[2]");
comp.cmp<char>("achFormatHint[3]");
comp.cmp<char>("achFormatHint[4]");
comp.cmp<char>("achFormatHint[5]");
comp.cmp<char>("achFormatHint[6]");
comp.cmp<char>("achFormatHint[7]");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyNode(comparer_context& comp) {
scoped_chunk chunk(comp,"aiNode");
comp.cmp<aiString>("mName");
comp.cmp<aiMatrix4x4>("mTransformation");
comp.cmp<uint32_t>("mNumChildren");
comp.cmp<uint32_t>(comp.cmp<uint32_t>("mNumMeshes"),"mMeshes");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AINODE) {
CompareOnTheFlyNode(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyScene(comparer_context& comp) {
scoped_chunk chunk(comp,"aiScene");
comp.cmp<uint32_t>("mFlags");
comp.cmp<uint32_t>("mNumMeshes");
comp.cmp<uint32_t>("mNumMaterials");
comp.cmp<uint32_t>("mNumAnimations");
comp.cmp<uint32_t>("mNumTextures");
comp.cmp<uint32_t>("mNumLights");
comp.cmp<uint32_t>("mNumCameras");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AIMATERIAL) {
CompareOnTheFlyMaterial(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AITEXTURE) {
CompareOnTheFlyTexture(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AIMESH) {
CompareOnTheFlyMesh(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AIANIMATION) {
CompareOnTheFlyAnimation(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AICAMERA) {
CompareOnTheFlyCamera(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AILIGHT) {
CompareOnTheFlyLight(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AINODE) {
CompareOnTheFlyNode(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFly(comparer_context& comp)
{
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AISCENE) {
CompareOnTheFlyScene(comp);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CheckHeader(comparer_context& comp)
{
fseek(comp.get_actual(),ASSBIN_HEADER_LENGTH,SEEK_CUR);
fseek(comp.get_expect(),ASSBIN_HEADER_LENGTH,SEEK_CUR);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
int Assimp_CompareDump (const char* const* params, unsigned int num)
{
// --help
if ((num == 1 && !strcmp( params[0], "-h")) || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) {
printf("%s",AICMD_MSG_CMPDUMP_HELP);
return AssimpCmdError::Success;
}
// assimp cmpdump actual expected
if (num < 2) {
std::cout << "assimp cmpdump: Invalid number of arguments. "
"See \'assimp cmpdump --help\'\r\n" << std::endl;
return AssimpCmdError::InvalidNumberOfArguments;
}
if(!strcmp(params[0],params[1])) {
std::cout << "assimp cmpdump: same file, same content." << std::endl;
return AssimpCmdError::Success;
}
class file_ptr
{
public:
file_ptr(FILE *p)
: m_file(p)
{}
~file_ptr()
{
if (m_file)
{
fclose(m_file);
m_file = nullptr;
}
}
operator FILE *() { return m_file; }
private:
FILE *m_file;
};
file_ptr actual(fopen(params[0],"rb"));
if (!actual) {
std::cout << "assimp cmpdump: Failure reading ACTUAL data from " <<
params[0] << std::endl;
return AssimpCmdError::FailedToLoadInputFile;
}
file_ptr expected(fopen(params[1],"rb"));
if (!expected) {
std::cout << "assimp cmpdump: Failure reading EXPECT data from " <<
params[1] << std::endl;
return AssimpCmdCompareDumpError::FailedToLoadExpectedInputFile;
}
comparer_context comp(actual,expected);
try {
CheckHeader(comp);
CompareOnTheFly(comp);
}
catch(const compare_fails_exception& ex) {
printf("%s",ex.what());
return AssimpCmdCompareDumpError::FileComparaisonFailure;
}
catch(...) {
// we don't bother checking too rigourously here, so
// we might end up here ...
std::cout << "Unknown failure, are the input files well-defined?";
return AssimpCmdCompareDumpError::UnknownFailure;
}
std::cout << "Success (totally " << std::dec << comp.get_num_chunks() <<
" chunks)" << std::endl;
return AssimpCmdError::Success;
}

View file

@ -0,0 +1,168 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Export.cpp
* @brief Implementation of the 'assimp export' utility
*/
#include "Main.h"
#include <assimp/ParsingUtils.h>
#include <assimp/StringUtils.h>
#ifndef ASSIMP_BUILD_NO_EXPORT
const char *AICMD_MSG_EXPORT_HELP_E =
"assimp export <model> [<out>] [-f<h>] [common parameters]\n"
"\t -f<h> Specify the file format. If omitted, the output format is \n"
"\t\tderived from the file extension of the given output file \n"
"\t[See the assimp_cmd docs for a full list of all common parameters] \n";
// -----------------------------------------------------------------------------------
size_t GetMatchingFormat(const std::string &outf, bool byext = false) {
for (size_t i = 0, end = globalExporter->GetExportFormatCount(); i < end; ++i) {
const aiExportFormatDesc *const e = globalExporter->GetExportFormatDescription(i);
if (outf == (byext ? e->fileExtension : e->id)) {
return i;
}
}
return SIZE_MAX;
}
// -----------------------------------------------------------------------------------
int Assimp_Export(const char *const *params, unsigned int num) {
const char *const invalid = "assimp export: Invalid number of arguments. See \'assimp export --help\'\n";
if (num < 1) {
printf(invalid);
return AssimpCmdError::InvalidNumberOfArguments;
}
// --help
if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
printf("%s", AICMD_MSG_EXPORT_HELP_E);
return AssimpCmdError::Success;
}
std::string in = std::string(params[0]);
std::string out = (num > 1 ? std::string(params[1]) : "-"), outext;
//
const std::string::size_type s = out.find_last_of('.');
if (s != std::string::npos) {
outext = out.substr(s + 1);
out = out.substr(0, s);
}
// get import flags
ImportData import;
ProcessStandardArguments(import, params + 1, num - 1);
// process other flags
std::string outf = "";
for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num; ++i) {
if (!params[i]) {
continue;
}
if (!strncmp(params[i], "-f", 2)) {
if (strncmp(params[i], "-fi", 3))
outf = std::string(params[i] + 2);
} else if (!strncmp(params[i], "--format=", 9)) {
outf = std::string(params[i] + 9);
}
}
std::transform(outf.begin(), outf.end(), outf.begin(), ai_tolower<char>);
// convert the output format to a format id
size_t outfi = GetMatchingFormat(outf);
if (outfi == SIZE_MAX) {
if (outf.length()) {
printf("assimp export: warning, format id \'%s\' is unknown\n", outf.c_str());
}
// retry to see if we know it as file extension
outfi = GetMatchingFormat(outf, true);
if (outfi == SIZE_MAX) {
// retry to see if we know the file extension of the output file
outfi = GetMatchingFormat(outext, true);
if (outfi == SIZE_MAX) {
// still no match -> failure
printf("assimp export: no output format specified and I failed to guess it\n");
return -23;
}
} else {
outext = outf;
}
}
// if no output file is specified, take the file name from input file
if (out[0] == '-') {
std::string::size_type pos = in.find_last_of('.');
if (pos == std::string::npos) {
pos = in.length();
}
out = in.substr(0, pos);
}
const aiExportFormatDesc *const e = globalExporter->GetExportFormatDescription(outfi);
printf("assimp export: select file format: \'%s\' (%s)\n", e->id, e->description);
// import the model
const aiScene *scene = ImportModel(import, in);
if (!scene) {
return AssimpCmdExportError::FailedToImportModel;
}
// derive the final file name
if (!outext.empty()) {
out += "." + outext;
}
// and call the export routine
if (!ExportModel(scene, import, out, e->id)) {
return AssimpCmdExportError::FailedToExportModel;
}
printf("assimp export: wrote output file: %s\n", out.c_str());
return AssimpCmdError::Success;
}
#endif // ASSIMP_BUILD_NO_EXPORT

View file

@ -0,0 +1,361 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file ImageExtractor.cpp
* @brief Implementation of the 'assimp extract' utility
*/
#include "Main.h"
#include <assimp/ParsingUtils.h>
#include <assimp/StringComparison.h>
#include <assimp/fast_atof.h>
static const char *AICMD_MSG_DUMP_HELP_E =
"assimp extract <model> [<out>] [-t<n>] [-f<fmt>] [-ba] [-s] [common parameters]\n"
"\t -ba Writes BMP's with alpha channel\n"
"\t -t<n> Zero-based index of the texture to be extracted \n"
"\t -f<f> Specify the file format if <out> is omitted \n"
"\t[See the assimp_cmd docs for a full list of all common parameters] \n"
"\t -cfast Fast post processing preset, runs just a few important steps \n"
"\t -cdefault Default post processing: runs all recommended steps\n"
"\t -cfull Fires almost all post processing steps \n";
#define AI_EXTRACT_WRITE_BMP_ALPHA 0x1
#include <assimp/Compiler/pushpack1.h>
// -----------------------------------------------------------------------------------
// Data structure for the first header of a BMP
struct BITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} PACK_STRUCT;
// -----------------------------------------------------------------------------------
// Data structure for the second header of a BMP
struct BITMAPINFOHEADER {
int32_t biSize;
int32_t biWidth;
int32_t biHeight;
int16_t biPlanes;
int16_t biBitCount;
uint32_t biCompression;
int32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
int32_t biClrUsed;
int32_t biClrImportant;
// pixel data follows header
} PACK_STRUCT;
// -----------------------------------------------------------------------------------
// Data structure for the header of a TGA
struct TGA_HEADER {
uint8_t identsize; // size of ID field that follows 18 byte header (0 usually)
uint8_t colourmaptype; // type of colour map 0=none, 1=has palette
uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=gray,+8=rle packed
uint16_t colourmapstart; // first colour map entry in palette
uint16_t colourmaplength; // number of colors in palette
uint8_t colourmapbits; // number of bits per palette entry 15,16,24,32
uint16_t xstart; // image x origin
uint16_t ystart; // image y origin
uint16_t width; // image width in pixels
uint16_t height; // image height in pixels
uint8_t bits; // image bits per pixel 8,16,24,32
uint8_t descriptor; // image descriptor bits (vh flip bits)
// pixel data follows header
} PACK_STRUCT;
#include <assimp/Compiler/poppack1.h>
// -----------------------------------------------------------------------------------
// Save a texture as bitmap
int SaveAsBMP(FILE *file, const aiTexel *data, unsigned int width, unsigned int height, bool SaveAlpha = false) {
if (!file || !data) {
return 1;
}
const unsigned int numc = (SaveAlpha ? 4 : 3);
unsigned char *buffer = new unsigned char[width * height * numc];
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) {
unsigned char *s = &buffer[(y * width + x) * numc];
const aiTexel *t = &data[y * width + x];
s[0] = t->b;
s[1] = t->g;
s[2] = t->r;
if (4 == numc) {
s[3] = t->a;
}
}
}
BITMAPFILEHEADER header;
header.bfType = 'B' | (int('M') << 8u);
header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
header.bfSize = header.bfOffBits + width * height * numc;
header.bfReserved1 = header.bfReserved2 = 0;
fwrite(&header, sizeof(BITMAPFILEHEADER), 1, file);
BITMAPINFOHEADER info;
info.biSize = 40;
info.biWidth = width;
info.biHeight = height;
info.biPlanes = 1;
info.biBitCount = (int16_t)numc << 3;
info.biCompression = 0;
info.biSizeImage = width * height * numc;
info.biXPelsPerMeter = 1; // dummy
info.biYPelsPerMeter = 1; // dummy
info.biClrUsed = 0;
info.biClrImportant = 0;
fwrite(&info, sizeof(BITMAPINFOHEADER), 1, file);
unsigned char *temp = buffer + info.biSizeImage;
const unsigned int row = width * numc;
for (int y = 0; temp -= row, y < info.biHeight; ++y) {
fwrite(temp, row, 1, file);
}
// delete the buffer
delete[] buffer;
return 0;
}
// -----------------------------------------------------------------------------------
// Save a texture as tga
int SaveAsTGA(FILE *file, const aiTexel *data, unsigned int width, unsigned int height) {
if (!file || !data) {
return 1;
}
TGA_HEADER head;
memset(&head, 0, sizeof(head));
head.bits = 32;
head.height = (uint16_t)height;
head.width = (uint16_t)width;
head.descriptor |= (1u << 5);
head.imagetype = 2; // actually it's RGBA
fwrite(&head, sizeof(TGA_HEADER), 1, file);
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) {
fwrite(data + y * width + x, 4, 1, file);
}
}
return 0;
}
// -----------------------------------------------------------------------------------
// Do the texture import for a given aiTexture
int DoExport(const aiTexture *tx, FILE *p, const std::string &extension, unsigned int flags) {
// export the image to the appropriate decoder
if (extension == "bmp") {
SaveAsBMP(p, tx->pcData, tx->mWidth, tx->mHeight,
(0 != (flags & AI_EXTRACT_WRITE_BMP_ALPHA)));
} else if (extension == "tga") {
SaveAsTGA(p, tx->pcData, tx->mWidth, tx->mHeight);
} else {
printf("assimp extract: No available texture encoder found for %s\n", extension.c_str());
return AssimpCmdExtractError::NoAvailableTextureEncoderFound;
}
return AssimpCmdError::Success;
}
// -----------------------------------------------------------------------------------
// Implementation of the assimp extract utility
int Assimp_Extract(const char *const *params, unsigned int num) {
const char *const invalid = "assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n";
// assimp extract in out [options]
if (num < 1) {
printf(invalid);
return AssimpCmdError::InvalidNumberOfArguments;
}
// --help
if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
printf("%s", AICMD_MSG_DUMP_HELP_E);
return AssimpCmdError::Success;
}
std::string in = std::string(params[0]);
std::string out = (num > 1 ? std::string(params[1]) : "-");
// get import flags
ImportData import;
ProcessStandardArguments(import, params + 1, num - 1);
bool nosuffix = false;
unsigned int texIdx = 0xffffffff, flags = 0;
// process other flags
std::string extension = "bmp";
for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num; ++i) {
if (!params[i]) {
continue;
}
if (!strncmp(params[i], "-f", 2)) {
extension = std::string(params[i] + 2);
} else if (!strncmp(params[i], "--format=", 9)) {
extension = std::string(params[i] + 9);
} else if (!strcmp(params[i], "--nosuffix") || !strcmp(params[i], "-s")) {
nosuffix = true;
} else if (!strncmp(params[i], "--texture=", 10)) {
texIdx = Assimp::strtoul10(params[i] + 10);
} else if (!strncmp(params[i], "-t", 2)) {
texIdx = Assimp::strtoul10(params[i] + 2);
} else if (!strcmp(params[i], "-ba") || !strcmp(params[i], "--bmp-with-alpha")) {
flags |= AI_EXTRACT_WRITE_BMP_ALPHA;
}
#if 0
else {
printf("Unknown parameter: %s\n",params[i]);
return 10;
}
#endif
}
std::transform(extension.begin(), extension.end(), extension.begin(), ai_tolower<char>);
if (out[0] == '-') {
// take file name from input file
std::string::size_type s = in.find_last_of('.');
if (s == std::string::npos)
s = in.length();
out = in.substr(0, s);
}
// take file extension from file name, if given
std::string::size_type s = out.find_last_of('.');
if (s != std::string::npos) {
extension = out.substr(s + 1, in.length() - (s + 1));
out = out.substr(0, s);
}
// import the main model
const aiScene *scene = ImportModel(import, in);
if (!scene) {
printf("assimp extract: Unable to load input file %s\n", in.c_str());
return AssimpCmdError::FailedToLoadInputFile;
}
// get the texture(s) to be exported
if (texIdx != 0xffffffff) {
// check whether the requested texture is existing
if (texIdx >= scene->mNumTextures) {
::printf("assimp extract: Texture %u requested, but there are just %i textures\n",
texIdx, scene->mNumTextures);
return AssimpCmdExtractError::TextureIndexIsOutOfRange;
}
} else {
::printf("assimp extract: Exporting %i textures\n", scene->mNumTextures);
}
// now write all output textures
for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
if (texIdx != 0xffffffff && texIdx != i) {
continue;
}
const aiTexture *tex = scene->mTextures[i];
std::string out_cpy = out, out_ext = extension;
// append suffix if necessary - always if all textures are exported
if (!nosuffix || (texIdx == 0xffffffff)) {
out_cpy.append("_img");
char tmp[10];
Assimp::ASSIMP_itoa10(tmp, i);
out_cpy.append(std::string(tmp));
}
// if the texture is a compressed one, we'll export
// it to its native file format
if (!tex->mHeight) {
printf("assimp extract: Texture %u is compressed (%s). Writing native file format.\n",
i, tex->achFormatHint);
// modify file extension
out_ext = std::string(tex->achFormatHint);
}
out_cpy.append("." + out_ext);
// open output file
FILE *p = ::fopen(out_cpy.c_str(), "wb");
if (!p) {
printf("assimp extract: Unable to open output file %s\n", out_cpy.c_str());
return AssimpCmdError::FailedToOpenOutputFile;
}
int m;
if (!tex->mHeight) {
m = (1 != fwrite(tex->pcData, tex->mWidth, 1, p)) ?
static_cast<int>(AssimpCmdError::Success) :
static_cast<int>(AssimpCmdExtractError::FailedToExportCompressedTexture);
} else {
m = DoExport(tex, p, extension, flags);
}
::fclose(p);
printf("assimp extract: Wrote texture %u to %s\n", i, out_cpy.c_str());
if (texIdx != 0xffffffff) {
return m;
}
}
return AssimpCmdError::Success;
}

511
vendor/assimp/tools/assimp_cmd/Info.cpp vendored Normal file
View file

@ -0,0 +1,511 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Info.cpp
* @brief Implementation of the 'assimp info' utility */
#include "Main.h"
#include <cstdio>
#include <iostream>
#include <string>
constexpr char AICMD_MSG_INFO_HELP_E[] =
"assimp info <file> [-r] [-v]\n"
"\tPrint basic structure of a 3D model\n"
"\t-r,--raw: No postprocessing, do a raw import\n"
"\t-v,--verbose: Print verbose info such as node transform data\n"
"\t-s, --silent: Print only minimal info\n";
// note: by default this is using utf-8 text.
// this is well supported on pretty much any linux terminal.
// if this causes problems on some platform,
// put an #ifdef to use the ascii version for that platform.
#ifdef _WIN32
constexpr char TREE_BRANCH_ASCII[] = "|-";
constexpr char TREE_STOP_ASCII[] = "'-";
constexpr char TREE_CONTINUE_ASCII[] = "| ";
const char *TREE_BRANCH = TREE_BRANCH_ASCII;
const char *TREE_STOP = TREE_STOP_ASCII;
const char *TREE_CONTINUE = TREE_CONTINUE_ASCII;
#else // _WIN32
constexpr char TREE_BRANCH_UTF8[] = "\xe2\x94\x9c\xe2\x95\xb4";
constexpr char TREE_STOP_UTF8[] = "\xe2\x94\x94\xe2\x95\xb4";
constexpr char TREE_CONTINUE_UTF8[] = "\xe2\x94\x82 ";
const char *TREE_BRANCH = TREE_BRANCH_UTF8;
const char *TREE_STOP = TREE_STOP_UTF8;
const char *TREE_CONTINUE = TREE_CONTINUE_UTF8;
#endif // _WIN32
// -----------------------------------------------------------------------------------
unsigned int CountNodes(const aiNode *root) {
unsigned int i = 0;
for (unsigned int a = 0; a < root->mNumChildren; ++a) {
i += CountNodes(root->mChildren[a]);
}
return 1 + i;
}
// -----------------------------------------------------------------------------------
unsigned int GetMaxDepth(const aiNode *root) {
unsigned int cnt = 0;
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
cnt = std::max(cnt, GetMaxDepth(root->mChildren[i]));
}
return cnt + 1;
}
// -----------------------------------------------------------------------------------
unsigned int CountVertices(const aiScene *scene) {
unsigned int cnt = 0;
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumVertices;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountFaces(const aiScene *scene) {
unsigned int cnt = 0;
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumFaces;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountBones(const aiScene *scene) {
unsigned int cnt = 0;
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumBones;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountAnimChannels(const aiScene *scene) {
unsigned int cnt = 0;
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
cnt += scene->mAnimations[i]->mNumChannels;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int GetAvgFacePerMesh(const aiScene *scene) {
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene) / scene->mNumMeshes) : 0;
}
// -----------------------------------------------------------------------------------
unsigned int GetAvgVertsPerMesh(const aiScene *scene) {
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene) / scene->mNumMeshes) : 0;
}
// -----------------------------------------------------------------------------------
void FindSpecialPoints(const aiScene *scene, const aiNode *root, aiVector3D special_points[3], const aiMatrix4x4 &mat = aiMatrix4x4()) {
// XXX that could be greatly simplified by using code from code/ProcessHelper.h
// XXX I just don't want to include it here.
const aiMatrix4x4 trafo = root->mTransformation * mat;
for (unsigned int i = 0; i < root->mNumMeshes; ++i) {
const aiMesh *mesh = scene->mMeshes[root->mMeshes[i]];
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
aiVector3D v = trafo * mesh->mVertices[a];
special_points[0].x = std::min(special_points[0].x, v.x);
special_points[0].y = std::min(special_points[0].y, v.y);
special_points[0].z = std::min(special_points[0].z, v.z);
special_points[1].x = std::max(special_points[1].x, v.x);
special_points[1].y = std::max(special_points[1].y, v.y);
special_points[1].z = std::max(special_points[1].z, v.z);
}
}
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
FindSpecialPoints(scene, root->mChildren[i], special_points, trafo);
}
}
// -----------------------------------------------------------------------------------
void FindSpecialPoints(const aiScene *scene, aiVector3D special_points[3]) {
special_points[0] = aiVector3D(1e10, 1e10, 1e10);
special_points[1] = aiVector3D(-1e10, -1e10, -1e10);
FindSpecialPoints(scene, scene->mRootNode, special_points);
special_points[2] = (special_points[0] + special_points[1]) * (ai_real)0.5;
}
// -----------------------------------------------------------------------------------
std::string FindPTypes(const aiScene *scene) {
bool haveit[4] = { false };
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes;
if (pt & aiPrimitiveType_POINT) {
haveit[0] = true;
}
if (pt & aiPrimitiveType_LINE) {
haveit[1] = true;
}
if (pt & aiPrimitiveType_TRIANGLE) {
haveit[2] = true;
}
if (pt & aiPrimitiveType_POLYGON) {
haveit[3] = true;
}
}
return (haveit[0] ? std::string("points") : "") + (haveit[1] ? "lines" : "") +
(haveit[2] ? "triangles" : "") + (haveit[3] ? "n-polygons" : "");
}
// -----------------------------------------------------------------------------------
// Prettily print the node graph to stdout
void PrintHierarchy(
const aiNode *node,
const std::string &indent,
bool verbose,
bool last = false,
bool first = true) {
// tree visualization
std::string branchchar;
if (first) {
branchchar = "";
} else if (last) {
branchchar = TREE_STOP;
} // "'-"
else {
branchchar = TREE_BRANCH;
} // "|-"
// print the indent and the branch character and the name
std::cout << indent << branchchar << node->mName.C_Str();
// if there are meshes attached, indicate this
if (node->mNumMeshes) {
std::cout << " (mesh ";
bool sep = false;
for (size_t i = 0; i < node->mNumMeshes; ++i) {
unsigned int mesh_index = node->mMeshes[i];
if (sep) {
std::cout << ", ";
}
std::cout << mesh_index;
sep = true;
}
std::cout << ")";
}
// finish the line
std::cout << std::endl;
// in verbose mode, print the transform data as well
if (verbose) {
// indent to use
std::string indentadd;
if (last) {
indentadd += " ";
} else {
indentadd += TREE_CONTINUE;
} // "| "..
if (node->mNumChildren == 0) {
indentadd += " ";
} else {
indentadd += TREE_CONTINUE;
} // .."| "
aiVector3D s, r, t;
node->mTransformation.Decompose(s, r, t);
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
std::cout << indent << indentadd;
printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
}
if (r.x || r.y || r.z) {
std::cout << indent << indentadd;
printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
}
if (t.x || t.y || t.z) {
std::cout << indent << indentadd;
printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
}
}
// and recurse
std::string nextIndent;
if (first) {
nextIndent = indent;
} else if (last) {
nextIndent = indent + " ";
} else {
nextIndent = indent + TREE_CONTINUE;
} // "| "
for (size_t i = 0; i < node->mNumChildren; ++i) {
bool lastone = (i == node->mNumChildren - 1);
PrintHierarchy(
node->mChildren[i],
nextIndent,
verbose,
lastone,
false);
}
}
// -----------------------------------------------------------------------------------
// Implementation of the assimp info utility to print basic file info
int Assimp_Info(const char *const *params, unsigned int num) {
// asssimp info <file> [-r]
if (num < 1) {
printf("assimp info: Invalid number of arguments. "
"See \'assimp info --help\'\n");
return AssimpCmdError::InvalidNumberOfArguments;
}
// --help
if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
printf("%s", AICMD_MSG_INFO_HELP_E);
return AssimpCmdError::Success;
}
const std::string in = std::string(params[0]);
// get -r and -v arguments
bool raw = false;
bool verbose = false;
bool silent = false;
for (unsigned int i = 1; i < num; ++i) {
if (!strcmp(params[i], "--raw") || !strcmp(params[i], "-r")) {
raw = true;
}
if (!strcmp(params[i], "--verbose") || !strcmp(params[i], "-v")) {
verbose = true;
}
if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) {
silent = true;
}
}
// Verbose and silent at the same time are not allowed
if (verbose && silent) {
printf("assimp info: Invalid arguments, verbose and silent at the same time are forbidden. ");
return AssimpCmdInfoError::InvalidCombinaisonOfArguments;
}
// Parse post-processing flags unless -r was specified
ImportData import;
if (!raw) {
// get import flags
ProcessStandardArguments(import, params + 1, num - 1);
//No custom post process flags defined, we set all the post process flags active
if (import.ppFlags == 0)
import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
}
// import the main model
const aiScene *scene = ImportModel(import, in);
if (!scene) {
printf("assimp info: Unable to load input file %s\n",
in.c_str());
return AssimpCmdError::FailedToLoadInputFile;
}
aiMemoryInfo mem;
globalImporter->GetMemoryRequirements(mem);
static const char *format_string =
"Memory consumption: %i B\n"
"Nodes: %i\n"
"Maximum depth %i\n"
"Meshes: %i\n"
"Animations: %i\n"
"Textures (embed.): %i\n"
"Materials: %i\n"
"Cameras: %i\n"
"Lights: %i\n"
"Vertices: %i\n"
"Faces: %i\n"
"Bones: %i\n"
"Animation Channels: %i\n"
"Primitive Types: %s\n"
"Average faces/mesh %i\n"
"Average verts/mesh %i\n"
"Minimum point (%f %f %f)\n"
"Maximum point (%f %f %f)\n"
"Center point (%f %f %f)\n"
;
aiVector3D special_points[3];
FindSpecialPoints(scene, special_points);
printf(format_string,
mem.total,
CountNodes(scene->mRootNode),
GetMaxDepth(scene->mRootNode),
scene->mNumMeshes,
scene->mNumAnimations,
scene->mNumTextures,
scene->mNumMaterials,
scene->mNumCameras,
scene->mNumLights,
CountVertices(scene),
CountFaces(scene),
CountBones(scene),
CountAnimChannels(scene),
FindPTypes(scene).c_str(),
GetAvgFacePerMesh(scene),
GetAvgVertsPerMesh(scene),
special_points[0][0], special_points[0][1], special_points[0][2],
special_points[1][0], special_points[1][1], special_points[1][2],
special_points[2][0], special_points[2][1], special_points[2][2]);
if (silent) {
printf("\n");
return AssimpCmdError::Success;
}
// meshes
if (scene->mNumMeshes) {
printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n");
}
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
const aiMesh *mesh = scene->mMeshes[i];
printf(" %d (%s)", i, mesh->mName.C_Str());
printf(
": [%d / %d / %d |",
mesh->mNumVertices,
mesh->mNumBones,
mesh->mNumFaces);
const unsigned int ptypes = mesh->mPrimitiveTypes;
if (ptypes & aiPrimitiveType_POINT) {
printf(" point");
}
if (ptypes & aiPrimitiveType_LINE) {
printf(" line");
}
if (ptypes & aiPrimitiveType_TRIANGLE) {
printf(" triangle");
}
if (ptypes & aiPrimitiveType_POLYGON) {
printf(" polygon");
}
printf("]\n");
}
// materials
if (scene->mNumMaterials)
printf("\nNamed Materials:");
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
const aiMaterial *mat = scene->mMaterials[i];
aiString name = mat->GetName();
printf("\n \'%s\'", name.data);
if (mat->mNumProperties)
printf(" (prop) [index / bytes | texture semantic]");
for (unsigned p = 0; p < mat->mNumProperties; p++) {
const aiMaterialProperty *prop = mat->mProperties[p];
const aiTextureType textype = static_cast<aiTextureType>(prop->mSemantic);
printf("\n %d (%s): [%d / %d | %s]",
p,
prop->mKey.data,
prop->mIndex,
prop->mDataLength,
aiTextureTypeToString(textype));
}
}
if (scene->mNumMaterials) {
printf("\n");
}
// textures
unsigned int total = 0;
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
aiString name;
static const aiTextureType types[] = {
aiTextureType_NONE,
aiTextureType_DIFFUSE,
aiTextureType_SPECULAR,
aiTextureType_AMBIENT,
aiTextureType_EMISSIVE,
aiTextureType_HEIGHT,
aiTextureType_NORMALS,
aiTextureType_SHININESS,
aiTextureType_OPACITY,
aiTextureType_DISPLACEMENT,
aiTextureType_LIGHTMAP,
aiTextureType_REFLECTION,
aiTextureType_BASE_COLOR,
aiTextureType_NORMAL_CAMERA,
aiTextureType_EMISSION_COLOR,
aiTextureType_METALNESS,
aiTextureType_DIFFUSE_ROUGHNESS,
aiTextureType_AMBIENT_OCCLUSION,
aiTextureType_UNKNOWN
};
for (unsigned int type = 0; type < sizeof(types) / sizeof(types[0]); ++type) {
for (unsigned int idx = 0; AI_SUCCESS == aiGetMaterialString(scene->mMaterials[i],
AI_MATKEY_TEXTURE(types[type], idx), &name);
++idx) {
printf("%s\n \'%s\'", (total++ ? "" : "\nTexture Refs:"), name.data);
}
}
}
if (total) {
printf("\n");
}
// animations
total = 0;
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
if (scene->mAnimations[i]->mName.length) {
printf("%s\n \'%s\'", (total++ ? "" : "\nNamed Animations:"), scene->mAnimations[i]->mName.data);
}
}
if (total) {
printf("\n");
}
// node hierarchy
printf("\nNode hierarchy:\n");
PrintHierarchy(scene->mRootNode, "", verbose);
printf("\n");
return AssimpCmdError::Success;
}

559
vendor/assimp/tools/assimp_cmd/Main.cpp vendored Normal file
View file

@ -0,0 +1,559 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Main.cpp
* @brief main() function of assimp_cmd
*/
#include "Main.h"
#include <assimp/ProgressHandler.hpp>
#include <iostream>
class ConsoleProgressHandler : public ProgressHandler {
public:
ConsoleProgressHandler() :
ProgressHandler() {
// empty
}
~ConsoleProgressHandler() override = default;
bool Update(float percentage) override {
std::cout << "\r" << percentage * 100.0f << " %";
return true;
}
};
constexpr char AICMD_MSG_ABOUT[] =
"------------------------------------------------------ \n"
"Open Asset Import Library (\"Assimp\", https://github.com/assimp/assimp) \n"
" -- Commandline toolchain --\n"
"------------------------------------------------------ \n\n"
"Version %i.%i %s%s%s%s%s(GIT commit %x)\n\n";
constexpr char AICMD_MSG_HELP[] =
"assimp <verb> <parameters>\n\n"
" verbs:\n"
" \tinfo - Quick file stats\n"
" \tlistext - List all known file extensions available for import\n"
" \tknowext - Check whether a file extension is recognized by Assimp\n"
#ifndef ASSIMP_BUILD_NO_EXPORT
" \texport - Export a file to one of the supported output formats\n"
" \tlistexport - List all supported export formats\n"
" \texportinfo - Show basic information on a specific export format\n"
#endif
" \textract - Extract embedded texture images\n"
" \tdump - Convert models to a binary or textual dump (ASSBIN/ASSXML)\n"
" \tcmpdump - Compare dumps created using \'assimp dump <file> -s ...\'\n"
" \tversion - Display Assimp version\n"
"\n Use \'assimp <verb> --help\' for detailed help on a command.\n"
;
/*extern*/ Assimp::Importer* globalImporter = nullptr;
#ifndef ASSIMP_BUILD_NO_EXPORT
/*extern*/ Assimp::Exporter* globalExporter = nullptr;
#endif
// ------------------------------------------------------------------------------
// Application entry point
int main (int argc, char* argv[]) {
if (argc <= 1) {
printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n");
return AssimpCmdError::Success;
}
// assimp version
// Display version information
if (! strcmp(argv[1], "version")) {
const unsigned int flags = aiGetCompileFlags();
printf(AICMD_MSG_ABOUT,
aiGetVersionMajor(),
aiGetVersionMinor(),
(flags & ASSIMP_CFLAGS_DEBUG ? "-debug " : ""),
(flags & ASSIMP_CFLAGS_NOBOOST ? "-noboost " : ""),
(flags & ASSIMP_CFLAGS_SHARED ? "-shared " : ""),
(flags & ASSIMP_CFLAGS_SINGLETHREADED ? "-st " : ""),
(flags & ASSIMP_CFLAGS_STLPORT ? "-stlport " : ""),
aiGetVersionRevision());
return AssimpCmdError::Success;
}
// assimp help
// Display some basic help (--help and -h work as well
// because people could try them intuitively)
if (!strcmp(argv[1], "help") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
printf("%s",AICMD_MSG_HELP);
return AssimpCmdError::Success;
}
// assimp cmpdump
// Compare two mini model dumps (regression suite)
if (! strcmp(argv[1], "cmpdump")) {
return Assimp_CompareDump (&argv[2],argc-2);
}
// construct global importer and exporter instances
Assimp::Importer imp;
imp.SetPropertyBool("GLOB_MEASURE_TIME",true);
globalImporter = &imp;
#ifndef ASSIMP_BUILD_NO_EXPORT
//
Assimp::Exporter exp;
globalExporter = &exp;
#endif
// assimp listext
// List all file extensions supported by Assimp
if (! strcmp(argv[1], "listext")) {
aiString s;
imp.GetExtensionList(s);
printf("%s\n",s.data);
return AssimpCmdError::Success;
}
#ifndef ASSIMP_BUILD_NO_EXPORT
// assimp listexport
// List all export file formats supported by Assimp (not the file extensions, just the format identifiers!)
if (! strcmp(argv[1], "listexport")) {
aiString s;
for(size_t i = 0, end = exp.GetExportFormatCount(); i < end; ++i) {
const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i);
s.Append( e->id );
if (i!=end-1) {
s.Append("\n");
}
}
printf("%s\n",s.data);
return AssimpCmdError::Success;
}
// assimp exportinfo
// stat an export format
if (! strcmp(argv[1], "exportinfo")) {
aiString s;
if (argc<3) {
printf("Expected file format id\n");
return AssimpCmdError::NoFileFormatSpecified;
}
for(size_t i = 0, end = exp.GetExportFormatCount(); i < end; ++i) {
const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i);
if (!strcmp(e->id,argv[2])) {
printf("%s\n%s\n%s\n",e->id,e->fileExtension,e->description);
return AssimpCmdError::Success;
}
}
printf("Unknown file format id: \'%s\'\n",argv[2]);
return AssimpCmdError::UnknownFileFormat;
}
// assimp export
// Export a model to a file
if (! strcmp(argv[1], "export")) {
return Assimp_Export (&argv[2],argc-2);
}
#endif
// assimp knowext
// Check whether a particular file extension is known by us, return 0 on success
if (! strcmp(argv[1], "knowext")) {
if (argc<3) {
printf("Expected file extension");
return AssimpCmdError::NoFileExtensionSpecified;
}
const bool b = imp.IsExtensionSupported(argv[2]);
printf("File extension \'%s\' is %sknown\n",argv[2],(b?"":"not "));
return b? AssimpCmdError::Success : AssimpCmdError::UnknownFileExtension;
}
// assimp info
// Print basic model statistics
if (! strcmp(argv[1], "info")) {
return Assimp_Info ((const char**)&argv[2],argc-2);
}
// assimp dump
// Dump a model to a file
if (! strcmp(argv[1], "dump")) {
return Assimp_Dump (&argv[2],argc-2);
}
// assimp extract
// Extract an embedded texture from a file
if (! strcmp(argv[1], "extract")) {
return Assimp_Extract (&argv[2],argc-2);
}
// assimp testbatchload
// Used by /test/other/streamload.py to load a list of files
// using the same importer instance to check for incompatible
// importers.
if (! strcmp(argv[1], "testbatchload")) {
return Assimp_TestBatchLoad (&argv[2],argc-2);
}
printf("Unrecognized command. Use \'assimp help\' for a detailed command list\n");
return AssimpCmdError::UnrecognizedCommand;
}
// ------------------------------------------------------------------------------
void SetLogStreams(const ImportData& imp)
{
printf("\nAttaching log stream ... OK\n");
unsigned int flags = 0;
if (imp.logFile.length()) {
flags |= aiDefaultLogStream_FILE;
}
if (imp.showLog) {
flags |= aiDefaultLogStream_STDERR;
}
DefaultLogger::create(imp.logFile.c_str(),imp.verbose ? Logger::VERBOSE : Logger::NORMAL,flags);
}
// ------------------------------------------------------------------------------
void FreeLogStreams()
{
DefaultLogger::kill();
}
// ------------------------------------------------------------------------------
void PrintHorBar()
{
printf("-----------------------------------------------------------------\n");
}
// ------------------------------------------------------------------------------
// Import a specific file
const aiScene* ImportModel(
const ImportData& imp,
const std::string& path)
{
// Attach log streams
if (imp.log) {
SetLogStreams(imp);
}
printf("Launching asset import ... OK\n");
// Now validate this flag combination
if(!globalImporter->ValidateFlags(imp.ppFlags)) {
printf("ERROR: Unsupported post-processing flags \n");
return nullptr;
}
printf("Validating postprocessing flags ... OK\n");
if (imp.showLog) {
PrintHorBar();
}
// do the actual import, measure time
const clock_t first = clock();
ConsoleProgressHandler *ph = new ConsoleProgressHandler;
globalImporter->SetProgressHandler(ph);
const aiScene* scene = globalImporter->ReadFile(path,imp.ppFlags);
if (imp.showLog) {
PrintHorBar();
}
if (!scene) {
printf("ERROR: Failed to load file: %s\n", globalImporter->GetErrorString());
return nullptr;
}
const clock_t second = ::clock();
const double seconds = static_cast<double>(second-first) / CLOCKS_PER_SEC;
printf("Importing file ... OK \n import took approx. %.5f seconds\n"
"\n",seconds);
if (imp.log) {
FreeLogStreams();
}
globalImporter->SetProgressHandler(nullptr);
delete ph;
return scene;
}
#ifndef ASSIMP_BUILD_NO_EXPORT
// ------------------------------------------------------------------------------
bool ExportModel(const aiScene* pOut,
const ImportData& imp,
const std::string& path,
const char* pID)
{
// Attach log streams
if (imp.log) {
SetLogStreams(imp);
}
printf("Launching asset export ... OK\n");
if (imp.showLog) {
PrintHorBar();
}
aiMatrix4x4 rx, ry, rz;
aiMatrix4x4::RotationX(imp.rot.x, rx);
aiMatrix4x4::RotationY(imp.rot.y, ry);
aiMatrix4x4::RotationZ(imp.rot.z, rz);
pOut->mRootNode->mTransformation *= rx;
pOut->mRootNode->mTransformation *= ry;
pOut->mRootNode->mTransformation *= rz;
// do the actual export, measure time
const clock_t first = clock();
const aiReturn res = globalExporter->Export(pOut,pID,path);
if (imp.showLog) {
PrintHorBar();
}
if (res != AI_SUCCESS) {
printf("Failed to write file\n");
printf("ERROR: %s\n", globalExporter->GetErrorString());
return false;
}
const clock_t second = ::clock();
const double seconds = static_cast<double>(second-first) / CLOCKS_PER_SEC;
printf("Exporting file ... OK \n export took approx. %.5f seconds\n"
"\n",seconds);
if (imp.log) {
FreeLogStreams();
}
return true;
}
#endif
// ------------------------------------------------------------------------------
// Process standard arguments
int ProcessStandardArguments(
ImportData& fill,
const char* const * params,
unsigned int num)
{
// -ptv --pretransform-vertices
// -gsn --gen-smooth-normals
// -gn --gen-normals
// -cts --calc-tangent-space
// -jiv --join-identical-vertices
// -rrm --remove-redundant-materials
// -fd --find-degenerates
// -slm --split-large-meshes
// -lbw --limit-bone-weights
// -vds --validate-data-structure
// -icl --improve-cache-locality
// -sbpt --sort-by-ptype
// -lh --convert-to-lh
// -fuv --flip-uv
// -fwo --flip-winding-order
// -tuv --transform-uv-coords
// -guv --gen-uvcoords
// -fid --find-invalid-data
// -fixn --fix normals
// -tri --triangulate
// -fi --find-instances
// -og --optimize-graph
// -om --optimize-meshes
// -db --debone
// -sbc --split-by-bone-count
// -gs --global-scale
//
// -c<file> --config-file=<file>
for (unsigned int i = 0; i < num;++i)
{
const char *param = params[ i ];
printf( "param = %s\n", param );
if (! strcmp( param, "-ptv") || ! strcmp( param, "--pretransform-vertices")) {
fill.ppFlags |= aiProcess_PreTransformVertices;
}
else if (! strcmp( param, "-gsn") || ! strcmp( param, "--gen-smooth-normals")) {
fill.ppFlags |= aiProcess_GenSmoothNormals;
}
else if (! strcmp( param, "-dn") || ! strcmp( param, "--drop-normals")) {
fill.ppFlags |= aiProcess_DropNormals;
}
else if (! strcmp( param, "-gn") || ! strcmp( param, "--gen-normals")) {
fill.ppFlags |= aiProcess_GenNormals;
}
else if (! strcmp( param, "-jiv") || ! strcmp( param, "--join-identical-vertices")) {
fill.ppFlags |= aiProcess_JoinIdenticalVertices;
}
else if (! strcmp( param, "-rrm") || ! strcmp( param, "--remove-redundant-materials")) {
fill.ppFlags |= aiProcess_RemoveRedundantMaterials;
}
else if (! strcmp( param, "-fd") || ! strcmp( param, "--find-degenerates")) {
fill.ppFlags |= aiProcess_FindDegenerates;
}
else if (! strcmp( param, "-slm") || ! strcmp( param, "--split-large-meshes")) {
fill.ppFlags |= aiProcess_SplitLargeMeshes;
}
else if (! strcmp( param, "-lbw") || ! strcmp( param, "--limit-bone-weights")) {
fill.ppFlags |= aiProcess_LimitBoneWeights;
}
else if (! strcmp( param, "-vds") || ! strcmp( param, "--validate-data-structure")) {
fill.ppFlags |= aiProcess_ValidateDataStructure;
}
else if (! strcmp( param, "-icl") || ! strcmp( param, "--improve-cache-locality")) {
fill.ppFlags |= aiProcess_ImproveCacheLocality;
}
else if (! strcmp( param, "-sbpt") || ! strcmp( param, "--sort-by-ptype")) {
fill.ppFlags |= aiProcess_SortByPType;
}
else if (! strcmp( param, "-lh") || ! strcmp( param, "--left-handed")) {
fill.ppFlags |= aiProcess_ConvertToLeftHanded;
}
else if (! strcmp( param, "-fuv") || ! strcmp( param, "--flip-uv")) {
fill.ppFlags |= aiProcess_FlipUVs;
}
else if (! strcmp( param, "-fwo") || ! strcmp( param, "--flip-winding-order")) {
fill.ppFlags |= aiProcess_FlipWindingOrder;
}
else if (! strcmp( param, "-tuv") || ! strcmp( param, "--transform-uv-coords")) {
fill.ppFlags |= aiProcess_TransformUVCoords;
}
else if (! strcmp( param, "-guv") || ! strcmp( param, "--gen-uvcoords")) {
fill.ppFlags |= aiProcess_GenUVCoords;
}
else if (! strcmp( param, "-fid") || ! strcmp( param, "--find-invalid-data")) {
fill.ppFlags |= aiProcess_FindInvalidData;
}
else if (! strcmp( param, "-fixn") || ! strcmp( param, "--fix-normals")) {
fill.ppFlags |= aiProcess_FixInfacingNormals;
}
else if (! strcmp( param, "-tri") || ! strcmp( param, "--triangulate")) {
fill.ppFlags |= aiProcess_Triangulate;
}
else if (! strcmp( param, "-cts") || ! strcmp( param, "--calc-tangent-space")) {
fill.ppFlags |= aiProcess_CalcTangentSpace;
}
else if (! strcmp( param, "-fi") || ! strcmp( param, "--find-instances")) {
fill.ppFlags |= aiProcess_FindInstances;
}
else if (! strcmp( param, "-og") || ! strcmp( param, "--optimize-graph")) {
fill.ppFlags |= aiProcess_OptimizeGraph;
}
else if (! strcmp( param, "-om") || ! strcmp( param, "--optimize-meshes")) {
fill.ppFlags |= aiProcess_OptimizeMeshes;
}
else if (! strcmp( param, "-db") || ! strcmp( param, "--debone")) {
fill.ppFlags |= aiProcess_Debone;
}
else if (! strcmp( param, "-sbc") || ! strcmp( param, "--split-by-bone-count")) {
fill.ppFlags |= aiProcess_SplitByBoneCount;
}
else if (!strcmp(param, "-embtex") || ! strcmp(param, "--embed-textures")) {
fill.ppFlags |= aiProcess_EmbedTextures;
}
else if (!strcmp(param, "-gs") || ! strcmp(param, "--global-scale")) {
fill.ppFlags |= aiProcess_GlobalScale;
}
else if (! strncmp( param, "-c",2) || ! strncmp( param, "--config=",9)) {
const unsigned int ofs = (params[i][1] == '-' ? 9 : 2);
// use default configurations
if (!strncmp( param + ofs, "full", 4 )) {
fill.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
} else if (!strncmp( param + ofs, "default", 7 )) {
fill.ppFlags |= aiProcessPreset_TargetRealtime_Quality;
} else if (! strncmp( param +ofs,"fast",4)) {
fill.ppFlags |= aiProcessPreset_TargetRealtime_Fast;
}
} else if (! strcmp( param, "-l") || ! strcmp( param, "--show-log")) {
fill.showLog = true;
}
else if (! strcmp( param, "-v") || ! strcmp( param, "--verbose")) {
fill.verbose = true;
}
else if (!strncmp(params[i], "-rx=", 4) || !strncmp(params[i], "--rotation-x=", 13)) {
std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4));
fill.rot.x = std::stof(value);
}
else if (!strncmp(params[i], "-ry=", 4) || !strncmp(params[i], "--rotation-y=", 13)) {
std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4));
fill.rot.y = std::stof(value);
}
else if (!strncmp(params[i], "-rz=", 4) || !strncmp(params[i], "--rotation-z=", 13)) {
std::string value = std::string(params[i] + (params[i][1] == '-' ? 13 : 4));
fill.rot.z = std::stof(value);
}
else if (! strncmp( param, "--log-out=",10) || ! strncmp( param, "-lo",3)) {
fill.logFile = std::string(params[i]+(params[i][1] == '-' ? 10 : 3));
if (!fill.logFile.length()) {
fill.logFile = "assimp-log.txt";
}
}
}
if (fill.logFile.length() || fill.showLog || fill.verbose) {
fill.log = true;
}
return AssimpCmdError::Success;
}
// ------------------------------------------------------------------------------
int Assimp_TestBatchLoad(const char* const* params, unsigned int num) {
for(unsigned int i = 0; i < num; ++i) {
globalImporter->ReadFile(params[i],aiProcessPreset_TargetRealtime_MaxQuality);
// we're totally silent. scene destructs automatically.
}
return AssimpCmdError::Success;
}

264
vendor/assimp/tools/assimp_cmd/Main.h vendored Normal file
View file

@ -0,0 +1,264 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Main.h
* @brief Utility declarations for assimp_cmd
*/
#ifndef AICMD_MAIN_INCLUDED
#define AICMD_MAIN_INCLUDED
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <limits>
#include <assimp/postprocess.h>
#include <assimp/version.h>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/DefaultLogger.hpp>
#include "../code/Common/Compression.h"
#ifndef ASSIMP_BUILD_NO_EXPORT
# include <assimp/Exporter.hpp>
#endif
#ifndef SIZE_MAX
# define SIZE_MAX (std::numeric_limits<size_t>::max())
#endif
using namespace Assimp;
// Global assimp importer instance
extern Assimp::Importer* globalImporter;
#ifndef ASSIMP_BUILD_NO_EXPORT
// Global assimp exporter instance
extern Assimp::Exporter* globalExporter;
#endif
// ------------------------------------------------------------------------------
/// Defines common import parameters
struct ImportData {
ImportData()
: ppFlags (0)
, showLog (false)
, verbose (false)
, log (false)
, rot (aiVector3D(0.f, 0.f, 0.f))
{}
/// Post-processing flags
unsigned int ppFlags;
// Log to std::err?
bool showLog;
// Log file
std::string logFile;
// Verbose log mode?
bool verbose;
// Need to log?
bool log;
// Export With Rotation
aiVector3D rot;
};
// ------------------------------------------------------------------------------
/// @brief General error codes used among assimp_cmd's utilities.
enum AssimpCmdError {
Success = 0,
InvalidNumberOfArguments,
UnrecognizedCommand,
FailedToLoadInputFile,
FailedToOpenOutputFile,
NoFileFormatSpecified,
UnknownFileFormat,
NoFileExtensionSpecified,
UnknownFileExtension,
ExceptionWasRaised,
// Add new error codes here...
LastAssimpCmdError, // Must be last.
};
// ------------------------------------------------------------------------------
/** Process standard arguments
*
* @param fill Filled by function
* @param params Command line parameters to be processed
* @param num NUmber of params
* @return An #AssimpCmdError value. */
int ProcessStandardArguments(ImportData& fill,
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** Import a specific model file
* @param imp Import configuration to be used
* @param path Path to the file to be read */
const aiScene* ImportModel(
const ImportData& imp,
const std::string& path);
#ifndef ASSIMP_BUILD_NO_EXPORT
// ------------------------------------------------------------------------------
/** Export a specific model file
* @param imp Import configuration to be used
* @param path Path to the file to be written
* @param format Format id*/
bool ExportModel(const aiScene* pOut,
const ImportData& imp,
const std::string& path,
const char* pID);
#endif
// ------------------------------------------------------------------------------
/** assimp_dump utility
* @param params Command line parameters to 'assimp dump'
* @param Number of params
* @return An #AssimpCmdError value.*/
int Assimp_Dump (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/// @brief Error codes used by the 'Export' utility.
enum AssimpCmdExportError {
FailedToImportModel = AssimpCmdError::LastAssimpCmdError,
FailedToExportModel,
// Add new error codes here...
LastAssimpCmdExportError, // Must be last.
};
// ------------------------------------------------------------------------------
/** assimp_export utility
* @param params Command line parameters to 'assimp export'
* @param Number of params
* @return Either an #AssimpCmdError or #AssimpCmdExportError value. */
int Assimp_Export (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/// @brief Error codes used by the 'Image Extractor' utility.
enum AssimpCmdExtractError {
TextureIndexIsOutOfRange = AssimpCmdError::LastAssimpCmdError,
NoAvailableTextureEncoderFound,
FailedToExportCompressedTexture,
// Add new error codes here...
LastAssimpCmdExtractError, // Must be last.
};
// ------------------------------------------------------------------------------
/** assimp_extract utility
* @param params Command line parameters to 'assimp extract'
* @param Number of params
* @return Either an #AssimpCmdError or #AssimpCmdExtractError value. */
int Assimp_Extract (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/// @brief Error codes used by the 'Compare Dump' utility.
enum AssimpCmdCompareDumpError {
FailedToLoadExpectedInputFile = AssimpCmdError::LastAssimpCmdError,
FileComparaisonFailure,
UnknownFailure,
// Add new error codes here...
LastAssimpCmdCompareDumpError, // Must be last.
};
// ------------------------------------------------------------------------------
/** assimp_cmpdump utility
* @param params Command line parameters to 'assimp cmpdump'
* @param Number of params
* @return Either an #AssimpCmdError or #AssimpCmdCompareDumpError. */
int Assimp_CompareDump (
const char* const* params,
unsigned int num);
/// @brief Error codes used by the 'Info' utility.
enum AssimpCmdInfoError {
InvalidCombinaisonOfArguments = AssimpCmdError::LastAssimpCmdError,
// Add new error codes here...
LastAssimpCmdInfoError, // Must be last.
};
// ------------------------------------------------------------------------------
/** @brief assimp info utility
* @param params Command line parameters to 'assimp info'
* @param Number of params
* @return Either an #AssimpCmdError or #AssimpCmdInfoError value. */
int Assimp_Info (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** @brief assimp testbatchload utility
* @param params Command line parameters to 'assimp testbatchload'
* @param Number of params
* @return An #AssimpCmdError value. */
int Assimp_TestBatchLoad (
const char* const* params,
unsigned int num);
#endif // !! AICMD_MAIN_INCLUDED

View file

@ -0,0 +1,172 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file WriteDump.cpp
* @brief Implementation of the 'assimp dump' utility
*/
#include "Main.h"
#include "PostProcessing/ProcessHelper.h"
const char *AICMD_MSG_DUMP_HELP =
"assimp dump <model> [<out>] [-b] [-s] [-z] [common parameters]\n"
"\t -b Binary output \n"
"\t -s Shortened \n"
"\t -z Compressed \n"
"\t[See the assimp_cmd docs for a full list of all common parameters] \n"
"\t -cfast Fast post processing preset, runs just a few important steps \n"
"\t -cdefault Default post processing: runs all recommended steps\n"
"\t -cfull Fires almost all post processing steps \n";
#include "Common/assbin_chunks.h"
#include <assimp/DefaultIOSystem.h>
#include "AssetLib/Assbin/AssbinFileWriter.h"
#include "AssetLib/Assxml/AssxmlFileWriter.h"
#include <memory>
FILE *out = nullptr;
bool shortened = false;
#ifndef ASSIMP_BUILD_NO_EXPORT
// -----------------------------------------------------------------------------------
int Assimp_Dump(const char *const *params, unsigned int num) {
const char *fail = "assimp dump: Invalid number of arguments. "
"See \'assimp dump --help\'\r\n";
// --help
if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
printf("%s", AICMD_MSG_DUMP_HELP);
return AssimpCmdError::Success;
}
// asssimp dump in out [options]
if (num < 1) {
printf("%s", fail);
return AssimpCmdError::InvalidNumberOfArguments;
}
std::string in = std::string(params[0]);
std::string cur_out = (num > 1 ? std::string(params[1]) : std::string("-"));
// store full command line
std::string cmd;
for (unsigned int i = (cur_out[0] == '-' ? 1 : 2); i < num; ++i) {
if (!params[i]) continue;
cmd.append(params[i]);
cmd.append(" ");
}
// get import flags
ImportData import;
ProcessStandardArguments(import, params + 1, num - 1);
bool binary = false, cur_shortened = false, compressed = false;
// process other flags
for (unsigned int i = 1; i < num; ++i) {
if (!params[i]) {
continue;
}
if (!strcmp(params[i], "-b") || !strcmp(params[i], "--binary")) {
binary = true;
} else if (!strcmp(params[i], "-s") || !strcmp(params[i], "--short")) {
cur_shortened = true;
} else if (!strcmp(params[i], "-z") || !strcmp(params[i], "--compressed")) {
compressed = true;
}
#if 0
else if (i > 2 || params[i][0] == '-') {
::printf("Unknown parameter: %s\n",params[i]);
return 10;
}
#endif
}
if (cur_out[0] == '-') {
// take file name from input file
std::string::size_type pos = in.find_last_of('.');
if (pos == std::string::npos) {
pos = in.length();
}
cur_out = in.substr(0, pos);
cur_out.append((binary ? ".assbin" : ".assxml"));
if (cur_shortened && binary) {
cur_out.append(".regress");
}
}
// import the main model
const aiScene *scene = ImportModel(import, in);
if (!scene) {
printf("assimp dump: Unable to load input file %s\n", in.c_str());
return AssimpCmdError::FailedToLoadInputFile;
}
try {
// Dump the main model, using the appropriate method.
std::unique_ptr<IOSystem> pIOSystem(new DefaultIOSystem());
if (binary) {
DumpSceneToAssbin(cur_out.c_str(), cmd.c_str(), pIOSystem.get(),
scene, shortened, compressed);
} else {
DumpSceneToAssxml(cur_out.c_str(), cmd.c_str(), pIOSystem.get(),
scene, shortened);
}
} catch (const std::exception &e) {
printf("%s", ("assimp dump: " + std::string(e.what())).c_str());
return AssimpCmdError::ExceptionWasRaised;
} catch (...) {
printf("assimp dump: An unknown exception occurred.\n");
return AssimpCmdError::ExceptionWasRaised;
}
printf("assimp dump: Wrote output dump %s\n", cur_out.c_str());
return AssimpCmdError::Success;
}
#else
int Assimp_Dump(const char *const *, unsigned int ) {
printf("assimp dump: Export disabled.\n");
return AssimpCmdError::UnrecognizedCommand;
}
#endif

View file

@ -0,0 +1,43 @@
#include <assimp/revision.h>
#if defined(__GNUC__) && defined(_WIN32)
#include "winresrc.h"
#else
#include "winres.h"
#endif
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
IDI_ASSIMP_CMD ICON "../shared/assimp_tools_icon.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_FILEVERSION
FILEFLAGSMASK VS_FF_DEBUG
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#endif
FILEOS VOS_NT
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "Comments", "Licensed under a 3-clause BSD license"
VALUE "CompanyName", "ASSIMP Team"
VALUE "FileDescription", "ASSIMP CMD Application"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "assimp"
VALUE "LegalCopyright", VER_COPYRIGHT_STR
VALUE "OriginalFilename", "assimp.exe"
VALUE "ProductName", "ASSIMP CMD Application"
VALUE "ProductVersion", VER_FILEVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 65001
END
END

View file

@ -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