This commit is contained in:
Marco Di Benedetto
2018-02-24 17:06:12 +01:00
41 changed files with 3899 additions and 424 deletions

View File

@@ -45,6 +45,7 @@ namespace Assimp {
namespace D3MF {
namespace XmlTag {
// Model-data specific tags
static const std::string model = "model";
static const std::string model_unit = "unit";
static const std::string metadata = "metadata";
@@ -62,6 +63,8 @@ namespace XmlTag {
static const std::string v2 = "v2";
static const std::string v3 = "v3";
static const std::string id = "id";
static const std::string pid = "pid";
static const std::string p1 = "p1";
static const std::string name = "name";
static const std::string type = "type";
static const std::string build = "build";
@@ -69,6 +72,13 @@ namespace XmlTag {
static const std::string objectid = "objectid";
static const std::string transform = "transform";
// Material definitions
static const std::string basematerials = "basematerials";
static const std::string basematerials_base = "base";
static const std::string basematerials_name = "name";
static const std::string basematerials_displaycolor = "displaycolor";
// Meta info tags
static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
@@ -83,7 +93,6 @@ namespace XmlTag {
static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
}
} // Namespace D3MF

View File

@@ -205,7 +205,7 @@ enum ErrorPolicy {
// -------------------------------------------------------------------------------
/** Represents a data structure in a BLEND file. A Structure defines n fields
* and their locatios and encodings the input stream. Usually, every
* and their locations and encodings the input stream. Usually, every
* Structure instance pertains to one equally-named data structure in the
* BlenderScene.h header. This class defines various utilities to map a
* binary `blob` read from the file to such a structure instance with

View File

@@ -502,7 +502,7 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
{
// the file blocks appear in list sorted by
// with ascending base addresses so we can run a
// binary search to locate the pointee quickly.
// binary search to locate the pointer quickly.
// NOTE: Blender seems to distinguish between side-by-side
// data (stored in the same data block) and far pointers,

View File

@@ -116,7 +116,7 @@ template <> void Structure :: Convert<MTex> (
ReadField<ErrorPolicy_Igno>(temp,"projy",db);
dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(temp,"projz",db);
dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);

View File

@@ -522,6 +522,13 @@ ADD_ASSIMP_IMPORTER( FBX
FBXDeformer.cpp
FBXBinaryTokenizer.cpp
FBXDocumentUtil.cpp
FBXExporter.h
FBXExporter.cpp
FBXExportNode.h
FBXExportNode.cpp
FBXExportProperty.h
FBXExportProperty.cpp
FBXCommon.h
)
SET( PostProcessing_SRCS
@@ -641,7 +648,7 @@ ADD_ASSIMP_IMPORTER( X
XFileExporter.cpp
)
ADD_ASSIMP_IMPORTER(X3D
ADD_ASSIMP_IMPORTER( X3D
X3DExporter.cpp
X3DExporter.hpp
X3DImporter.cpp

View File

@@ -61,6 +61,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unzip.h>
#include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h"
#include <assimp/fast_atof.h>
#include <iomanip>
namespace Assimp {
namespace D3MF {
@@ -68,7 +71,9 @@ namespace D3MF {
class XmlSerializer {
public:
XmlSerializer(XmlReader* xmlReader)
: xmlReader(xmlReader) {
: mMeshes()
, mMaterials()
, xmlReader(xmlReader){
// empty
}
@@ -77,14 +82,21 @@ public:
}
void ImportXml(aiScene* scene) {
if ( nullptr == scene ) {
return;
}
scene->mRootNode = new aiNode();
std::vector<aiNode*> children;
while(ReadToEndElement(D3MF::XmlTag::model)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::object) {
const std::string nodeName( xmlReader->getNodeName() );
if( nodeName == D3MF::XmlTag::object) {
children.push_back(ReadObject(scene));
} else if(xmlReader->getNodeName() == D3MF::XmlTag::build) {
} else if( nodeName == D3MF::XmlTag::build) {
//
} else if ( nodeName == D3MF::XmlTag::basematerials ) {
ReadBaseMaterials();
}
}
@@ -92,11 +104,16 @@ public:
scene->mRootNode->mName.Set( "3MF" );
}
scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
std::copy(meshes.begin(), meshes.end(), scene->mMeshes);
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
scene->mNumMaterials = mMaterials.size();
if ( 0 != scene->mNumMaterials ) {
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
std::copy( mMaterials.begin(), mMaterials.end(), scene->mMaterials );
}
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
@@ -104,8 +121,7 @@ public:
}
private:
aiNode* ReadObject(aiScene* scene)
{
aiNode* ReadObject(aiScene* scene) {
std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds;
@@ -124,19 +140,16 @@ private:
node->mParent = scene->mRootNode;
node->mName.Set(name);
size_t meshIdx = meshes.size();
size_t meshIdx = mMeshes.size();
while(ReadToEndElement(D3MF::XmlTag::object))
{
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
{
while(ReadToEndElement(D3MF::XmlTag::object)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh();
mesh->mName.Set(name);
meshes.push_back(mesh);
mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx));
meshIdx++;
++meshIdx;
}
}
@@ -147,19 +160,14 @@ private:
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
return node.release();
}
aiMesh* ReadMesh() {
aiMesh* mesh = new aiMesh();
while(ReadToEndElement(D3MF::XmlTag::mesh))
{
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
{
while(ReadToEndElement(D3MF::XmlTag::mesh)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
ImportVertices(mesh);
}
else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
{
} else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
ImportTriangles(mesh);
}
}
@@ -167,14 +175,11 @@ private:
return mesh;
}
void ImportVertices(aiMesh* mesh)
{
void ImportVertices(aiMesh* mesh) {
std::vector<aiVector3D> vertices;
while(ReadToEndElement(D3MF::XmlTag::vertices))
{
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex)
{
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex());
}
}
@@ -182,11 +187,9 @@ private:
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
aiVector3D ReadVertex()
{
aiVector3D ReadVertex() {
aiVector3D vertex;
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
@@ -196,16 +199,18 @@ private:
return vertex;
}
void ImportTriangles(aiMesh* mesh)
{
void ImportTriangles(aiMesh* mesh) {
std::vector<aiFace> faces;
while(ReadToEndElement(D3MF::XmlTag::triangles))
{
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
{
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
const std::string nodeName( xmlReader->getNodeName() );
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
faces.push_back(ReadTriangle());
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
if ( nullptr != pidToken ) {
int matIdx( std::atoi( pidToken ) );
mesh->mMaterialIndex = matIdx;
}
}
}
@@ -216,8 +221,7 @@ private:
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
aiFace ReadTriangle()
{
aiFace ReadTriangle() {
aiFace face;
face.mNumIndices = 3;
@@ -229,45 +233,113 @@ private:
return face;
}
private:
bool ReadToStartElement(const std::string& startTag)
{
while(xmlReader->read())
{
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag)
{
return true;
void ReadBaseMaterials() {
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
mMaterials.push_back( readMaterialDef() );
xmlReader->read();
}
}
bool parseColor( const char *color, aiColor4D &diffuse ) {
if ( nullptr == color ) {
return false;
}
const size_t len( strlen( color ) );
if ( 9 != len ) {
return false;
}
const char *buf( color );
if ( '#' != *buf ) {
return false;
}
++buf;
char comp[ 3 ] = { 0,0,'\0' };
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
return true;
}
aiMaterial *readMaterialDef() {
aiMaterial *mat( nullptr );
const char *name( nullptr );
const char *color( nullptr );
const std::string nodeName( xmlReader->getNodeName() );
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
aiString matName;
matName.Set( name );
mat = new aiMaterial;
mat->AddProperty( &matName, AI_MATKEY_NAME );
color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
aiColor4D diffuse;
if ( parseColor( color, diffuse ) ) {
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
}
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END &&
xmlReader->getNodeName() == startTag)
{
}
return mat;
}
private:
bool ReadToStartElement(const std::string& startTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
//DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
bool ReadToEndElement(const std::string& closeTag)
{
while(xmlReader->read())
{
bool ReadToEndElement(const std::string& closeTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
}
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
&& xmlReader->getNodeName() == closeTag)
{
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false;
}
}
DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
private:
std::vector<aiMesh*> meshes;
std::vector<aiMesh*> mMeshes;
std::vector<aiMaterial*> mMaterials;
XmlReader* xmlReader;
};

View File

@@ -97,6 +97,8 @@ void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportPropert
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
//void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
// ------------------------------------------------------------------------------------------------
@@ -169,6 +171,11 @@ Exporter::ExportFormatEntry gExporters[] =
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
#endif
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
//Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
#endif
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
#endif

86
code/FBXCommon.h Normal file
View File

@@ -0,0 +1,86 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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 FBXCommon.h
* Some useful constants and enums for dealing with FBX files.
*/
#ifndef AI_FBXCOMMON_H_INC
#define AI_FBXCOMMON_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
namespace FBX
{
const std::string NULL_RECORD = { // 13 null bytes
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
}; // who knows why
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit
// rotation order. We'll probably use EulerXYZ for everything
enum RotOrder {
RotOrder_EulerXYZ = 0,
RotOrder_EulerXZY,
RotOrder_EulerYZX,
RotOrder_EulerYXZ,
RotOrder_EulerZXY,
RotOrder_EulerZYX,
RotOrder_SphericXYZ,
RotOrder_MAX // end-of-enum sentinel
};
// transformation inheritance method. Most of the time RSrs
enum TransformInheritance {
TransformInheritance_RrSs = 0,
TransformInheritance_RSrs,
TransformInheritance_Rrs,
TransformInheritance_MAX // end-of-enum sentinel
};
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXCOMMON_H_INC

View File

@@ -142,6 +142,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
nodes.reserve( conns.size() );
std::vector<aiNode*> nodes_chain;
std::vector<aiNode*> post_nodes_chain;
try {
for( const Connection* con : conns ) {
@@ -161,6 +162,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
if ( model ) {
nodes_chain.clear();
post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent_transform;
@@ -168,7 +170,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
// assimp (or rather: the complicated transformation chain that
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.
GenerateTransformationNodeChain( *model, nodes_chain );
GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
ai_assert( nodes_chain.size() );
@@ -213,8 +215,39 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
// attach geometry
ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
// attach sub-nodes
ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform );
// check if there will be any child nodes
const std::vector<const Connection*>& child_conns
= doc.GetConnectionsByDestinationSequenced( model->ID(), "Model" );
// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for( aiNode* postnode : post_nodes_chain ) {
ai_assert( postnode );
if ( last_parent != &parent ) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode*[ 1 ];
last_parent->mChildren[ 0 ] = postnode;
}
postnode->mParent = last_parent;
last_parent = postnode;
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
Util::delete_fun<aiNode> deleter;
std::for_each(
post_nodes_chain.begin(),
post_nodes_chain.end(),
deleter
);
}
// attach sub-nodes (if any)
ConvertNodes( model->ID(), *last_parent, new_abs_transform );
if ( doc.Settings().readLights ) {
ConvertLights( *model );
@@ -240,6 +273,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
Util::delete_fun<aiNode> deleter;
std::for_each( nodes.begin(), nodes.end(), deleter );
std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter );
std::for_each( post_nodes_chain.begin(), post_nodes_chain.end(), deleter );
}
}
@@ -396,6 +430,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
return "GeometricRotation";
case TransformationComp_GeometricTranslation:
return "GeometricTranslation";
case TransformationComp_GeometricScalingInverse:
return "GeometricScalingInverse";
case TransformationComp_GeometricRotationInverse:
return "GeometricRotationInverse";
case TransformationComp_GeometricTranslationInverse:
return "GeometricTranslationInverse";
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
default:
break;
@@ -437,6 +477,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
return "GeometricRotation";
case TransformationComp_GeometricTranslation:
return "GeometricTranslation";
case TransformationComp_GeometricScalingInverse:
return "GeometricScalingInverse";
case TransformationComp_GeometricRotationInverse:
return "GeometricRotationInverse";
case TransformationComp_GeometricTranslationInverse:
return "GeometricTranslationInverse";
case TransformationComp_MAXIMUM: // this is to silence compiler warnings
break;
}
@@ -548,17 +594,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
bool ok;
const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
const TransformationComp comp = static_cast< TransformationComp >( i );
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
continue;
}
bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
if ( ok && v.SquareLength() > zero_epsilon ) {
return true;
if ( ok && scale_compare ) {
if ( (v - all_ones).SquareLength() > zero_epsilon ) {
return true;
}
} else if ( ok ) {
if ( v.SquareLength() > zero_epsilon ) {
return true;
}
}
}
@@ -570,7 +624,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
}
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes )
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
{
const PropertyTable& props = model.Props();
const Model::RotOrder rot = model.RotationOrder();
@@ -582,6 +636,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// generate transformation matrices for all the different transformation components
const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
bool is_complex = false;
const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
@@ -634,7 +689,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
}
const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) {
if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
}
@@ -644,18 +699,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
}
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) {
if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
aiVector3D GeometricScalingInverse = GeometricScaling;
bool canscale = true;
for (size_t i = 0; i < 3; ++i) {
if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
} else {
FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
canscale = false;
break;
}
}
if (canscale) {
aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
}
}
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
is_complex = true;
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
chain[ TransformationComp_GeometricRotationInverse ].Inverse();
}
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
}
// is_complex needs to be consistent with NeedsComplexTransformationChain()
@@ -690,10 +765,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
}
aiNode* nd = new aiNode();
output_nodes.push_back( nd );
nd->mName.Set( NameTransformationChainNode( name, comp ) );
nd->mTransformation = chain[ i ];
// geometric inverses go in a post-node chain
if ( comp == TransformationComp_GeometricScalingInverse ||
comp == TransformationComp_GeometricRotationInverse ||
comp == TransformationComp_GeometricTranslationInverse
) {
post_output_nodes.push_back( nd );
} else {
output_nodes.push_back( nd );
}
}
ai_assert( output_nodes.size() );
@@ -2209,8 +2292,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
has_any = true;
if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation &&
comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation )
{
has_complex = true;
}

View File

@@ -82,7 +82,10 @@ public:
* The different parts that make up the final local transformation of a fbx-node
*/
enum TransformationComp {
TransformationComp_Translation = 0,
TransformationComp_GeometricScalingInverse = 0,
TransformationComp_GeometricRotationInverse,
TransformationComp_GeometricTranslationInverse,
TransformationComp_Translation,
TransformationComp_RotationOffset,
TransformationComp_RotationPivot,
TransformationComp_PreRotation,
@@ -153,7 +156,7 @@ private:
/**
* note: memory for output_nodes will be managed by the caller
*/
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes);
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
// ------------------------------------------------------------------------------------------------
void SetupNodeMetadata(const Model& model, aiNode& nd);

284
code/FBXExportNode.cpp Normal file
View File

@@ -0,0 +1,284 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportNode.h"
#include "FBXCommon.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/ai_assert.h>
#include <string>
#include <memory> // shared_ptr
// AddP70<type> helpers... there's no usable pattern here,
// so all are defined as separate functions.
// Even "animatable" properties are often completely different
// from the standard (nonanimated) property definition,
// so they are specified with an 'A' suffix.
void FBX::Node::AddP70int(
const std::string& name, int32_t value
) {
FBX::Node n("P");
n.AddProperties(name, "int", "Integer", "", value);
AddChild(n);
}
void FBX::Node::AddP70bool(
const std::string& name, bool value
) {
FBX::Node n("P");
n.AddProperties(name, "bool", "", "", int32_t(value));
AddChild(n);
}
void FBX::Node::AddP70double(
const std::string& name, double value
) {
FBX::Node n("P");
n.AddProperties(name, "double", "Number", "", value);
AddChild(n);
}
void FBX::Node::AddP70numberA(
const std::string& name, double value
) {
FBX::Node n("P");
n.AddProperties(name, "Number", "", "A", value);
AddChild(n);
}
void FBX::Node::AddP70color(
const std::string& name, double r, double g, double b
) {
FBX::Node n("P");
n.AddProperties(name, "ColorRGB", "Color", "", r, g, b);
AddChild(n);
}
void FBX::Node::AddP70colorA(
const std::string& name, double r, double g, double b
) {
FBX::Node n("P");
n.AddProperties(name, "Color", "", "A", r, g, b);
AddChild(n);
}
void FBX::Node::AddP70vector(
const std::string& name, double x, double y, double z
) {
FBX::Node n("P");
n.AddProperties(name, "Vector3D", "Vector", "", x, y, z);
AddChild(n);
}
void FBX::Node::AddP70vectorA(
const std::string& name, double x, double y, double z
) {
FBX::Node n("P");
n.AddProperties(name, "Vector", "", "A", x, y, z);
AddChild(n);
}
void FBX::Node::AddP70string(
const std::string& name, const std::string& value
) {
FBX::Node n("P");
n.AddProperties(name, "KString", "", "", value);
AddChild(n);
}
void FBX::Node::AddP70enum(
const std::string& name, int32_t value
) {
FBX::Node n("P");
n.AddProperties(name, "enum", "", "", value);
AddChild(n);
}
void FBX::Node::AddP70time(
const std::string& name, int64_t value
) {
FBX::Node n("P");
n.AddProperties(name, "KTime", "Time", "", value);
AddChild(n);
}
// public member functions for writing to binary fbx
void FBX::Node::Dump(std::shared_ptr<Assimp::IOStream> outfile)
{
Assimp::StreamWriterLE outstream(outfile);
Dump(outstream);
}
void FBX::Node::Dump(Assimp::StreamWriterLE &s)
{
// write header section (with placeholders for some things)
Begin(s);
// write properties
DumpProperties(s);
// go back and fill in property related placeholders
EndProperties(s, properties.size());
// write children
DumpChildren(s);
// finish, filling in end offset placeholder
End(s, !children.empty());
}
void FBX::Node::Begin(Assimp::StreamWriterLE &s)
{
// remember start pos so we can come back and write the end pos
this->start_pos = s.Tell();
// placeholders for end pos and property section info
s.PutU4(0); // end pos
s.PutU4(0); // number of properties
s.PutU4(0); // total property section length
// node name
s.PutU1(name.size()); // length of node name
s.PutString(name); // node name as raw bytes
// property data comes after here
this->property_start = s.Tell();
}
void FBX::Node::DumpProperties(Assimp::StreamWriterLE& s)
{
for (auto &p : properties) {
p.Dump(s);
}
}
void FBX::Node::DumpChildren(Assimp::StreamWriterLE& s)
{
for (FBX::Node& child : children) {
child.Dump(s);
}
}
void FBX::Node::EndProperties(Assimp::StreamWriterLE &s)
{
EndProperties(s, properties.size());
}
void FBX::Node::EndProperties(
Assimp::StreamWriterLE &s,
size_t num_properties
) {
if (num_properties == 0) { return; }
size_t pos = s.Tell();
ai_assert(pos > property_start);
size_t property_section_size = pos - property_start;
s.Seek(start_pos + 4);
s.PutU4(num_properties);
s.PutU4(property_section_size);
s.Seek(pos);
}
void FBX::Node::End(
Assimp::StreamWriterLE &s,
bool has_children
) {
// if there were children, add a null record
if (has_children) { s.PutString(FBX::NULL_RECORD); }
// now go back and write initial pos
this->end_pos = s.Tell();
s.Seek(start_pos);
s.PutU4(end_pos);
s.Seek(end_pos);
}
// static member functions
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
// TODO: optional zip compression!
void FBX::Node::WritePropertyNode(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s
){
Node node(name);
node.Begin(s);
s.PutU1('d');
s.PutU4(v.size()); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(v.size() * 8); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
node.EndProperties(s, 1);
node.End(s, false);
}
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
// TODO: optional zip compression!
void FBX::Node::WritePropertyNode(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
){
Node node(name);
node.Begin(s);
s.PutU1('i');
s.PutU4(v.size()); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
s.PutU4(v.size() * 4); // data size
for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
node.EndProperties(s, 1);
node.End(s, false);
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

197
code/FBXExportNode.h Normal file
View File

@@ -0,0 +1,197 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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 FBXExportNode.h
* Declares the FBX::Node helper class for fbx export.
*/
#ifndef AI_FBXEXPORTNODE_H_INC
#define AI_FBXEXPORTNODE_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportProperty.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
namespace FBX {
class Node;
}
class FBX::Node
{
public: // public data members
// TODO: accessors
std::string name; // node name
std::vector<FBX::Property> properties; // node properties
std::vector<FBX::Node> children; // child nodes
public: // constructors
Node() = default;
Node(const std::string& n) : name(n) {}
Node(const std::string& n, const FBX::Property &p)
: name(n)
{ properties.push_back(p); }
Node(const std::string& n, const std::vector<FBX::Property> &pv)
: name(n), properties(pv) {}
public: // functions to add properties or children
// add a single property to the node
template <typename T>
void AddProperty(T value) {
properties.emplace_back(value);
}
// convenience function to add multiple properties at once
template <typename T, typename... More>
void AddProperties(T value, More... more) {
properties.emplace_back(value);
AddProperties(more...);
}
void AddProperties() {}
// add a child node directly
void AddChild(const Node& node) { children.push_back(node); }
// convenience function to add a child node with a single property
template <typename... More>
void AddChild(
const std::string& name,
More... more
) {
FBX::Node c(name);
c.AddProperties(more...);
children.push_back(c);
}
public: // support specifically for dealing with Properties70 nodes
// it really is simpler to make these all separate functions.
// the versions with 'A' suffixes are for animatable properties.
// those often follow a completely different format internally in FBX.
void AddP70int(const std::string& name, int32_t value);
void AddP70bool(const std::string& name, bool value);
void AddP70double(const std::string& name, double value);
void AddP70numberA(const std::string& name, double value);
void AddP70color(const std::string& name, double r, double g, double b);
void AddP70colorA(const std::string& name, double r, double g, double b);
void AddP70vector(const std::string& name, double x, double y, double z);
void AddP70vectorA(const std::string& name, double x, double y, double z);
void AddP70string(const std::string& name, const std::string& value);
void AddP70enum(const std::string& name, int32_t value);
void AddP70time(const std::string& name, int64_t value);
// template for custom P70 nodes.
// anything that doesn't fit in the above can be created manually.
template <typename... More>
void AddP70(
const std::string& name,
const std::string& type,
const std::string& type2,
const std::string& flags,
More... more
) {
Node n("P");
n.AddProperties(name, type, type2, flags, more...);
AddChild(n);
}
public: // member functions for writing data to a file or stream
// write the full node as binary data to the given file or stream
void Dump(std::shared_ptr<Assimp::IOStream> outfile);
void Dump(Assimp::StreamWriterLE &s);
// these other functions are for writing data piece by piece.
// they must be used carefully.
// for usage examples see FBXExporter.cpp.
void Begin(Assimp::StreamWriterLE &s);
void DumpProperties(Assimp::StreamWriterLE& s);
void EndProperties(Assimp::StreamWriterLE &s);
void EndProperties(Assimp::StreamWriterLE &s, size_t num_properties);
void DumpChildren(Assimp::StreamWriterLE& s);
void End(Assimp::StreamWriterLE &s, bool has_children);
private: // data used for binary dumps
size_t start_pos; // starting position in stream
size_t end_pos; // ending position in stream
size_t property_start; // starting position of property section
public: // static member functions
// convenience function to create a node with a single property,
// and write it to the stream.
template <typename T>
static void WritePropertyNode(
const std::string& name,
const T value,
Assimp::StreamWriterLE& s
) {
FBX::Property p(value);
FBX::Node node(name, p);
node.Dump(s);
}
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
static void WritePropertyNode(
const std::string& name,
const std::vector<double>& v,
Assimp::StreamWriterLE& s
);
// convenience function to create and write a property node,
// holding a single property which is an array of values.
// does not copy the data, so is efficient for large arrays.
static void WritePropertyNode(
const std::string& name,
const std::vector<int32_t>& v,
Assimp::StreamWriterLE& s
);
};
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTNODE_H_INC

201
code/FBXExportProperty.cpp Normal file
View File

@@ -0,0 +1,201 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_EXPORT
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportProperty.h"
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <string>
#include <vector>
#include <sstream> // stringstream
// constructors for single element properties
FBX::Property::Property(bool v)
: type('C'), data(1)
{
data = {uint8_t(v)};
}
FBX::Property::Property(int16_t v) : type('Y'), data(2)
{
uint8_t* d = data.data();
(reinterpret_cast<int16_t*>(d))[0] = v;
}
FBX::Property::Property(int32_t v) : type('I'), data(4)
{
uint8_t* d = data.data();
(reinterpret_cast<int32_t*>(d))[0] = v;
}
FBX::Property::Property(float v) : type('F'), data(4)
{
uint8_t* d = data.data();
(reinterpret_cast<float*>(d))[0] = v;
}
FBX::Property::Property(double v) : type('D'), data(8)
{
uint8_t* d = data.data();
(reinterpret_cast<double*>(d))[0] = v;
}
FBX::Property::Property(int64_t v) : type('L'), data(8)
{
uint8_t* d = data.data();
(reinterpret_cast<int64_t*>(d))[0] = v;
}
// constructors for array-type properties
FBX::Property::Property(const char* c, bool raw)
: Property(std::string(c), raw)
{}
// strings can either be saved as "raw" (R) data, or "string" (S) data
FBX::Property::Property(const std::string& s, bool raw)
: type(raw ? 'R' : 'S'), data(s.size())
{
for (size_t i = 0; i < s.size(); ++i) {
data[i] = uint8_t(s[i]);
}
}
FBX::Property::Property(const std::vector<uint8_t>& r)
: type('R'), data(r)
{}
FBX::Property::Property(const std::vector<int32_t>& va)
: type('i'), data(4*va.size())
{
int32_t* d = reinterpret_cast<int32_t*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const std::vector<double>& va)
: type('d'), data(8*va.size())
{
double* d = reinterpret_cast<double*>(data.data());
for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
}
FBX::Property::Property(const aiMatrix4x4& vm)
: type('d'), data(8*16)
{
double* d = reinterpret_cast<double*>(data.data());
for (size_t c = 0; c < 4; ++c) {
for (size_t r = 0; r < 4; ++r) {
d[4*c+r] = vm[r][c];
}
}
}
// public member functions
size_t FBX::Property::size()
{
switch (type) {
case 'C': case 'Y': case 'I': case 'F': case 'D': case 'L':
return data.size() + 1;
case 'S': case 'R':
return data.size() + 5;
case 'i': case 'd':
return data.size() + 13;
default:
throw DeadlyExportError("Requested size on property of unknown type");
}
}
void FBX::Property::Dump(Assimp::StreamWriterLE &s)
{
s.PutU1(type);
uint8_t* d;
size_t N;
switch (type) {
case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(data.data()))); return;
case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(data.data()))); return;
case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(data.data()))); return;
case 'F': s.PutF4(*(reinterpret_cast<float*>(data.data()))); return;
case 'D': s.PutF8(*(reinterpret_cast<double*>(data.data()))); return;
case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(data.data()))); return;
case 'S':
case 'R':
s.PutU4(data.size());
for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
return;
case 'i':
N = data.size() / 4;
s.PutU4(N); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(data.size()); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) {
s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
}
return;
case 'd':
N = data.size() / 8;
s.PutU4(N); // number of elements
s.PutU4(0); // no encoding (1 would be zip-compressed)
// TODO: compress if large?
s.PutU4(data.size()); // data size
d = data.data();
for (size_t i = 0; i < N; ++i) {
s.PutF8((reinterpret_cast<double*>(d))[i]);
}
return;
default:
std::stringstream err;
err << "Tried to dump property with invalid type '";
err << type << "'!";
throw DeadlyExportError(err.str());
}
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

123
code/FBXExportProperty.h Normal file
View File

@@ -0,0 +1,123 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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 FBXExportProperty.h
* Declares the FBX::Property helper class for fbx export.
*/
#ifndef AI_FBXEXPORTPROPERTY_H_INC
#define AI_FBXEXPORTPROPERTY_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include <assimp/types.h> // aiMatrix4x4
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <vector>
#include <type_traits> // is_void
namespace FBX {
class Property;
}
/** FBX::Property
*
* Holds a value of any of FBX's recognized types,
* each represented by a particular one-character code.
* C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true
* Y : 2-byte int16
* I : 4-byte int32
* F : 4-byte float
* D : 8-byte double
* L : 8-byte int64
* i : array of int32
* f : array of float
* d : array of double
* l : array of int64
* b : array of 1-byte booleans (0x00 or 0x01)
* S : string (array of 1-byte char)
* R : raw data (array of bytes)
*/
class FBX::Property
{
public:
// constructors for basic types.
// all explicit to avoid accidental typecasting
explicit Property(bool v);
// TODO: determine if there is actually a byte type,
// or if this always means <bool>. 'C' seems to imply <char>,
// so possibly the above was intended to represent both.
explicit Property(int16_t v);
explicit Property(int32_t v);
explicit Property(float v);
explicit Property(double v);
explicit Property(int64_t v);
// strings can either be stored as 'R' (raw) or 'S' (string) type
explicit Property(const char* c, bool raw=false);
explicit Property(const std::string& s, bool raw=false);
explicit Property(const std::vector<uint8_t>& r);
explicit Property(const std::vector<int32_t>& va);
explicit Property(const std::vector<double>& va);
explicit Property(const aiMatrix4x4& vm);
// this will catch any type not defined above,
// so that we don't accidentally convert something we don't want.
// for example (const char*) --> (bool)... seriously wtf C++
template <class T>
explicit Property(T v) : type('X') {
static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
} // note: no line wrap so it appears verbatim on the compiler error
// the size of this property node in a binary file, in bytes
size_t size();
// write this property node as binary data to the given stream
void Dump(Assimp::StreamWriterLE &s);
private:
char type;
std::vector<uint8_t> data;
};
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTPROPERTY_H_INC

2044
code/FBXExporter.cpp Normal file

File diff suppressed because it is too large Load Diff

146
code/FBXExporter.h Normal file
View File

@@ -0,0 +1,146 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2018, 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 FBXExporter.h
* Declares the exporter class to write a scene to an fbx file
*/
#ifndef AI_FBXEXPORTER_H_INC
#define AI_FBXEXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
#include "FBXExportNode.h" // FBX::Node
#include <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <vector>
#include <map>
#include <memory> // shared_ptr
#include <sstream> // stringstream
struct aiScene;
struct aiNode;
//struct aiMaterial;
namespace Assimp
{
class IOSystem;
class IOStream;
class ExportProperties;
// ---------------------------------------------------------------------
/** Helper class to export a given scene to an FBX file. */
// ---------------------------------------------------------------------
class FBXExporter
{
public:
/// Constructor for a specific scene to export
FBXExporter(const aiScene* pScene, const ExportProperties* pProperties);
// call one of these methods to export
void ExportBinary(const char* pFile, IOSystem* pIOSystem);
void ExportAscii(const char* pFile, IOSystem* pIOSystem);
private:
bool binary; // whether current export is in binary or ascii format
const aiScene* mScene; // the scene to export
const ExportProperties* mProperties; // currently unused
std::shared_ptr<IOStream> outfile; // file to write to
std::vector<FBX::Node> connections; // conection storage
std::vector<int64_t> mesh_uids;
std::vector<int64_t> material_uids;
std::map<const aiNode*,int64_t> node_uids;
// this crude unique-ID system is actually fine
int64_t last_uid = 999999;
int64_t generate_uid() { return ++last_uid; }
// binary files have a specific header and footer,
// in addition to the actual data
void WriteBinaryHeader();
void WriteBinaryFooter();
// WriteAllNodes does the actual export.
// It just calls all the Write<Section> methods below in order.
void WriteAllNodes();
// Methods to write individual sections.
// The order here matches the order inside an FBX file.
// Each method corresponds to a top-level FBX section,
// except WriteHeader which also includes some binary-only sections
// and WriteFooter which is binary data only.
void WriteHeaderExtension();
// WriteFileId(); // binary-only, included in WriteHeader
// WriteCreationTime(); // binary-only, included in WriteHeader
// WriteCreator(); // binary-only, included in WriteHeader
void WriteGlobalSettings();
void WriteDocuments();
void WriteReferences();
void WriteDefinitions();
void WriteObjects();
void WriteConnections();
// WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
// helpers
void WriteModelNodes(
Assimp::StreamWriterLE& s,
const aiNode* node,
int64_t parent_uid,
const std::map<std::string,int64_t>& bone_uids
);
void WriteModelNodes( // usually don't call this directly
StreamWriterLE& s,
const aiNode* node,
int64_t parent_uid,
const std::map<std::string,int64_t>& bone_uids,
std::vector<std::pair<std::string,aiVector3D>>& transform_chain
);
};
}
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXEXPORTER_H_INC

View File

@@ -428,16 +428,19 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
const std::vector<unsigned int>& mapping_offsets,
const std::vector<unsigned int>& mappings)
{
bool isDirect = ReferenceInformationType == "Direct";
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
// fallback to direct data if there is no index data element
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
isDirect = true;
isIndexToDirect = false;
}
// handle permutations of Mapping and Reference type - it would be nice to
// deal with this more elegantly and with less redundancy, but right
// now it seems unavoidable.
if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
if ( !HasElement( source, indexDataElementName ) ) {
return;
}
if (MappingInformationType == "ByVertice" && isDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@@ -450,14 +453,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
}
}
}
else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
data_out.resize(vertex_count);
if ( !HasElement( source, indexDataElementName ) ) {
return;
}
std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
@@ -472,7 +472,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
}
}
}
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@@ -485,7 +485,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
data_out.swap(tempData);
}
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));

View File

@@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Implements a filter system to filter calls to Exists() and Open()
* in order to improve the success rate of file opening ...
*/
#pragma once
#ifndef AI_FILESYSTEMFILTER_H_INC
#define AI_FILESYSTEMFILTER_H_INC
#include "../include/assimp/IOSystem.hpp"
#include "../include/assimp/DefaultLogger.hpp"
#include "../include/assimp/fast_atof.h"
#include "../include/assimp/ParsingUtils.h"
#include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/fast_atof.h>
#include <assimp/ParsingUtils.h>
namespace Assimp {
@@ -64,90 +65,89 @@ class FileSystemFilter : public IOSystem
public:
/** Constructor. */
FileSystemFilter(const std::string& file, IOSystem* old)
: wrapped (old)
, src_file (file)
, sep(wrapped->getOsSeparator())
{
ai_assert(NULL != wrapped);
: mWrapped (old)
, mSrc_file(file)
, sep(mWrapped->getOsSeparator()) {
ai_assert(nullptr != mWrapped);
// Determine base directory
base = src_file;
mBase = mSrc_file;
std::string::size_type ss2;
if (std::string::npos != (ss2 = base.find_last_of("\\/"))) {
base.erase(ss2,base.length()-ss2);
}
else {
base = "";
// return;
if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) {
mBase.erase(ss2,mBase.length()-ss2);
} else {
mBase = "";
}
// make sure the directory is terminated properly
char s;
if (base.length() == 0) {
base = ".";
base += getOsSeparator();
}
else if ((s = *(base.end()-1)) != '\\' && s != '/') {
base += getOsSeparator();
if ( mBase.empty() ) {
mBase = ".";
mBase += getOsSeparator();
} else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
mBase += getOsSeparator();
}
DefaultLogger::get()->info("Import root directory is \'" + base + "\'");
DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'");
}
/** Destructor. */
~FileSystemFilter()
{
// haha
~FileSystemFilter() {
// empty
}
// -------------------------------------------------------------------
/** Tests for the existence of a file at the given path. */
bool Exists( const char* pFile) const
{
bool Exists( const char* pFile) const {
ai_assert( nullptr != mWrapped );
std::string tmp = pFile;
// Currently this IOSystem is also used to open THE ONE FILE.
if (tmp != src_file) {
if (tmp != mSrc_file) {
BuildPath(tmp);
Cleanup(tmp);
}
return wrapped->Exists(tmp);
return mWrapped->Exists(tmp);
}
// -------------------------------------------------------------------
/** Returns the directory separator. */
char getOsSeparator() const
{
char getOsSeparator() const {
return sep;
}
// -------------------------------------------------------------------
/** Open a new file with a given path. */
IOStream* Open( const char* pFile, const char* pMode = "rb")
{
ai_assert(pFile);
ai_assert(pMode);
IOStream* Open( const char* pFile, const char* pMode = "rb") {
ai_assert( nullptr != mWrapped );
if ( nullptr == pFile || nullptr == pMode ) {
return nullptr;
}
ai_assert( nullptr != pFile );
ai_assert( nullptr != pMode );
// First try the unchanged path
IOStream* s = wrapped->Open(pFile,pMode);
IOStream* s = mWrapped->Open(pFile,pMode);
if (!s) {
if (nullptr == s) {
std::string tmp = pFile;
// Try to convert between absolute and relative paths
BuildPath(tmp);
s = wrapped->Open(tmp,pMode);
s = mWrapped->Open(tmp,pMode);
if (!s) {
if (nullptr == s) {
// Finally, look for typical issues with paths
// and try to correct them. This is our last
// resort.
tmp = pFile;
Cleanup(tmp);
BuildPath(tmp);
s = wrapped->Open(tmp,pMode);
s = mWrapped->Open(tmp,pMode);
}
}
@@ -156,27 +156,75 @@ public:
// -------------------------------------------------------------------
/** Closes the given file and releases all resources associated with it. */
void Close( IOStream* pFile)
{
return wrapped->Close(pFile);
void Close( IOStream* pFile) {
ai_assert( nullptr != mWrapped );
return mWrapped->Close(pFile);
}
// -------------------------------------------------------------------
/** Compare two paths */
bool ComparePaths (const char* one, const char* second) const
{
return wrapped->ComparePaths (one,second);
bool ComparePaths (const char* one, const char* second) const {
ai_assert( nullptr != mWrapped );
return mWrapped->ComparePaths (one,second);
}
// -------------------------------------------------------------------
/** Pushes a new directory onto the directory stack. */
bool PushDirectory(const std::string &path ) {
ai_assert( nullptr != mWrapped );
return mWrapped->PushDirectory(path);
}
// -------------------------------------------------------------------
/** Returns the top directory from the stack. */
const std::string &CurrentDirectory() const {
ai_assert( nullptr != mWrapped );
return mWrapped->CurrentDirectory();
}
// -------------------------------------------------------------------
/** Returns the number of directories stored on the stack. */
size_t StackSize() const {
ai_assert( nullptr != mWrapped );
return mWrapped->StackSize();
}
// -------------------------------------------------------------------
/** Pops the top directory from the stack. */
bool PopDirectory() {
ai_assert( nullptr != mWrapped );
return mWrapped->PopDirectory();
}
// -------------------------------------------------------------------
/** Creates an new directory at the given path. */
bool CreateDirectory(const std::string &path) {
ai_assert( nullptr != mWrapped );
return mWrapped->CreateDirectory(path);
}
// -------------------------------------------------------------------
/** Will change the current directory to the given path. */
bool ChangeDirectory(const std::string &path) {
ai_assert( nullptr != mWrapped );
return mWrapped->ChangeDirectory(path);
}
// -------------------------------------------------------------------
/** Delete file. */
bool DeleteFile(const std::string &file) {
ai_assert( nullptr != mWrapped );
return mWrapped->DeleteFile(file);
}
private:
// -------------------------------------------------------------------
/** Build a valid path from a given relative or absolute path.
*/
void BuildPath (std::string& in) const
{
void BuildPath (std::string& in) const {
ai_assert( nullptr != mWrapped );
// if we can already access the file, great.
if (in.length() < 3 || wrapped->Exists(in)) {
if (in.length() < 3 || mWrapped->Exists(in)) {
return;
}
@@ -184,8 +232,8 @@ private:
if (in[1] != ':') {
// append base path and try
const std::string tmp = base + in;
if (wrapped->Exists(tmp)) {
const std::string tmp = mBase + in;
if (mWrapped->Exists(tmp)) {
in = tmp;
return;
}
@@ -207,7 +255,7 @@ private:
std::string::size_type last_dirsep = std::string::npos;
while(true) {
tmp = base;
tmp = mBase;
tmp += sep;
std::string::size_type dirsep = in.rfind('/', last_dirsep);
@@ -223,7 +271,7 @@ private:
last_dirsep = dirsep-1;
tmp += in.substr(dirsep+1, in.length()-pos);
if (wrapped->Exists(tmp)) {
if (mWrapped->Exists(tmp)) {
in = tmp;
return;
}
@@ -236,15 +284,14 @@ private:
// -------------------------------------------------------------------
/** Cleanup the given path
*/
void Cleanup (std::string& in) const
{
char last = 0;
void Cleanup (std::string& in) const {
if(in.empty()) {
return;
}
// Remove a very common issue when we're parsing file names: spaces at the
// beginning of the path.
char last = 0;
std::string::iterator it = in.begin();
while (IsSpaceOrNewLine( *it ))++it;
if (it != in.begin()) {
@@ -274,9 +321,7 @@ private:
it = in.erase(it);
--it;
}
}
else if (*it == '%' && in.end() - it > 2) {
} else if (*it == '%' && in.end() - it > 2) {
// Hex sequence in URIs
if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
*it = HexOctetToDecimal(&*it);
@@ -290,8 +335,8 @@ private:
}
private:
IOSystem* wrapped;
std::string src_file, base;
IOSystem *mWrapped;
std::string mSrc_file, mBase;
char sep;
};

View File

@@ -60,9 +60,9 @@ namespace Assimp {
* @param in Input mesh
* @return Hash.
*/
inline uint64_t GetMeshHash(aiMesh* in)
{
ai_assert(NULL != in);
inline
uint64_t GetMeshHash(aiMesh* in) {
ai_assert(nullptr != in);
// ... get an unique value representing the vertex format of the mesh
const unsigned int fhash = GetMeshVFormatUnique(in);
@@ -78,14 +78,14 @@ inline uint64_t GetMeshHash(aiMesh* in)
/** @brief Perform a component-wise comparison of two arrays
*
* @param first First array
* @param second Second aray
* @param second Second array
* @param size Size of both arrays
* @param e Epsilon
* @return true if the arrays are identical
*/
inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
unsigned int size, float e)
{
inline
bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
unsigned int size, float e) {
for (const aiVector3D* end = first+size; first != end; ++first,++second) {
if ( (*first - *second).SquareLength() >= e)
return false;

View File

@@ -190,7 +190,7 @@ Importer::~Importer()
delete pimpl->mIOHandler;
delete pimpl->mProgressHandler;
// Kill imported scene. Destructors should do that recursivly
// Kill imported scene. Destructor's should do that recursively
delete pimpl->mScene;
// Delete shared post-processing data
@@ -200,18 +200,6 @@ Importer::~Importer()
delete pimpl;
}
// ------------------------------------------------------------------------------------------------
// Copy constructor - copies the config of another Importer, not the scene
Importer::Importer(const Importer &other)
: pimpl(NULL) {
new(this) Importer();
pimpl->mIntProperties = other.pimpl->mIntProperties;
pimpl->mFloatProperties = other.pimpl->mFloatProperties;
pimpl->mStringProperties = other.pimpl->mStringProperties;
pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
}
// ------------------------------------------------------------------------------------------------
// Register a custom post-processing step
aiReturn Importer::RegisterPPStep(BaseProcess* pImp)

View File

@@ -835,7 +835,7 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
{
static const aiVector3D zeroVec(0.f, 0.f, 0.f);
const aiVector3D zeroVec(0.f, 0.f, 0.f);
NextNode();
while(m_currentNodeName == nnKeyFrame)

View File

@@ -731,17 +731,22 @@ enum MeshAttribute {
TexCoord
};
static const std::string PosToken = "position";
static const std::string ColToken = "color";
static const std::string NormalToken = "normal";
static const std::string TexCoordToken = "texcoord";
//------------------------------------------------------------------------------------------------
static MeshAttribute getAttributeByName( const char *attribName ) {
ai_assert( nullptr != attribName );
if ( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) {
if ( 0 == strncmp( PosToken.c_str(), attribName, PosToken.size() ) ) {
return Position;
} else if ( 0 == strncmp( "color", attribName, strlen( "color" ) ) ) {
} else if ( 0 == strncmp( ColToken.c_str(), attribName, ColToken.size() ) ) {
return Color;
} else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) {
} else if( 0 == strncmp( NormalToken.c_str(), attribName, NormalToken.size() ) ) {
return Normal;
} else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) {
} else if( 0 == strncmp( TexCoordToken.c_str(), attribName, TexCoordToken.size() ) ) {
return TexCoord;
}
@@ -1098,14 +1103,12 @@ void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene * /*pS
return;
}
const float floatVal( val->getFloat() );
if ( prop->m_value != nullptr ) {
if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mHorizontalFOV = floatVal;
} else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mClipPlaneNear = floatVal;
} else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mClipPlaneFar = floatVal;
}
if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mHorizontalFOV = floatVal;
} else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 4 ) ) {
m_currentCamera->mClipPlaneNear = floatVal;
} else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
m_currentCamera->mClipPlaneFar = floatVal;
}
}
}

View File

@@ -125,6 +125,9 @@ corresponding preprocessor flag to selectively disable steps.
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
# include "DeboneProcess.h"
#endif
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
# include "ScaleProcess.h"
#endif
namespace Assimp {
@@ -136,7 +139,7 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
// of sequence it is executed. Steps that are added here are not
// validated - as RegisterPPStep() does - all dependencies must be given.
// ----------------------------------------------------------------------------
out.reserve(30);
out.reserve(31);
#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
out.push_back( new MakeLeftHandedProcess());
#endif
@@ -197,7 +200,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
out.push_back( new GenFaceNormalsProcess());
#endif
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
out.push_back( new ScaleProcess());
#endif
// .........................................................................
// DON'T change the order of these five ..
// XXX this is actually a design weakness that dates back to the time

View File

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
#include "ScaleProcess.h"
#include <assimp/scene.h>
@@ -104,3 +106,5 @@ void ScaleProcess::applyScaling( aiNode *currentNode ) {
}
} // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS

View File

@@ -1256,29 +1256,30 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
aiMetadataEntry& out = dest->mValues[i];
out.mType = in.mType;
switch (dest->mValues[i].mType) {
case AI_BOOL:
out.mData = new bool(*static_cast<bool*>(in.mData));
break;
case AI_INT32:
out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
break;
case AI_UINT64:
out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
break;
case AI_FLOAT:
out.mData = new float(*static_cast<float*>(in.mData));
break;
case AI_DOUBLE:
out.mData = new double(*static_cast<double*>(in.mData));
break;
case AI_AISTRING:
out.mData = new aiString(*static_cast<aiString*>(in.mData));
break;
case AI_AIVECTOR3D:
out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
break;
default:
ai_assert(false);
case AI_BOOL:
out.mData = new bool(*static_cast<bool*>(in.mData));
break;
case AI_INT32:
out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
break;
case AI_UINT64:
out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
break;
case AI_FLOAT:
out.mData = new float(*static_cast<float*>(in.mData));
break;
case AI_DOUBLE:
out.mData = new double(*static_cast<double*>(in.mData));
break;
case AI_AISTRING:
out.mData = new aiString(*static_cast<aiString*>(in.mData));
break;
case AI_AIVECTOR3D:
out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
break;
default:
ai_assert(false);
break;
}
}
}

View File

@@ -294,7 +294,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition,
index++;
// Now start iterating from there until the first position lays outside of the distance range.
// Add all positions inside the distance range within the tolerance to the result aray
// Add all positions inside the distance range within the tolerance to the result array
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
while( ToBinary(it->mDistance) < maxDistBinary)
{

View File

@@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "VertexTriangleAdjacency.h"
#include <assimp/mesh.h>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
@@ -60,8 +59,8 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
// compute the number of referenced vertices if it wasn't specified by the caller
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
if (!iNumVertices) {
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
ai_assert( nullptr != pcFace );
ai_assert(3 == pcFace->mNumIndices);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
@@ -69,19 +68,18 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
}
}
this->iNumVertices = iNumVertices;
mNumVertices = iNumVertices;
unsigned int* pi;
// allocate storage
if (bComputeNumTriangles) {
pi = mLiveTriangles = new unsigned int[iNumVertices+1];
memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
mOffsetTable = new unsigned int[iNumVertices+2]+1;
}
else {
} else {
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
mLiveTriangles = NULL; // important, otherwise the d'tor would crash
}
@@ -90,8 +88,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
*piEnd++ = 0u;
// first pass: compute the number of faces referencing each vertex
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
{
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
pi[pcFace->mIndices[0]]++;
pi[pcFace->mIndices[1]]++;
pi[pcFace->mIndices[2]]++;

View File

@@ -60,10 +60,8 @@ namespace Assimp {
* @note Although it is called #VertexTriangleAdjacency, the current version does also
* support arbitrary polygons. */
// --------------------------------------------------------------------------------------------
class ASSIMP_API VertexTriangleAdjacency
{
class ASSIMP_API VertexTriangleAdjacency {
public:
// ----------------------------------------------------------------------------
/** @brief Construction from an existing index buffer
* @param pcFaces Index buffer
@@ -77,39 +75,30 @@ public:
unsigned int iNumVertices = 0,
bool bComputeNumTriangles = true);
// ----------------------------------------------------------------------------
/** @brief Destructor */
~VertexTriangleAdjacency();
public:
// ----------------------------------------------------------------------------
/** @brief Get all triangles adjacent to a vertex
* @param iVertIndex Index of the vertex
* @return A pointer to the adjacency list. */
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const
{
ai_assert(iVertIndex < iNumVertices);
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
ai_assert(iVertIndex < mNumVertices);
return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
}
// ----------------------------------------------------------------------------
/** @brief Get the number of triangles that are referenced by
* a vertex. This function returns a reference that can be modified
* @param iVertIndex Index of the vertex
* @return Number of referenced triangles */
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex)
{
ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles);
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) {
ai_assert( iVertIndex < mNumVertices );
ai_assert( nullptr != mLiveTriangles );
return mLiveTriangles[iVertIndex];
}
public:
//! Offset table
unsigned int* mOffsetTable;
@@ -120,9 +109,9 @@ public:
unsigned int* mLiveTriangles;
//! Debug: Number of referenced vertices
unsigned int iNumVertices;
unsigned int mNumVertices;
};
}
} //! ns Assimp
#endif // !! AI_VTADJACENCY_H_INC

View File

@@ -137,7 +137,7 @@ namespace glTF2
// Vec/matrix types, as raw float arrays
typedef float (vec3)[3];
typedef float (vec4)[4];
typedef float (mat4)[16];
typedef float (mat4)[16];
namespace Util
{
@@ -166,33 +166,8 @@ namespace glTF2
//! Magic number for GLB files
#define AI_GLB_MAGIC_NUMBER "glTF"
#include <assimp/pbrmaterial.h>
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
#ifdef ASSIMP_API
#include "./../include/assimp/Compiler/pushpack1.h"
#endif