Build Assimp from source

This commit is contained in:
Dane Johnson
2021-03-15 13:46:19 -05:00
parent b7a83a2876
commit a41fcbe7f4
2126 changed files with 1385127 additions and 40 deletions

View File

@@ -0,0 +1,78 @@
# Open Asset Import Library (assimp)
# ----------------------------------------------------------------------
#
# Copyright (c) 2006-2019, 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 2.6 )
INCLUDE_DIRECTORIES(
${Assimp_SOURCE_DIR}/include
${Assimp_SOURCE_DIR}/code
${Assimp_BINARY_DIR}/tools/assimp_cmd
)
LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib )
ADD_EXECUTABLE( assimp_cmd
assimp_cmd.rc
CompareDump.cpp
ImageExtractor.cpp
Main.cpp
Main.h
resource.h
WriteDumb.cpp
Info.cpp
Export.cpp
)
SET_PROPERTY(TARGET assimp_cmd PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
IF( WIN32 )
ADD_CUSTOM_COMMAND(TARGET assimp_cmd
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:assimp> $<TARGET_FILE_DIR:assimp_cmd>
MAIN_DEPENDENCY assimp)
ENDIF( WIN32 )
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,952 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file CompareDump.cpp
* @brief Implementation of the 'assimp cmpdmp', which compares
* two model dumps for equality. It plays an important role
* in the regression test suite.
*/
#include "Main.h"
const char* AICMD_MSG_CMPDUMP_HELP =
"assimp cmpdump <actual> <expected>\n"
"\tCompare two short dumps produced with \'assimp dump <..> -s\' for equality.\n"
;
#include "Common/assbin_chunks.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
#include "generic_inserter.hpp"
#include <map>
#include <deque>
#include <stack>
#include <sstream>
#include <iostream>
#include <assimp/ai_assert.h>
// get << for aiString
template <typename char_t, typename traits_t>
void mysprint(std::basic_ostream<char_t, traits_t>& os, const aiString& vec) {
os << "[length: \'" << std::dec << vec.length << "\' content: \'" << vec.data << "\']";
}
template <typename char_t, typename traits_t>
std::basic_ostream<char_t, traits_t>& operator<< (std::basic_ostream<char_t, traits_t>& os, const aiString& vec) {
return generic_inserter(mysprint<char_t,traits_t>, os, vec);
}
class sliced_chunk_iterator;
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class compare_fails_exception
///
/// @brief Sentinel exception to return quickly from deeply nested control paths
////////////////////////////////////////////////////////////////////////////////////////////////////
class compare_fails_exception : public virtual std::exception {
public:
enum {MAX_ERR_LEN = 4096};
/* public c'tors */
compare_fails_exception(const char* msg) {
strncpy(mywhat,msg,MAX_ERR_LEN-1);
strcat(mywhat,"\n");
}
/* public member functions */
const char* what() const throw() {
return mywhat;
}
private:
char mywhat[MAX_ERR_LEN+1];
};
#define MY_FLT_EPSILON 1e-1f
#define MY_DBL_EPSILON 1e-1
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class comparer_context
///
/// @brief Record our way through the files to be compared and dump useful information if we fail.
////////////////////////////////////////////////////////////////////////////////////////////////////
class comparer_context {
friend class sliced_chunk_iterator;
public:
/* construct given two file handles to compare */
comparer_context(FILE* actual,FILE* expect)
: actual(actual)
, expect(expect)
, cnt_chunks(0)
{
ai_assert(actual);
ai_assert(expect);
fseek(actual,0,SEEK_END);
lengths.push(std::make_pair(static_cast<uint32_t>(ftell(actual)),0));
fseek(actual,0,SEEK_SET);
history.push_back(HistoryEntry("---",PerChunkCounter()));
}
public:
/* set new scope */
void push_elem(const char* msg) {
const std::string s = msg;
PerChunkCounter::const_iterator it = history.back().second.find(s);
if(it != history.back().second.end()) {
++history.back().second[s];
}
else history.back().second[s] = 0;
history.push_back(HistoryEntry(s,PerChunkCounter()));
debug_trace.push_back("PUSH " + s);
}
/* leave current scope */
void pop_elem() {
ai_assert(history.size());
debug_trace.push_back("POP "+ history.back().first);
history.pop_back();
}
/* push current chunk length and start offset on top of stack */
void push_length(uint32_t nl, uint32_t start) {
lengths.push(std::make_pair(nl,start));
++cnt_chunks;
}
/* pop the chunk length stack */
void pop_length() {
ai_assert(lengths.size());
lengths.pop();
}
/* access the current chunk length */
uint32_t get_latest_chunk_length() {
ai_assert(lengths.size());
return lengths.top().first;
}
/* access the current chunk start offset */
uint32_t get_latest_chunk_start() {
ai_assert(lengths.size());
return lengths.top().second;
}
/* total number of chunk headers passed so far*/
uint32_t get_num_chunks() {
return cnt_chunks;
}
/* get ACTUAL file desc. != NULL */
FILE* get_actual() const {
return actual;
}
/* get EXPECT file desc. != NULL */
FILE* get_expect() const {
return expect;
}
/* compare next T from both streams, name occurs in error messages */
template<typename T> T cmp(const std::string& name) {
T a,e;
read(a,e);
if(a != e) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is " << a,
ss.str()),name);
}
// std::cout << name << " " << std::hex << a << std::endl;
return a;
}
/* compare next num T's from both streams, name occurs in error messages */
template<typename T> void cmp(size_t num,const std::string& name) {
for(size_t n = 0; n < num; ++n) {
std::stringstream ss;
cmp<T>((ss<<name<<"["<<n<<"]",ss.str()));
// std::cout << name << " " << std::hex << a << std::endl;
}
}
/* Bounds of an aiVector3D array (separate function
* because partial specializations of member functions are illegal--)*/
template<typename T> void cmp_bounds(const std::string& name) {
cmp<T> (name+".<minimum-value>");
cmp<T> (name+".<maximum-value>");
}
private:
/* Report failure */
AI_WONT_RETURN void failure(const std::string& err, const std::string& name) AI_WONT_RETURN_SUFFIX {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Files are different at "
<< history.back().first
<< "."
<< name
<< ".\nError is: "
<< err
<< ".\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
/** print our 'stack' */
std::string print_hierarchy() {
std::stringstream ss;
ss << "\n";
const char* last = history.back().first.c_str();
std::string pad;
for(ChunkHistory::reverse_iterator rev = history.rbegin(),
end = history.rend(); rev != end; ++rev, pad += " ")
{
ss << pad << (*rev).first << "(Index: " << (*rev).second[last] << ")" << "\n";
last = (*rev).first.c_str();
}
ss << std::endl << "Debug trace: "<< "\n";
for (std::vector<std::string>::const_iterator it = debug_trace.begin(); it != debug_trace.end(); ++it) {
ss << *it << "\n";
}
ss << std::flush;
return ss.str();
}
/* read from both streams at the same time */
template <typename T> void read(T& filla,T& fille) {
if(1 != fread(&filla,sizeof(T),1,actual)) {
EOFActual();
}
if(1 != fread(&fille,sizeof(T),1,expect)) {
EOFExpect();
}
}
private:
void EOFActual() {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Unexpected EOF reading ACTUAL.\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
void EOFExpect() {
std::stringstream ss;
throw compare_fails_exception((ss
<< "Unexpected EOF reading EXPECT.\nCurrent position in scene hierarchy is "
<< print_hierarchy(),ss.str().c_str()
));
}
FILE *const actual, *const expect;
typedef std::map<std::string,unsigned int> PerChunkCounter;
typedef std::pair<std::string,PerChunkCounter> HistoryEntry;
typedef std::deque<HistoryEntry> ChunkHistory;
ChunkHistory history;
std::vector<std::string> debug_trace;
typedef std::stack<std::pair<uint32_t,uint32_t> > LengthStack;
LengthStack lengths;
uint32_t cnt_chunks;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
/* specialization for aiString (it needs separate handling because its on-disk representation
* differs from its binary representation in memory and can't be treated as an array of n T's.*/
template <> void comparer_context :: read<aiString>(aiString& filla,aiString& fille) {
uint32_t lena,lene;
read(lena,lene);
if(lena && 1 != fread(&filla.data,lena,1,actual)) {
EOFActual();
}
if(lene && 1 != fread(&fille.data,lene,1,expect)) {
EOFExpect();
}
fille.data[fille.length=static_cast<unsigned int>(lene)] = '\0';
filla.data[filla.length=static_cast<unsigned int>(lena)] = '\0';
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for float, uses epsilon for comparisons*/
template<> float comparer_context :: cmp<float>(const std::string& name)
{
float a,e,t;
read(a,e);
if((t=fabs(a-e)) > MY_FLT_EPSILON) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is "
<< a << " (delta is " << t << ")", ss.str()),name);
}
return a;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for double, uses epsilon for comparisons*/
template<> double comparer_context :: cmp<double>(const std::string& name)
{
double a,e,t;
read(a,e);
if((t=fabs(a-e)) > MY_DBL_EPSILON) {
std::stringstream ss;
failure((ss<< "Expected " << e << ", but actual is "
<< a << " (delta is " << t << ")", ss.str()),name);
}
return a;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVector3D */
template<> aiVector3D comparer_context :: cmp<aiVector3D >(const std::string& name)
{
const float x = cmp<float>(name+".x");
const float y = cmp<float>(name+".y");
const float z = cmp<float>(name+".z");
return aiVector3D(x,y,z);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiColor4D */
template<> aiColor4D comparer_context :: cmp<aiColor4D >(const std::string& name)
{
const float r = cmp<float>(name+".r");
const float g = cmp<float>(name+".g");
const float b = cmp<float>(name+".b");
const float a = cmp<float>(name+".a");
return aiColor4D(r,g,b,a);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiQuaternion */
template<> aiQuaternion comparer_context :: cmp<aiQuaternion >(const std::string& name)
{
const float w = cmp<float>(name+".w");
const float x = cmp<float>(name+".x");
const float y = cmp<float>(name+".y");
const float z = cmp<float>(name+".z");
return aiQuaternion(w,x,y,z);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiQuatKey */
template<> aiQuatKey comparer_context :: cmp<aiQuatKey >(const std::string& name)
{
const double mTime = cmp<double>(name+".mTime");
const aiQuaternion mValue = cmp<aiQuaternion>(name+".mValue");
return aiQuatKey(mTime,mValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVectorKey */
template<> aiVectorKey comparer_context :: cmp<aiVectorKey >(const std::string& name)
{
const double mTime = cmp<double>(name+".mTime");
const aiVector3D mValue = cmp<aiVector3D>(name+".mValue");
return aiVectorKey(mTime,mValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiMatrix4x4 */
template<> aiMatrix4x4 comparer_context :: cmp<aiMatrix4x4 >(const std::string& name)
{
aiMatrix4x4 res;
for(unsigned int i = 0; i < 4; ++i) {
for(unsigned int j = 0; j < 4; ++j) {
std::stringstream ss;
res[i][j] = cmp<float>(name+(ss<<".m"<<i<<j,ss.str()));
}
}
return res;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Specialization for aiVertexWeight */
template<> aiVertexWeight comparer_context :: cmp<aiVertexWeight >(const std::string& name)
{
const unsigned int mVertexId = cmp<unsigned int>(name+".mVertexId");
const float mWeight = cmp<float>(name+".mWeight");
return aiVertexWeight(mVertexId,mWeight);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class sliced_chunk_iterator
///
/// @brief Helper to iterate easily through corresponding chunks of two dumps simultaneously.
///
/// Not a *real* iterator, doesn't fully conform to the isocpp iterator spec
////////////////////////////////////////////////////////////////////////////////////////////////////
class sliced_chunk_iterator {
friend class sliced_chunk_reader;
sliced_chunk_iterator(comparer_context& ctx, long end)
: ctx(ctx)
, endit(false)
, next(std::numeric_limits<long>::max())
, end(end)
{
load_next();
}
public:
~sliced_chunk_iterator() {
fseek(ctx.get_actual(),end,SEEK_SET);
fseek(ctx.get_expect(),end,SEEK_SET);
}
public:
/* get current chunk head */
typedef std::pair<uint32_t,uint32_t> Chunk;
const Chunk& operator*() {
return current;
}
/* get to next chunk head */
const sliced_chunk_iterator& operator++() {
cleanup();
load_next();
return *this;
}
/* */
bool is_end() const {
return endit;
}
private:
/* get to the end of *this* chunk */
void cleanup() {
if(next != std::numeric_limits<long>::max()) {
fseek(ctx.get_actual(),next,SEEK_SET);
fseek(ctx.get_expect(),next,SEEK_SET);
ctx.pop_length();
}
}
/* advance to the next chunk */
void load_next() {
Chunk actual;
size_t res=0;
const long cur = ftell(ctx.get_expect());
if(end-cur<8) {
current = std::make_pair(0u,0u);
endit = true;
return;
}
res|=fread(&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() {
}
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]");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyNode(comparer_context& comp) {
scoped_chunk chunk(comp,"aiNode");
comp.cmp<aiString>("mName");
comp.cmp<aiMatrix4x4>("mTransformation");
comp.cmp<uint32_t>("mNumChildren");
comp.cmp<uint32_t>(comp.cmp<uint32_t>("mNumMeshes"),"mMeshes");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AINODE) {
CompareOnTheFlyNode(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFlyScene(comparer_context& comp) {
scoped_chunk chunk(comp,"aiScene");
comp.cmp<uint32_t>("mFlags");
comp.cmp<uint32_t>("mNumMeshes");
comp.cmp<uint32_t>("mNumMaterials");
comp.cmp<uint32_t>("mNumAnimations");
comp.cmp<uint32_t>("mNumTextures");
comp.cmp<uint32_t>("mNumLights");
comp.cmp<uint32_t>("mNumCameras");
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AIMATERIAL) {
CompareOnTheFlyMaterial(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AITEXTURE) {
CompareOnTheFlyTexture(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AIMESH) {
CompareOnTheFlyMesh(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AIANIMATION) {
CompareOnTheFlyAnimation(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AICAMERA) {
CompareOnTheFlyCamera(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AILIGHT) {
CompareOnTheFlyLight(comp);
}
else if ((*it).first == ASSBIN_CHUNK_AINODE) {
CompareOnTheFlyNode(comp);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CompareOnTheFly(comparer_context& comp)
{
sliced_chunk_reader reader(comp);
for(sliced_chunk_iterator it = reader.begin(); !it.is_end(); ++it) {
if ((*it).first == ASSBIN_CHUNK_AISCENE) {
CompareOnTheFlyScene(comp);
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CheckHeader(comparer_context& comp)
{
fseek(comp.get_actual(),ASSBIN_HEADER_LENGTH,SEEK_CUR);
fseek(comp.get_expect(),ASSBIN_HEADER_LENGTH,SEEK_CUR);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
int Assimp_CompareDump (const char* const* params, unsigned int num)
{
// --help
if ((num == 1 && !strcmp( params[0], "-h")) || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) {
printf("%s",AICMD_MSG_CMPDUMP_HELP);
return 0;
}
// assimp cmpdump actual expected
if (num < 2) {
std::cout << "assimp cmpdump: Invalid number of arguments. "
"See \'assimp cmpdump --help\'\r\n" << std::endl;
return 1;
}
if(!strcmp(params[0],params[1])) {
std::cout << "assimp cmpdump: same file, same content." << std::endl;
return 0;
}
class file_ptr
{
public:
file_ptr(FILE *p)
: m_file(p)
{}
~file_ptr()
{
if (m_file)
{
fclose(m_file);
m_file = NULL;
}
}
operator FILE *() { return m_file; }
private:
FILE *m_file;
};
file_ptr actual(fopen(params[0],"rb"));
if (!actual) {
std::cout << "assimp cmpdump: Failure reading ACTUAL data from " <<
params[0] << std::endl;
return -5;
}
file_ptr expected(fopen(params[1],"rb"));
if (!expected) {
std::cout << "assimp cmpdump: Failure reading EXPECT data from " <<
params[1] << std::endl;
return -6;
}
comparer_context comp(actual,expected);
try {
CheckHeader(comp);
CompareOnTheFly(comp);
}
catch(const compare_fails_exception& ex) {
printf("%s",ex.what());
return -1;
}
catch(...) {
// we don't bother checking too rigourously here, so
// we might end up here ...
std::cout << "Unknown failure, are the input files well-defined?";
return -3;
}
std::cout << "Success (totally " << std::dec << comp.get_num_chunks() <<
" chunks)" << std::endl;
return 0;
}

View File

@@ -0,0 +1,174 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, 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"
#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 1;
}
// --help
if (!strcmp( params[0], "-h") || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) {
printf("%s",AICMD_MSG_EXPORT_HELP_E);
return 0;
}
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(),::tolower);
// 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 s = in.find_last_of('.');
if (s == std::string::npos) {
s = in.length();
}
out = in.substr(0,s);
}
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 -39;
}
// derive the final file name
out += "."+outext;
// and call the export routine
if(!ExportModel(scene, import, out,e->id)) {
return -25;
}
printf("assimp export: wrote output file: %s\n",out.c_str());
return 0;
}
#endif // no export

View File

@@ -0,0 +1,376 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, 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/fast_atof.h>
#include <assimp/StringComparison.h>
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=grey,+8=rle packed
uint16_t colourmapstart; // first colour map entry in palette
uint16_t colourmaplength; // number of colours 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 = 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 1;
}
return 0;
}
// -----------------------------------------------------------------------------------
// 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 1;
}
// --help
if (!strcmp( params[0], "-h") || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) {
printf("%s",AICMD_MSG_DUMP_HELP_E);
return 0;
}
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(),::tolower);
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 5;
}
// 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 %i requested, but there are just %i textures\n",
texIdx, scene->mNumTextures);
return 6;
}
}
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 %i 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 7;
}
int m;
if (!tex->mHeight) {
m = (1 != fwrite(tex->pcData,tex->mWidth,1,p));
}
else m = DoExport(tex,p,extension,flags);
::fclose(p);
printf("assimp extract: Wrote texture %i to %s\n",i, out_cpy.c_str());
if (texIdx != 0xffffffff)
return m;
}
return 0;
}

View File

@@ -0,0 +1,477 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Info.cpp
* @brief Implementation of the 'assimp info' utility */
#include "Main.h"
#include <cstdio>
#include <iostream>
#include <string>
const char* AICMD_MSG_INFO_HELP_E =
"assimp info <file> [-r] [-v]\n"
"\tPrint basic structure of a 3D model\n"
"\t-r,--raw: No postprocessing, do a raw import\n"
"\t-v,--verbose: Print verbose info such as node transform data\n"
"\t-s, --silent: Print only minimal info\n";
const char *TREE_BRANCH_ASCII = "|-";
const char *TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4";
const char *TREE_STOP_ASCII = "'-";
const char *TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4";
const char *TREE_CONTINUE_ASCII = "| ";
const char *TREE_CONTINUE_UTF8 = "\xe2\x94\x82 ";
// note: by default this is using utf-8 text.
// this is well supported on pretty much any linux terminal.
// if this causes problems on some platform,
// put an #ifdef to use the ascii version for that platform.
const char *TREE_BRANCH = TREE_BRANCH_UTF8;
const char *TREE_STOP = TREE_STOP_UTF8;
const char *TREE_CONTINUE = TREE_CONTINUE_UTF8;
// -----------------------------------------------------------------------------------
unsigned int CountNodes(const aiNode* root)
{
unsigned int i = 0;
for (unsigned int a = 0; a < root->mNumChildren; ++a ) {
i += CountNodes(root->mChildren[a]);
}
return 1+i;
}
// -----------------------------------------------------------------------------------
unsigned int GetMaxDepth(const aiNode* root)
{
unsigned int cnt = 0;
for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
cnt = std::max(cnt,GetMaxDepth(root->mChildren[i]));
}
return cnt+1;
}
// -----------------------------------------------------------------------------------
unsigned int CountVertices(const aiScene* scene)
{
unsigned int cnt = 0;
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumVertices;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountFaces(const aiScene* scene)
{
unsigned int cnt = 0;
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumFaces;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountBones(const aiScene* scene)
{
unsigned int cnt = 0;
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
cnt += scene->mMeshes[i]->mNumBones;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int CountAnimChannels(const aiScene* scene)
{
unsigned int cnt = 0;
for(unsigned int i = 0; i < scene->mNumAnimations; ++i) {
cnt += scene->mAnimations[i]->mNumChannels;
}
return cnt;
}
// -----------------------------------------------------------------------------------
unsigned int GetAvgFacePerMesh(const aiScene* scene) {
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene)/scene->mNumMeshes) : 0;
}
// -----------------------------------------------------------------------------------
unsigned int GetAvgVertsPerMesh(const aiScene* scene) {
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene)/scene->mNumMeshes) : 0;
}
// -----------------------------------------------------------------------------------
void FindSpecialPoints(const aiScene* scene,const aiNode* root,aiVector3D special_points[3],const aiMatrix4x4& mat=aiMatrix4x4())
{
// XXX that could be greatly simplified by using code from code/ProcessHelper.h
// XXX I just don't want to include it here.
const aiMatrix4x4 trafo = root->mTransformation*mat;
for(unsigned int i = 0; i < root->mNumMeshes; ++i) {
const aiMesh* mesh = scene->mMeshes[root->mMeshes[i]];
for(unsigned int a = 0; a < mesh->mNumVertices; ++a) {
aiVector3D v = trafo*mesh->mVertices[a];
special_points[0].x = std::min(special_points[0].x,v.x);
special_points[0].y = std::min(special_points[0].y,v.y);
special_points[0].z = std::min(special_points[0].z,v.z);
special_points[1].x = std::max(special_points[1].x,v.x);
special_points[1].y = std::max(special_points[1].y,v.y);
special_points[1].z = std::max(special_points[1].z,v.z);
}
}
for(unsigned int i = 0; i < root->mNumChildren; ++i) {
FindSpecialPoints(scene,root->mChildren[i],special_points,trafo);
}
}
// -----------------------------------------------------------------------------------
void FindSpecialPoints(const aiScene* scene,aiVector3D special_points[3])
{
special_points[0] = aiVector3D(1e10,1e10,1e10);
special_points[1] = aiVector3D(-1e10,-1e10,-1e10);
FindSpecialPoints(scene,scene->mRootNode,special_points);
special_points[2] = (special_points[0]+special_points[1])*(ai_real)0.5;
}
// -----------------------------------------------------------------------------------
std::string FindPTypes(const aiScene* scene)
{
bool haveit[4] = {0};
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes;
if (pt & aiPrimitiveType_POINT) {
haveit[0]=true;
}
if (pt & aiPrimitiveType_LINE) {
haveit[1]=true;
}
if (pt & aiPrimitiveType_TRIANGLE) {
haveit[2]=true;
}
if (pt & aiPrimitiveType_POLYGON) {
haveit[3]=true;
}
}
return (haveit[0]?std::string("points"):"")+(haveit[1]?"lines":"")+
(haveit[2]?"triangles":"")+(haveit[3]?"n-polygons":"");
}
// -----------------------------------------------------------------------------------
// Prettily print the node graph to stdout
void PrintHierarchy(
const aiNode* node,
const std::string &indent,
bool verbose,
bool last = false,
bool first = true
){
// tree visualization
std::string branchchar;
if (first) { branchchar = ""; }
else if (last) { branchchar = TREE_STOP; } // "'-"
else { branchchar = TREE_BRANCH; } // "|-"
// print the indent and the branch character and the name
std::cout << indent << branchchar << node->mName.C_Str();
// if there are meshes attached, indicate this
if (node->mNumMeshes) {
std::cout << " (mesh ";
bool sep = false;
for (size_t i=0; i < node->mNumMeshes; ++i) {
unsigned int mesh_index = node->mMeshes[i];
if (sep) { std::cout << ", "; }
std::cout << mesh_index;
sep = true;
}
std::cout << ")";
}
// finish the line
std::cout << std::endl;
// in verbose mode, print the transform data as well
if (verbose) {
// indent to use
std::string indentadd;
if (last) { indentadd += " "; }
else { indentadd += TREE_CONTINUE; } // "| "..
if (node->mNumChildren == 0) { indentadd += " "; }
else { indentadd += TREE_CONTINUE; } // .."| "
aiVector3D s, r, t;
node->mTransformation.Decompose(s, r, t);
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
std::cout << indent << indentadd;
printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
}
if (r.x || r.y || r.z) {
std::cout << indent << indentadd;
printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
}
if (t.x || t.y || t.z) {
std::cout << indent << indentadd;
printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
}
}
// and recurse
std::string nextIndent;
if (first) { nextIndent = indent; }
else if (last) { nextIndent = indent + " "; }
else { nextIndent = indent + TREE_CONTINUE; } // "| "
for (size_t i = 0; i < node->mNumChildren; ++i) {
bool lastone = (i == node->mNumChildren - 1);
PrintHierarchy(
node->mChildren[i],
nextIndent,
verbose,
lastone,
false
);
}
}
// -----------------------------------------------------------------------------------
// Implementation of the assimp info utility to print basic file info
int Assimp_Info (const char* const* params, unsigned int num) {
// --help
if (!strcmp( params[0],"-h")||!strcmp( params[0],"--help")||!strcmp( params[0],"-?") ) {
printf("%s",AICMD_MSG_INFO_HELP_E);
return 0;
}
// asssimp info <file> [-r]
if (num < 1) {
printf("assimp info: Invalid number of arguments. "
"See \'assimp info --help\'\n");
return 1;
}
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 forbitten. ");
return 1;
}
// 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 5;
}
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 0;
}
// meshes
if (scene->mNumMeshes) {
printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n");
}
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
const aiMesh* mesh = scene->mMeshes[i];
printf(" %d (%s)", i, mesh->mName.C_Str());
printf(
": [%d / %d / %d |",
mesh->mNumVertices,
mesh->mNumBones,
mesh->mNumFaces
);
const unsigned int ptypes = mesh->mPrimitiveTypes;
if (ptypes & aiPrimitiveType_POINT) { printf(" point"); }
if (ptypes & aiPrimitiveType_LINE) { printf(" line"); }
if (ptypes & aiPrimitiveType_TRIANGLE) { printf(" triangle"); }
if (ptypes & aiPrimitiveType_POLYGON) { printf(" polygon"); }
printf("]\n");
}
// materials
unsigned int total=0;
for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
aiString name;
if (AI_SUCCESS==aiGetMaterialString(scene->mMaterials[i],AI_MATKEY_NAME,&name)) {
printf("%s\n \'%s\'",(total++?"":"\nNamed Materials:" ),name.data);
}
}
if(total) {
printf("\n");
}
// textures
total=0;
for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
aiString name;
static const aiTextureType types[] = {
aiTextureType_NONE,
aiTextureType_DIFFUSE,
aiTextureType_SPECULAR,
aiTextureType_AMBIENT,
aiTextureType_EMISSIVE,
aiTextureType_HEIGHT,
aiTextureType_NORMALS,
aiTextureType_SHININESS,
aiTextureType_OPACITY,
aiTextureType_DISPLACEMENT,
aiTextureType_LIGHTMAP,
aiTextureType_REFLECTION,
aiTextureType_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 0;
}

View File

@@ -0,0 +1,521 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, 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"
const char* AICMD_MSG_ABOUT =
"------------------------------------------------------ \n"
"Open Asset Import Library (\"Assimp\", https://github.com/assimp/assimp) \n"
" -- Commandline toolchain --\n"
"------------------------------------------------------ \n\n"
"Version %i.%i %s%s%s%s%s(GIT commit %x)\n\n";
const char* AICMD_MSG_HELP =
"assimp <verb> <parameters>\n\n"
" verbs:\n"
" \tinfo - Quick file stats\n"
" \tlistext - List all known file extensions available for import\n"
" \tknowext - Check whether a file extension is recognized by Assimp\n"
#ifndef ASSIMP_BUILD_NO_EXPORT
" \texport - Export a file to one of the supported output formats\n"
" \tlistexport - List all supported export formats\n"
" \texportinfo - Show basic information on a specific export format\n"
#endif
" \textract - Extract embedded texture images\n"
" \tdump - Convert models to a binary or textual dump (ASSBIN/ASSXML)\n"
" \tcmpdump - Compare dumps created using \'assimp dump <file> -s ...\'\n"
" \tversion - Display Assimp version\n"
"\n Use \'assimp <verb> --help\' for detailed help on a command.\n"
;
/*extern*/ Assimp::Importer* globalImporter = NULL;
#ifndef ASSIMP_BUILD_NO_EXPORT
/*extern*/ Assimp::Exporter* globalExporter = NULL;
#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 0;
}
// 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 0;
}
// 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 0;
}
// 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 0;
}
#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 0;
}
// assimp exportinfo
// stat an export format
if (! strcmp(argv[1], "exportinfo")) {
aiString s;
if (argc<3) {
printf("Expected file format id\n");
return -11;
}
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 0;
}
}
printf("Unknown file format id: \'%s\'\n",argv[2]);
return -12;
}
// 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 -10;
}
const bool b = imp.IsExtensionSupported(argv[2]);
printf("File extension \'%s\' is %sknown\n",argv[2],(b?"":"not "));
return b?0:-1;
}
// 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 1;
}
// ------------------------------------------------------------------------------
void SetLogStreams(const ImportData& imp)
{
printf("\nAttaching log stream ... OK\n");
unsigned int flags = 0;
if (imp.logFile.length()) {
flags |= aiDefaultLogStream_FILE;
}
if (imp.showLog) {
flags |= aiDefaultLogStream_STDERR;
}
DefaultLogger::create(imp.logFile.c_str(),imp.verbose ? Logger::VERBOSE : Logger::NORMAL,flags);
}
// ------------------------------------------------------------------------------
void FreeLogStreams()
{
DefaultLogger::kill();
}
// ------------------------------------------------------------------------------
void PrintHorBar()
{
printf("-----------------------------------------------------------------\n");
}
// ------------------------------------------------------------------------------
// Import a specific file
const aiScene* ImportModel(
const ImportData& imp,
const std::string& path)
{
// Attach log streams
if (imp.log) {
SetLogStreams(imp);
}
printf("Launching asset import ... OK\n");
// Now validate this flag combination
if(!globalImporter->ValidateFlags(imp.ppFlags)) {
printf("ERROR: Unsupported post-processing flags \n");
return NULL;
}
printf("Validating postprocessing flags ... OK\n");
if (imp.showLog) {
PrintHorBar();
}
// do the actual import, measure time
const clock_t first = clock();
const aiScene* scene = globalImporter->ReadFile(path,imp.ppFlags);
if (imp.showLog) {
PrintHorBar();
}
if (!scene) {
printf("ERROR: Failed to load file: %s\n", globalImporter->GetErrorString());
return NULL;
}
const clock_t second = ::clock();
const double seconds = static_cast<double>(second-first) / CLOCKS_PER_SEC;
printf("Importing file ... OK \n import took approx. %.5f seconds\n"
"\n",seconds);
if (imp.log) {
FreeLogStreams();
}
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();
}
// 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( 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 0;
}
// ------------------------------------------------------------------------------
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 0;
}

View File

@@ -0,0 +1,205 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Main.h
* @brief Utility declarations for assimp_cmd
*/
#ifndef AICMD_MAIN_INCLUDED
#define AICMD_MAIN_INCLUDED
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <limits>
#include <assimp/postprocess.h>
#include <assimp/version.h>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include <assimp/DefaultLogger.hpp>
#ifndef ASSIMP_BUILD_NO_EXPORT
# include <assimp/Exporter.hpp>
#endif
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include <../contrib/zlib/zlib.h>
#endif
#ifndef SIZE_MAX
# define SIZE_MAX (std::numeric_limits<size_t>::max())
#endif
using namespace Assimp;
// Global assimp importer instance
extern Assimp::Importer* globalImporter;
#ifndef ASSIMP_BUILD_NO_EXPORT
// Global assimp exporter instance
extern Assimp::Exporter* globalExporter;
#endif
// ------------------------------------------------------------------------------
/// Defines common import parameters
struct ImportData {
ImportData()
: ppFlags (0)
, showLog (false)
, verbose (false)
, log (false)
{}
/// 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;
};
// ------------------------------------------------------------------------------
/** Process standard arguments
*
* @param fill Filled by function
* @param params Command line parameters to be processed
* @param num NUmber of params
* @return 0 for success */
int ProcessStandardArguments(ImportData& fill,
const char* 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 dumb'
* @param Number of params
* @return 0 for success*/
int Assimp_Dump (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** assimp_export utility
* @param params Command line parameters to 'assimp export'
* @param Number of params
* @return 0 for success*/
int Assimp_Export (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** assimp_extract utility
* @param params Command line parameters to 'assimp extract'
* @param Number of params
* @return 0 for success*/
int Assimp_Extract (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** assimp_cmpdump utility
* @param params Command line parameters to 'assimp cmpdump'
* @param Number of params
* @return 0 for success*/
int Assimp_CompareDump (
const char* const* params,
unsigned int num);
// ------------------------------------------------------------------------------
/** @brief assimp info utility
* @param params Command line parameters to 'assimp info'
* @param Number of params
* @return 0 for success */
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 0 for success */
int Assimp_TestBatchLoad (
const char* const* params,
unsigned int num);
#endif // !! AICMD_MAIN_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include "../../revision.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Deutsch (Deutschland) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
#ifdef _WIN32
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ASSIMP_VIEW ICON "../shared/assimp_tools_icon.ico"
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
#endif

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

View File

@@ -0,0 +1,21 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by assimp_view.rc
//
#define IDC_MYICON 2
#define IDD_ASSIMP_VIEW_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDI_ASSIMP_VIEW 107
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 159
#define _APS_NEXT_COMMAND_VALUE 32831
#define _APS_NEXT_CONTROL_VALUE 1052
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif