pull/1811/head
commit
b0ac2d9daf
17
CREDITS
17
CREDITS
|
@ -157,12 +157,27 @@ Contributed ExportProperties interface
|
|||
Contributed X File exporter
|
||||
Contributed Step (stp) exporter
|
||||
|
||||
- Thomas Iorns (mesilliac)
|
||||
Initial FBX Export support
|
||||
|
||||
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
||||
|
||||
Patreons:
|
||||
|
||||
========
|
||||
Patreons
|
||||
========
|
||||
|
||||
Huge thanks to our Patreons!
|
||||
|
||||
- migenius
|
||||
- Marcus
|
||||
- Cort
|
||||
- elect
|
||||
- Steffen
|
||||
|
||||
|
||||
===================
|
||||
Commercial Sponsors
|
||||
===================
|
||||
|
||||
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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]]++;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -248,9 +248,9 @@ bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationT
|
|||
}
|
||||
}
|
||||
|
||||
bool continuationFound( false ), endOfDataLine( false );
|
||||
bool continuationFound( false );
|
||||
size_t i = 0;
|
||||
while ( !endOfDataLine ) {
|
||||
for( ;; ) {
|
||||
if ( continuationToken == m_cache[ m_cachePos ] ) {
|
||||
continuationFound = true;
|
||||
++m_cachePos;
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
* If this Importer owns a scene it won't be copied.
|
||||
* Call ReadFile() to start the import process.
|
||||
*/
|
||||
Importer(const Importer& other);
|
||||
Importer(const Importer& other)=delete;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Assignment operator has been deleted
|
||||
|
|
|
@ -99,19 +99,19 @@ public:
|
|||
// Seek specific position
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) {
|
||||
if (aiOrigin_SET == pOrigin) {
|
||||
if (pOffset >= length) {
|
||||
if (pOffset > length) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
pos = pOffset;
|
||||
}
|
||||
else if (aiOrigin_END == pOrigin) {
|
||||
if (pOffset >= length) {
|
||||
if (pOffset > length) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
pos = length-pOffset;
|
||||
}
|
||||
else {
|
||||
if (pOffset+pos >= length) {
|
||||
if (pOffset+pos > length) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
pos += pOffset;
|
||||
|
|
|
@ -66,49 +66,50 @@ static const unsigned int BufferSize = 4096;
|
|||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE char_t ToLower( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
char_t ToLower( char_t in ) {
|
||||
return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE char_t ToUpper( char_t in) {
|
||||
AI_FORCE_INLINE
|
||||
char_t ToUpper( char_t in) {
|
||||
return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE bool IsUpper( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
bool IsUpper( char_t in) {
|
||||
return (in >= (char_t)'A' && in <= (char_t)'Z');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE bool IsLower( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
bool IsLower( char_t in) {
|
||||
return (in >= (char_t)'a' && in <= (char_t)'z');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE bool IsSpace( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
bool IsSpace( char_t in) {
|
||||
return (in == (char_t)' ' || in == (char_t)'\t');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE bool IsLineEnd( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
bool IsLineEnd( char_t in) {
|
||||
return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE bool IsSpaceOrNewLine( char_t in)
|
||||
{
|
||||
AI_FORCE_INLINE
|
||||
bool IsSpaceOrNewLine( char_t in) {
|
||||
return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ protected:
|
|||
|
||||
Entry() { /** intentionally not initialized.*/ }
|
||||
Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG)
|
||||
:
|
||||
:
|
||||
mIndex( pIndex),
|
||||
mPosition( pPosition),
|
||||
mSmoothGroups (pSG),
|
||||
|
|
|
@ -47,8 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <vector>
|
||||
#include <assimp/types.h>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** A little helper class to quickly find all vertices in the epsilon environment of a given
|
||||
|
@ -148,17 +147,20 @@ protected:
|
|||
aiVector3D mPlaneNormal;
|
||||
|
||||
/** An entry in a spatially sorted position array. Consists of a vertex index,
|
||||
* its position and its precalculated distance from the reference plane */
|
||||
struct Entry
|
||||
{
|
||||
* its position and its pre-calculated distance from the reference plane */
|
||||
struct Entry {
|
||||
unsigned int mIndex; ///< The vertex referred by this entry
|
||||
aiVector3D mPosition; ///< Position
|
||||
ai_real mDistance; ///< Distance of this vertex to the sorting plane
|
||||
|
||||
Entry() { /** intentionally not initialized.*/ }
|
||||
Entry()
|
||||
: mIndex( 999999999 ), mPosition(), mDistance( 99999. ) {
|
||||
// empty
|
||||
}
|
||||
Entry( unsigned int pIndex, const aiVector3D& pPosition, ai_real pDistance)
|
||||
: mIndex( pIndex), mPosition( pPosition), mDistance( pDistance)
|
||||
{ }
|
||||
: mIndex( pIndex), mPosition( pPosition), mDistance( pDistance) {
|
||||
// empty
|
||||
}
|
||||
|
||||
bool operator < (const Entry& e) const { return mDistance < e.mDistance; }
|
||||
};
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Assimp {
|
|||
// --------------------------------------------------------------------------------------------
|
||||
/** Wrapper class around IOStream to allow for consistent writing of binary data in both
|
||||
* little and big endian format. Don't attempt to instance the template directly. Use
|
||||
* StreamWriterLE to read from a little-endian stream and StreamWriterBE to read from a
|
||||
* StreamWriterLE to write to a little-endian stream and StreamWriterBE to write to a
|
||||
* BE stream. Alternatively, there is StreamWriterAny if the endianness of the output
|
||||
* stream is to be determined at runtime.
|
||||
*/
|
||||
|
@ -108,6 +108,38 @@ public:
|
|||
stream->Flush();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Flush the contents of the internal buffer, and the output IOStream */
|
||||
void Flush()
|
||||
{
|
||||
stream->Write(&buffer[0], 1, buffer.size());
|
||||
stream->Flush();
|
||||
buffer.clear();
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Seek to the given offset / origin in the output IOStream.
|
||||
*
|
||||
* Flushes the internal buffer and the output IOStream prior to seeking. */
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin=aiOrigin_SET)
|
||||
{
|
||||
Flush();
|
||||
return stream->Seek(pOffset, pOrigin);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Tell the current position in the output IOStream.
|
||||
*
|
||||
* First flushes the internal buffer and the output IOStream. */
|
||||
size_t Tell()
|
||||
{
|
||||
Flush();
|
||||
return stream->Tell();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
@ -171,6 +203,32 @@ public:
|
|||
Put(n);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Write an aiString to the stream */
|
||||
void PutString(const aiString& s)
|
||||
{
|
||||
// as Put(T f) below
|
||||
if (cursor + s.length >= buffer.size()) {
|
||||
buffer.resize(cursor + s.length);
|
||||
}
|
||||
void* dest = &buffer[cursor];
|
||||
::memcpy(dest, s.C_Str(), s.length);
|
||||
cursor += s.length;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** Write a std::string to the stream */
|
||||
void PutString(const std::string& s)
|
||||
{
|
||||
// as Put(T f) below
|
||||
if (cursor + s.size() >= buffer.size()) {
|
||||
buffer.resize(cursor + s.size());
|
||||
}
|
||||
void* dest = &buffer[cursor];
|
||||
::memcpy(dest, s.c_str(), s.size());
|
||||
cursor += s.size();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
// ------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __FAST_A_TO_F_H_INCLUDED__
|
||||
#define __FAST_A_TO_F_H_INCLUDED__
|
||||
#ifndef FAST_A_TO_F_H_INCLUDED
|
||||
#define FAST_A_TO_F_H_INCLUDED
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
@ -26,15 +26,13 @@
|
|||
#include "StringComparison.h"
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <stdint.h>
|
||||
#else
|
||||
# include <assimp/Compiler/pstdint.h>
|
||||
#endif
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
const double fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug
|
||||
0.0,
|
||||
|
@ -59,69 +57,65 @@ const double fast_atof_table[16] = { // we write [16] here instead of [] to wo
|
|||
// ------------------------------------------------------------------------------------
|
||||
// Convert a string in decimal format to a number
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline unsigned int strtoul10( const char* in, const char** out=0)
|
||||
{
|
||||
inline
|
||||
unsigned int strtoul10( const char* in, const char** out=0) {
|
||||
unsigned int value = 0;
|
||||
|
||||
bool running = true;
|
||||
while ( running )
|
||||
{
|
||||
if ( *in < '0' || *in > '9' )
|
||||
for ( ;; ) {
|
||||
if ( *in < '0' || *in > '9' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
value = ( value * 10 ) + ( *in - '0' );
|
||||
++in;
|
||||
}
|
||||
if (out)*out = in;
|
||||
if ( out ) {
|
||||
*out = in;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Convert a string in octal format to a number
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline unsigned int strtoul8( const char* in, const char** out=0)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
|
||||
bool running = true;
|
||||
while ( running )
|
||||
{
|
||||
if ( *in < '0' || *in > '7' )
|
||||
inline
|
||||
unsigned int strtoul8( const char* in, const char** out=0) {
|
||||
unsigned int value( 0 );
|
||||
for ( ;; ) {
|
||||
if ( *in < '0' || *in > '7' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
value = ( value << 3 ) + ( *in - '0' );
|
||||
++in;
|
||||
}
|
||||
if (out)*out = in;
|
||||
if ( out ) {
|
||||
*out = in;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Convert a string in hex format to a number
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline unsigned int strtoul16( const char* in, const char** out=0)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
|
||||
bool running = true;
|
||||
while ( running )
|
||||
{
|
||||
if ( *in >= '0' && *in <= '9' )
|
||||
{
|
||||
inline
|
||||
unsigned int strtoul16( const char* in, const char** out=0) {
|
||||
unsigned int value( 0 );
|
||||
for ( ;; ) {
|
||||
if ( *in >= '0' && *in <= '9' ) {
|
||||
value = ( value << 4u ) + ( *in - '0' );
|
||||
}
|
||||
else if (*in >= 'A' && *in <= 'F')
|
||||
{
|
||||
} else if (*in >= 'A' && *in <= 'F') {
|
||||
value = ( value << 4u ) + ( *in - 'A' ) + 10;
|
||||
}
|
||||
else if (*in >= 'a' && *in <= 'f')
|
||||
{
|
||||
} else if (*in >= 'a' && *in <= 'f') {
|
||||
value = ( value << 4u ) + ( *in - 'a' ) + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
else break;
|
||||
++in;
|
||||
}
|
||||
if (out)*out = in;
|
||||
if ( out ) {
|
||||
*out = in;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -129,17 +123,16 @@ inline unsigned int strtoul16( const char* in, const char** out=0)
|
|||
// Convert just one hex digit
|
||||
// Return value is UINT_MAX if the input character is not a hex digit.
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline unsigned int HexDigitToDecimal(char in)
|
||||
{
|
||||
unsigned int out = UINT_MAX;
|
||||
if (in >= '0' && in <= '9')
|
||||
inline
|
||||
unsigned int HexDigitToDecimal(char in) {
|
||||
unsigned int out( UINT_MAX );
|
||||
if ( in >= '0' && in <= '9' ) {
|
||||
out = in - '0';
|
||||
|
||||
else if (in >= 'a' && in <= 'f')
|
||||
} else if ( in >= 'a' && in <= 'f' ) {
|
||||
out = 10u + in - 'a';
|
||||
|
||||
else if (in >= 'A' && in <= 'F')
|
||||
} else if ( in >= 'A' && in <= 'F' ) {
|
||||
out = 10u + in - 'A';
|
||||
}
|
||||
|
||||
// return value is UINT_MAX if the input is not a hex digit
|
||||
return out;
|
||||
|
@ -148,8 +141,8 @@ inline unsigned int HexDigitToDecimal(char in)
|
|||
// ------------------------------------------------------------------------------------
|
||||
// Convert a hex-encoded octet (2 characters, i.e. df or 1a).
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline uint8_t HexOctetToDecimal(const char* in)
|
||||
{
|
||||
inline
|
||||
uint8_t HexOctetToDecimal(const char* in) {
|
||||
return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]);
|
||||
}
|
||||
|
||||
|
@ -157,11 +150,12 @@ inline uint8_t HexOctetToDecimal(const char* in)
|
|||
// ------------------------------------------------------------------------------------
|
||||
// signed variant of strtoul10
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline int strtol10( const char* in, const char** out=0)
|
||||
{
|
||||
inline
|
||||
int strtol10( const char* in, const char** out=0) {
|
||||
bool inv = (*in=='-');
|
||||
if (inv || *in=='+')
|
||||
if ( inv || *in == '+' ) {
|
||||
++in;
|
||||
}
|
||||
|
||||
int value = strtoul10(in,out);
|
||||
if (inv) {
|
||||
|
@ -176,10 +170,9 @@ inline int strtol10( const char* in, const char** out=0)
|
|||
// 0NNN - oct
|
||||
// NNN - dec
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline unsigned int strtoul_cppstyle( const char* in, const char** out=0)
|
||||
{
|
||||
if ('0' == in[0])
|
||||
{
|
||||
inline
|
||||
unsigned int strtoul_cppstyle( const char* in, const char** out=0) {
|
||||
if ('0' == in[0]) {
|
||||
return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out);
|
||||
}
|
||||
return strtoul10(in, out);
|
||||
|
@ -189,19 +182,19 @@ inline unsigned int strtoul_cppstyle( const char* in, const char** out=0)
|
|||
// Special version of the function, providing higher accuracy and safety
|
||||
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0)
|
||||
{
|
||||
inline
|
||||
uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0) {
|
||||
unsigned int cur = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
if ( *in < '0' || *in > '9' )
|
||||
throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
|
||||
if ( *in < '0' || *in > '9' ) {
|
||||
throw std::invalid_argument( std::string( "The string \"" ) + in + "\" cannot be converted into a value." );
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
while ( running )
|
||||
{
|
||||
if ( *in < '0' || *in > '9' )
|
||||
for ( ;; ) {
|
||||
if ( *in < '0' || *in > '9' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
|
||||
|
||||
|
@ -210,7 +203,6 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
|
|||
DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." );
|
||||
return 0;
|
||||
}
|
||||
//throw std::overflow_error();
|
||||
|
||||
value = new_value;
|
||||
|
||||
|
@ -218,21 +210,23 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
|
|||
++cur;
|
||||
|
||||
if (max_inout && *max_inout == cur) {
|
||||
|
||||
if (out) { /* skip to end */
|
||||
while (*in >= '0' && *in <= '9')
|
||||
while ( *in >= '0' && *in <= '9' ) {
|
||||
++in;
|
||||
}
|
||||
*out = in;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
if ( out ) {
|
||||
*out = in;
|
||||
}
|
||||
|
||||
if (max_inout)
|
||||
if ( max_inout ) {
|
||||
*max_inout = cur;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -240,11 +234,12 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
|
|||
// ------------------------------------------------------------------------------------
|
||||
// signed variant of strtoul10_64
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0)
|
||||
{
|
||||
inline
|
||||
int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) {
|
||||
bool inv = (*in == '-');
|
||||
if (inv || *in == '+')
|
||||
if ( inv || *in == '+' ) {
|
||||
++in;
|
||||
}
|
||||
|
||||
int64_t value = strtoul10_64(in, out, max_inout);
|
||||
if (inv) {
|
||||
|
@ -253,7 +248,6 @@ inline int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* m
|
|||
return value;
|
||||
}
|
||||
|
||||
|
||||
// Number of relevant decimals for floating-point parsing.
|
||||
#define AI_FAST_ATOF_RELAVANT_DECIMALS 15
|
||||
|
||||
|
@ -262,9 +256,9 @@ inline int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* m
|
|||
//! about 6 times faster than atof in win32.
|
||||
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
|
||||
// ------------------------------------------------------------------------------------
|
||||
template <typename Real>
|
||||
inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
|
||||
{
|
||||
template<typename Real>
|
||||
inline
|
||||
const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) {
|
||||
Real f = 0;
|
||||
|
||||
bool inv = (*c == '-');
|
||||
|
@ -272,42 +266,36 @@ inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma
|
|||
++c;
|
||||
}
|
||||
|
||||
if ((c[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0)
|
||||
{
|
||||
if ((c[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0) {
|
||||
out = std::numeric_limits<Real>::quiet_NaN();
|
||||
c += 3;
|
||||
return c;
|
||||
}
|
||||
|
||||
if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0)
|
||||
{
|
||||
if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0) {
|
||||
out = std::numeric_limits<Real>::infinity();
|
||||
if (inv) {
|
||||
out = -out;
|
||||
}
|
||||
c += 3;
|
||||
if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inity", 5) == 0)
|
||||
{
|
||||
if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inity", 5) == 0) {
|
||||
c += 5;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(c[0] >= '0' && c[0] <= '9') &&
|
||||
!((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9'))
|
||||
{
|
||||
!((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
|
||||
throw std::invalid_argument("Cannot parse string "
|
||||
"as real number: does not start with digit "
|
||||
"or decimal point followed by digit.");
|
||||
}
|
||||
|
||||
if (*c != '.' && (! check_comma || c[0] != ','))
|
||||
{
|
||||
if (*c != '.' && (! check_comma || c[0] != ',')) {
|
||||
f = static_cast<Real>( strtoul10_64 ( c, &c) );
|
||||
}
|
||||
|
||||
if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')
|
||||
{
|
||||
if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') {
|
||||
++c;
|
||||
|
||||
// NOTE: The original implementation is highly inaccurate here. The precision of a single
|
||||
|
@ -332,7 +320,6 @@ inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma
|
|||
// A major 'E' must be allowed. Necessary for proper reading of some DXF files.
|
||||
// Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
|
||||
if (*c == 'e' || *c == 'E') {
|
||||
|
||||
++c;
|
||||
const bool einv = (*c=='-');
|
||||
if (einv || *c=='+') {
|
||||
|
@ -358,30 +345,31 @@ inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma
|
|||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// The same but more human.
|
||||
inline ai_real fast_atof(const char* c)
|
||||
{
|
||||
inline
|
||||
ai_real fast_atof(const char* c) {
|
||||
ai_real ret(0.0);
|
||||
fast_atoreal_move<ai_real>(c, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline ai_real fast_atof( const char* c, const char** cout)
|
||||
{
|
||||
inline
|
||||
ai_real fast_atof( const char* c, const char** cout) {
|
||||
ai_real ret(0.0);
|
||||
*cout = fast_atoreal_move<ai_real>(c, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline ai_real fast_atof( const char** inout)
|
||||
{
|
||||
inline
|
||||
ai_real fast_atof( const char** inout) {
|
||||
ai_real ret(0.0);
|
||||
*inout = fast_atoreal_move<ai_real>(*inout, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
} //! namespace Assimp
|
||||
|
||||
#endif
|
||||
#endif // FAST_A_TO_F_H_INCLUDED
|
||||
|
|
|
@ -200,8 +200,7 @@ struct aiFace
|
|||
// ---------------------------------------------------------------------------
|
||||
/** @brief A single influence of a bone on a vertex.
|
||||
*/
|
||||
struct aiVertexWeight
|
||||
{
|
||||
struct aiVertexWeight {
|
||||
//! Index of the vertex which is influenced by the bone.
|
||||
unsigned int mVertexId;
|
||||
|
||||
|
@ -214,15 +213,26 @@ struct aiVertexWeight
|
|||
//! Default constructor
|
||||
aiVertexWeight()
|
||||
: mVertexId(0)
|
||||
, mWeight(0.0f)
|
||||
{ }
|
||||
, mWeight(0.0f) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Initialisation from a given index and vertex weight factor
|
||||
//! \param pID ID
|
||||
//! \param pWeight Vertex weight factor
|
||||
aiVertexWeight( unsigned int pID, float pWeight)
|
||||
: mVertexId( pID), mWeight( pWeight)
|
||||
{ /* nothing to do here */ }
|
||||
aiVertexWeight( unsigned int pID, float pWeight )
|
||||
: mVertexId( pID )
|
||||
, mWeight( pWeight ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
bool operator == ( const aiVertexWeight &rhs ) const {
|
||||
return ( mVertexId == rhs.mVertexId && mWeight == rhs.mWeight );
|
||||
}
|
||||
|
||||
bool operator != ( const aiVertexWeight &rhs ) const {
|
||||
return ( *this == rhs );
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
};
|
||||
|
@ -233,31 +243,41 @@ struct aiVertexWeight
|
|||
*
|
||||
* A bone has a name by which it can be found in the frame hierarchy and by
|
||||
* which it can be addressed by animations. In addition it has a number of
|
||||
* influences on vertices.
|
||||
* influences on vertices, and a matrix relating the mesh position to the
|
||||
* position of the bone at the time of binding.
|
||||
*/
|
||||
struct aiBone
|
||||
{
|
||||
struct aiBone {
|
||||
//! The name of the bone.
|
||||
C_STRUCT aiString mName;
|
||||
|
||||
//! The number of vertices affected by this bone
|
||||
//! The number of vertices affected by this bone.
|
||||
//! The maximum value for this member is #AI_MAX_BONE_WEIGHTS.
|
||||
unsigned int mNumWeights;
|
||||
|
||||
//! The vertices affected by this bone
|
||||
//! The influence weights of this bone, by vertex index.
|
||||
C_STRUCT aiVertexWeight* mWeights;
|
||||
|
||||
//! Matrix that transforms from mesh space to bone space in bind pose
|
||||
/** Matrix that transforms from bone space to mesh space in bind pose.
|
||||
*
|
||||
* This matrix describes the position of the mesh
|
||||
* in the local space of this bone when the skeleton was bound.
|
||||
* Thus it can be used directly to determine a desired vertex position,
|
||||
* given the world-space transform of the bone when animated,
|
||||
* and the position of the vertex in mesh space.
|
||||
*
|
||||
* It is sometimes called an inverse-bind matrix,
|
||||
* or inverse bind pose matrix.
|
||||
*/
|
||||
C_STRUCT aiMatrix4x4 mOffsetMatrix;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//! Default constructor
|
||||
aiBone()
|
||||
: mName()
|
||||
, mNumWeights( 0 )
|
||||
, mWeights( NULL )
|
||||
{
|
||||
: mName()
|
||||
, mNumWeights( 0 )
|
||||
, mWeights( nullptr ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
|
@ -298,7 +318,19 @@ struct aiBone
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool operator == ( const aiBone &rhs ) const {
|
||||
if ( mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < mNumWeights; ++i ) {
|
||||
if ( mWeights[ i ] != rhs.mWeights[ i ] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//! Destructor - deletes the array of vertex weights
|
||||
~aiBone()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 pbrmaterial.h
|
||||
* @brief Defines the material system of the library
|
||||
*/
|
||||
#ifndef AI_PBRMATERIAL_H_INC
|
||||
#define AI_PBRMATERIAL_H_INC
|
||||
|
||||
#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(type, N) _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
|
||||
|
||||
#endif //!!AI_PBRMATERIAL_H_INC
|
|
@ -47,9 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "Main.h"
|
||||
|
||||
const char* AICMD_MSG_INFO_HELP_E =
|
||||
"assimp info <file> [-r]\n"
|
||||
"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-r,--raw: No postprocessing, do a raw import\n"
|
||||
"\t-v,--verbose: Print verbose info such as node transform data\n";
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
@ -184,7 +185,7 @@ std::string FindPTypes(const aiScene* scene)
|
|||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline,
|
||||
unsigned int cline, unsigned int cnest=0)
|
||||
unsigned int cline, bool verbose, unsigned int cnest=0)
|
||||
{
|
||||
if (cline++ >= maxline || cnest >= maxnest) {
|
||||
return;
|
||||
|
@ -194,8 +195,29 @@ void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxli
|
|||
printf("-- ");
|
||||
}
|
||||
printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
|
||||
|
||||
if (verbose) {
|
||||
// print the actual transform
|
||||
//printf(",");
|
||||
aiVector3D s, r, t;
|
||||
root->mTransformation.Decompose(s, r, t);
|
||||
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
|
||||
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); }
|
||||
printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
|
||||
}
|
||||
if (r.x || r.y || r.z) {
|
||||
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); }
|
||||
printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
|
||||
}
|
||||
if (t.x || t.y || t.z) {
|
||||
for(unsigned int i = 0; i < cnest; ++i) { printf(" "); }
|
||||
printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
|
||||
}
|
||||
}
|
||||
//printf("\n");
|
||||
|
||||
for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
|
||||
PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,cnest+1);
|
||||
PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1);
|
||||
if(i == root->mNumChildren-1) {
|
||||
for(unsigned int i = 0; i < cnest; ++i) {
|
||||
printf(" ");
|
||||
|
@ -230,10 +252,23 @@ int Assimp_Info (const char* const* params, unsigned int num)
|
|||
|
||||
const std::string in = std::string(params[0]);
|
||||
|
||||
// get -r and -v arguments
|
||||
bool raw = false;
|
||||
bool verbose = 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;
|
||||
}
|
||||
}
|
||||
|
||||
// do maximum post-processing unless -r was specified
|
||||
ImportData import;
|
||||
import.ppFlags = num>1&&(!strcmp(params[1],"--raw")||!strcmp(params[1],"-r")) ? 0
|
||||
: aiProcessPreset_TargetRealtime_MaxQuality;
|
||||
if (!raw) {
|
||||
import.ppFlags = aiProcessPreset_TargetRealtime_MaxQuality;
|
||||
}
|
||||
|
||||
// import the main model
|
||||
const aiScene* scene = ImportModel(import,in);
|
||||
|
@ -346,7 +381,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
|
|||
|
||||
printf("\nNode hierarchy:\n");
|
||||
unsigned int cline=0;
|
||||
PrintHierarchy(scene->mRootNode,20,1000,cline);
|
||||
PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue