- fbx: refactor parsing code, move all parsing stuff to FBXParser.cpp. Parsing errors now carry the prefix "FBX-Parser".
parent
ef0dcaaea2
commit
315285faf0
|
@ -66,8 +66,8 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
|
||||||
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
|
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
|
||||||
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
|
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
|
||||||
|
|
||||||
ReadVectorDataArray(keys, KeyTime);
|
ParseVectorDataArray(keys, KeyTime);
|
||||||
ReadVectorDataArray(values, KeyValueFloat);
|
ParseVectorDataArray(values, KeyValueFloat);
|
||||||
|
|
||||||
if(keys.size() != values.size()) {
|
if(keys.size() != values.size()) {
|
||||||
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
|
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
|
||||||
|
@ -80,12 +80,12 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
|
||||||
|
|
||||||
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
|
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
|
||||||
if(KeyAttrDataFloat) {
|
if(KeyAttrDataFloat) {
|
||||||
ReadVectorDataArray(attributes, *KeyAttrDataFloat);
|
ParseVectorDataArray(attributes, *KeyAttrDataFloat);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
|
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
|
||||||
if(KeyAttrFlags) {
|
if(KeyAttrFlags) {
|
||||||
ReadVectorDataArray(flags, *KeyAttrFlags);
|
ParseVectorDataArray(flags, *KeyAttrFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,8 +97,8 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Indexes) {
|
if(Indexes) {
|
||||||
ReadVectorDataArray(indices,*Indexes);
|
ParseVectorDataArray(indices,*Indexes);
|
||||||
ReadVectorDataArray(weights,*Weights);
|
ParseVectorDataArray(weights,*Weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(indices.size() != weights.size()) {
|
if(indices.size() != weights.size()) {
|
||||||
|
|
|
@ -45,8 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "FBXParser.h"
|
#include "FBXParser.h"
|
||||||
#include "FBXDocument.h"
|
#include "FBXDocument.h"
|
||||||
#include "FBXUtil.h"
|
#include "FBXUtil.h"
|
||||||
|
@ -96,322 +94,6 @@ void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// extract required compound scope
|
|
||||||
const Scope& GetRequiredScope(const Element& el)
|
|
||||||
{
|
|
||||||
const Scope* const s = el.Compound();
|
|
||||||
if(!s) {
|
|
||||||
DOMError("expected compound scope",&el);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// get token at a particular index
|
|
||||||
const Token& GetRequiredToken(const Element& el, unsigned int index)
|
|
||||||
{
|
|
||||||
const TokenList& t = el.Tokens();
|
|
||||||
if(index >= t.size()) {
|
|
||||||
DOMError(Formatter::format( "missing token at index " ) << index,&el);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *t[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// wrapper around ParseTokenAsID() with DOMError handling
|
|
||||||
uint64_t ParseTokenAsID(const Token& t)
|
|
||||||
{
|
|
||||||
const char* err;
|
|
||||||
const uint64_t i = ParseTokenAsID(t,err);
|
|
||||||
if(err) {
|
|
||||||
DOMError(err,t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// wrapper around ParseTokenAsDim() with DOMError handling
|
|
||||||
size_t ParseTokenAsDim(const Token& t)
|
|
||||||
{
|
|
||||||
const char* err;
|
|
||||||
const size_t i = ParseTokenAsDim(t,err);
|
|
||||||
if(err) {
|
|
||||||
DOMError(err,t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// wrapper around ParseTokenAsFloat() with DOMError handling
|
|
||||||
float ParseTokenAsFloat(const Token& t)
|
|
||||||
{
|
|
||||||
const char* err;
|
|
||||||
const float i = ParseTokenAsFloat(t,err);
|
|
||||||
if(err) {
|
|
||||||
DOMError(err,t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// wrapper around ParseTokenAsInt() with DOMError handling
|
|
||||||
int ParseTokenAsInt(const Token& t)
|
|
||||||
{
|
|
||||||
const char* err;
|
|
||||||
const int i = ParseTokenAsInt(t,err);
|
|
||||||
if(err) {
|
|
||||||
DOMError(err,t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// wrapper around ParseTokenAsString() with DOMError handling
|
|
||||||
std::string ParseTokenAsString(const Token& t)
|
|
||||||
{
|
|
||||||
const char* err;
|
|
||||||
const std::string& i = ParseTokenAsString(t,err);
|
|
||||||
if(err) {
|
|
||||||
DOMError(err,t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// extract a required element from a scope, abort if the element cannot be found
|
|
||||||
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
|
|
||||||
{
|
|
||||||
const Element* el = sc[index];
|
|
||||||
if(!el) {
|
|
||||||
DOMError("did not find required element \"" + index + "\"",element);
|
|
||||||
}
|
|
||||||
return *el;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: tacke code duplication in the various ReadVectorDataArray() overloads below.
|
|
||||||
// could use a type traits based solution.
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of float3 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// may throw bad_alloc if the input is rubbish, but this need
|
|
||||||
// not to be prevented - importing would fail but we wouldn't
|
|
||||||
// crash since assimp handles this case properly.
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
if (a.Tokens().size() % 3 != 0) {
|
|
||||||
DOMError("number of floats is not a multiple of three (3)",&el);
|
|
||||||
}
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
aiVector3D v;
|
|
||||||
v.x = ParseTokenAsFloat(**it++);
|
|
||||||
v.y = ParseTokenAsFloat(**it++);
|
|
||||||
v.z = ParseTokenAsFloat(**it++);
|
|
||||||
|
|
||||||
out.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of color4 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray() above
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
if (a.Tokens().size() % 4 != 0) {
|
|
||||||
DOMError("number of floats is not a multiple of four (4)",&el);
|
|
||||||
}
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
aiColor4D v;
|
|
||||||
v.r = ParseTokenAsFloat(**it++);
|
|
||||||
v.g = ParseTokenAsFloat(**it++);
|
|
||||||
v.b = ParseTokenAsFloat(**it++);
|
|
||||||
v.a = ParseTokenAsFloat(**it++);
|
|
||||||
|
|
||||||
out.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of float2 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray() above
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
if (a.Tokens().size() % 2 != 0) {
|
|
||||||
DOMError("number of floats is not a multiple of two (2)",&el);
|
|
||||||
}
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
aiVector2D v;
|
|
||||||
v.x = ParseTokenAsFloat(**it++);
|
|
||||||
v.y = ParseTokenAsFloat(**it++);
|
|
||||||
|
|
||||||
out.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of ints
|
|
||||||
void ReadVectorDataArray(std::vector<int>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray()
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
const int ival = ParseTokenAsInt(**it++);
|
|
||||||
out.push_back(ival);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of floats
|
|
||||||
void ReadVectorDataArray(std::vector<float>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray()
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
const float ival = ParseTokenAsFloat(**it++);
|
|
||||||
out.push_back(ival);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of uints
|
|
||||||
void ReadVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray()
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
const int ival = ParseTokenAsInt(**it++);
|
|
||||||
if(ival < 0) {
|
|
||||||
DOMError("encountered negative integer index");
|
|
||||||
}
|
|
||||||
out.push_back(static_cast<unsigned int>(ival));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// read an array of uint64_ts
|
|
||||||
void ReadVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const TokenList& tok = el.Tokens();
|
|
||||||
const size_t dim = ParseTokenAsDim(*tok[0]);
|
|
||||||
|
|
||||||
// see notes in ReadVectorDataArray()
|
|
||||||
out.reserve(dim);
|
|
||||||
|
|
||||||
const Scope& scope = GetRequiredScope(el);
|
|
||||||
const Element& a = GetRequiredElement(scope,"a",&el);
|
|
||||||
|
|
||||||
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
|
||||||
const uint64_t ival = ParseTokenAsID(**it++);
|
|
||||||
|
|
||||||
out.push_back(ival);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
aiMatrix4x4 ReadMatrix(const Element& element)
|
|
||||||
{
|
|
||||||
std::vector<float> values;
|
|
||||||
ReadVectorDataArray(values,element);
|
|
||||||
|
|
||||||
if(values.size() != 16) {
|
|
||||||
DOMError("expected 16 matrix elements");
|
|
||||||
}
|
|
||||||
|
|
||||||
aiMatrix4x4 result;
|
|
||||||
|
|
||||||
|
|
||||||
result.a1 = values[0];
|
|
||||||
result.a2 = values[1];
|
|
||||||
result.a3 = values[2];
|
|
||||||
result.a4 = values[3];
|
|
||||||
|
|
||||||
result.b1 = values[4];
|
|
||||||
result.b2 = values[5];
|
|
||||||
result.b3 = values[6];
|
|
||||||
result.b4 = values[7];
|
|
||||||
|
|
||||||
result.c1 = values[8];
|
|
||||||
result.c2 = values[9];
|
|
||||||
result.c3 = values[10];
|
|
||||||
result.c4 = values[11];
|
|
||||||
|
|
||||||
result.d1 = values[12];
|
|
||||||
result.d2 = values[13];
|
|
||||||
result.d3 = values[14];
|
|
||||||
result.d4 = values[15];
|
|
||||||
|
|
||||||
result.Transpose();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// fetch a property table and the corresponding property template
|
// fetch a property table and the corresponding property template
|
||||||
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
namespace Util {
|
namespace Util {
|
||||||
|
|
||||||
// does not return
|
|
||||||
|
/* DOM/Parse error reporting - does not return */
|
||||||
void DOMError(const std::string& message, const Token& token);
|
void DOMError(const std::string& message, const Token& token);
|
||||||
void DOMError(const std::string& message, const Element* element = NULL);
|
void DOMError(const std::string& message, const Element* element = NULL);
|
||||||
|
|
||||||
|
@ -56,51 +57,6 @@ void DOMError(const std::string& message, const Element* element = NULL);
|
||||||
void DOMWarning(const std::string& message, const Token& token);
|
void DOMWarning(const std::string& message, const Token& token);
|
||||||
void DOMWarning(const std::string& message, const Element* element = NULL);
|
void DOMWarning(const std::string& message, const Element* element = NULL);
|
||||||
|
|
||||||
// extract required compound scope
|
|
||||||
const Scope& GetRequiredScope(const Element& el);
|
|
||||||
// get token at a particular index
|
|
||||||
const Token& GetRequiredToken(const Element& el, unsigned int index);
|
|
||||||
|
|
||||||
// wrapper around ParseTokenAsID() with DOMError handling
|
|
||||||
uint64_t ParseTokenAsID(const Token& t);
|
|
||||||
// wrapper around ParseTokenAsDim() with DOMError handling
|
|
||||||
size_t ParseTokenAsDim(const Token& t);
|
|
||||||
// wrapper around ParseTokenAsFloat() with DOMError handling
|
|
||||||
float ParseTokenAsFloat(const Token& t);
|
|
||||||
// wrapper around ParseTokenAsInt() with DOMError handling
|
|
||||||
int ParseTokenAsInt(const Token& t);
|
|
||||||
// wrapper around ParseTokenAsString() with DOMError handling
|
|
||||||
std::string ParseTokenAsString(const Token& t);
|
|
||||||
|
|
||||||
|
|
||||||
// extract a required element from a scope, abort if the element cannot be found
|
|
||||||
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
|
|
||||||
|
|
||||||
// read an array of float3 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of color4 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of float2 tuples
|
|
||||||
void ReadVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of ints
|
|
||||||
void ReadVectorDataArray(std::vector<int>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of floats
|
|
||||||
void ReadVectorDataArray(std::vector<float>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of uints
|
|
||||||
void ReadVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
|
||||||
|
|
||||||
// read an array of uint64_t's
|
|
||||||
void ReadVectorDataArray(std::vector<uint64_t>& out, const Element& el);
|
|
||||||
|
|
||||||
|
|
||||||
// read a 4x4 matrix from an array of 16 floats
|
|
||||||
aiMatrix4x4 ReadMatrix(const Element& element);
|
|
||||||
|
|
||||||
|
|
||||||
// fetch a property table and the corresponding property template
|
// fetch a property table and the corresponding property template
|
||||||
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||||
|
@ -109,8 +65,6 @@ boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||||
const Scope& sc);
|
const Scope& sc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline const T* ProcessSimpleConnection(const Connection& con,
|
inline const T* ProcessSimpleConnection(const Connection& con,
|
||||||
|
|
|
@ -99,7 +99,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
const ElementCollection& Layer = sc->GetCollection("Layer");
|
const ElementCollection& Layer = sc->GetCollection("Layer");
|
||||||
|
|
||||||
std::vector<aiVector3D> tempVerts;
|
std::vector<aiVector3D> tempVerts;
|
||||||
ReadVectorDataArray(tempVerts,Vertices);
|
ParseVectorDataArray(tempVerts,Vertices);
|
||||||
|
|
||||||
if(tempVerts.empty()) {
|
if(tempVerts.empty()) {
|
||||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||||
|
@ -107,7 +107,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> tempFaces;
|
std::vector<int> tempFaces;
|
||||||
ReadVectorDataArray(tempFaces,PolygonVertexIndex);
|
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
|
||||||
|
|
||||||
if(tempFaces.empty()) {
|
if(tempFaces.empty()) {
|
||||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||||
|
@ -346,7 +346,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
const std::vector<unsigned int>& mappings)
|
const std::vector<unsigned int>& mappings)
|
||||||
{
|
{
|
||||||
std::vector<T> tempUV;
|
std::vector<T> tempUV;
|
||||||
ReadVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
|
ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
|
||||||
|
|
||||||
// handle permutations of Mapping and Reference type - it would be nice to
|
// handle permutations of Mapping and Reference type - it would be nice to
|
||||||
// deal with this more elegantly and with less redundancy, but right
|
// deal with this more elegantly and with less redundancy, but right
|
||||||
|
@ -365,7 +365,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
data_out.resize(vertex_count);
|
data_out.resize(vertex_count);
|
||||||
|
|
||||||
std::vector<int> uvIndices;
|
std::vector<int> uvIndices;
|
||||||
ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||||
|
|
||||||
for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
|
for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||||
data_out.resize(vertex_count);
|
data_out.resize(vertex_count);
|
||||||
|
|
||||||
std::vector<int> uvIndices;
|
std::vector<int> uvIndices;
|
||||||
ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||||
|
|
||||||
if (uvIndices.size() != vertex_count) {
|
if (uvIndices.size() != vertex_count) {
|
||||||
FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
|
FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
|
||||||
|
@ -500,7 +500,7 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
||||||
// materials are handled separately. First of all, they are assigned per-face
|
// materials are handled separately. First of all, they are assigned per-face
|
||||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||||
// has a slightly different meaning for materials.
|
// has a slightly different meaning for materials.
|
||||||
ReadVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||||
|
|
||||||
if (MappingInformationType == "AllSame") {
|
if (MappingInformationType == "AllSame") {
|
||||||
// easy - same material for all faces
|
// easy - same material for all faces
|
||||||
|
|
|
@ -57,12 +57,53 @@ using namespace Assimp::FBX;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// signal parsing error, this is always unrecoverable. Throws DeadlyImportError.
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ParseError(const std::string& message, TokenPtr token)
|
// signal parse error, this is always unrecoverable. Throws DeadlyImportError.
|
||||||
{
|
void ParseError(const std::string& message, const Token& token)
|
||||||
throw DeadlyImportError(token ? Util::AddTokenText("FBX-Parse",message,token) : ("FBX-Parse " + message));
|
{
|
||||||
}
|
throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ParseError(const std::string& message, const Element* element = NULL)
|
||||||
|
{
|
||||||
|
if(element) {
|
||||||
|
ParseError(message,element->KeyToken());
|
||||||
|
}
|
||||||
|
throw DeadlyImportError("FBX-Parser " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// print warning, do return
|
||||||
|
void ParseWarning(const std::string& message, const Token& token)
|
||||||
|
{
|
||||||
|
if(DefaultLogger::get()) {
|
||||||
|
DefaultLogger::get()->warn(Util::AddTokenText("FBX-Parser",message,&token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ParseWarning(const std::string& message, const Element* element = NULL)
|
||||||
|
{
|
||||||
|
if(element) {
|
||||||
|
ParseWarning(message,element->KeyToken());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(DefaultLogger::get()) {
|
||||||
|
DefaultLogger::get()->warn("FBX-Parser: " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ParseError(const std::string& message, TokenPtr token)
|
||||||
|
{
|
||||||
|
if(token) {
|
||||||
|
ParseError(message, *token);
|
||||||
|
}
|
||||||
|
ParseError(message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +171,7 @@ Scope::Scope(Parser& parser,bool topLevel)
|
||||||
|
|
||||||
TokenPtr n = parser.AdvanceToNextToken();
|
TokenPtr n = parser.AdvanceToNextToken();
|
||||||
if(n == NULL) {
|
if(n == NULL) {
|
||||||
ParseError("unexpected end of file",NULL);
|
ParseError("unexpected end of file");
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: empty scopes are allowed
|
// note: empty scopes are allowed
|
||||||
|
@ -419,6 +460,323 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out)
|
||||||
return std::string(s+1,length-2);
|
return std::string(s+1,length-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of float3 tuples
|
||||||
|
void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// may throw bad_alloc if the input is rubbish, but this need
|
||||||
|
// not to be prevented - importing would fail but we wouldn't
|
||||||
|
// crash since assimp handles this case properly.
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
if (a.Tokens().size() % 3 != 0) {
|
||||||
|
ParseError("number of floats is not a multiple of three (3)",&el);
|
||||||
|
}
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
aiVector3D v;
|
||||||
|
v.x = ParseTokenAsFloat(**it++);
|
||||||
|
v.y = ParseTokenAsFloat(**it++);
|
||||||
|
v.z = ParseTokenAsFloat(**it++);
|
||||||
|
|
||||||
|
out.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of color4 tuples
|
||||||
|
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray() above
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
if (a.Tokens().size() % 4 != 0) {
|
||||||
|
ParseError("number of floats is not a multiple of four (4)",&el);
|
||||||
|
}
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
aiColor4D v;
|
||||||
|
v.r = ParseTokenAsFloat(**it++);
|
||||||
|
v.g = ParseTokenAsFloat(**it++);
|
||||||
|
v.b = ParseTokenAsFloat(**it++);
|
||||||
|
v.a = ParseTokenAsFloat(**it++);
|
||||||
|
|
||||||
|
out.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of float2 tuples
|
||||||
|
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray() above
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
if (a.Tokens().size() % 2 != 0) {
|
||||||
|
ParseError("number of floats is not a multiple of two (2)",&el);
|
||||||
|
}
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
aiVector2D v;
|
||||||
|
v.x = ParseTokenAsFloat(**it++);
|
||||||
|
v.y = ParseTokenAsFloat(**it++);
|
||||||
|
|
||||||
|
out.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of ints
|
||||||
|
void ParseVectorDataArray(std::vector<int>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray()
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
const int ival = ParseTokenAsInt(**it++);
|
||||||
|
out.push_back(ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of floats
|
||||||
|
void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray()
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
const float ival = ParseTokenAsFloat(**it++);
|
||||||
|
out.push_back(ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of uints
|
||||||
|
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray()
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
const int ival = ParseTokenAsInt(**it++);
|
||||||
|
if(ival < 0) {
|
||||||
|
ParseError("encountered negative integer index");
|
||||||
|
}
|
||||||
|
out.push_back(static_cast<unsigned int>(ival));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// read an array of uint64_ts
|
||||||
|
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const TokenList& tok = el.Tokens();
|
||||||
|
const size_t dim = ParseTokenAsDim(*tok[0]);
|
||||||
|
|
||||||
|
// see notes in ParseVectorDataArray()
|
||||||
|
out.reserve(dim);
|
||||||
|
|
||||||
|
const Scope& scope = GetRequiredScope(el);
|
||||||
|
const Element& a = GetRequiredElement(scope,"a",&el);
|
||||||
|
|
||||||
|
for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
|
||||||
|
const uint64_t ival = ParseTokenAsID(**it++);
|
||||||
|
|
||||||
|
out.push_back(ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
aiMatrix4x4 ReadMatrix(const Element& element)
|
||||||
|
{
|
||||||
|
std::vector<float> values;
|
||||||
|
ParseVectorDataArray(values,element);
|
||||||
|
|
||||||
|
if(values.size() != 16) {
|
||||||
|
ParseError("expected 16 matrix elements");
|
||||||
|
}
|
||||||
|
|
||||||
|
aiMatrix4x4 result;
|
||||||
|
|
||||||
|
|
||||||
|
result.a1 = values[0];
|
||||||
|
result.a2 = values[1];
|
||||||
|
result.a3 = values[2];
|
||||||
|
result.a4 = values[3];
|
||||||
|
|
||||||
|
result.b1 = values[4];
|
||||||
|
result.b2 = values[5];
|
||||||
|
result.b3 = values[6];
|
||||||
|
result.b4 = values[7];
|
||||||
|
|
||||||
|
result.c1 = values[8];
|
||||||
|
result.c2 = values[9];
|
||||||
|
result.c3 = values[10];
|
||||||
|
result.c4 = values[11];
|
||||||
|
|
||||||
|
result.d1 = values[12];
|
||||||
|
result.d2 = values[13];
|
||||||
|
result.d3 = values[14];
|
||||||
|
result.d4 = values[15];
|
||||||
|
|
||||||
|
result.Transpose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsString() with ParseError handling
|
||||||
|
std::string ParseTokenAsString(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const std::string& i = ParseTokenAsString(t,err);
|
||||||
|
if(err) {
|
||||||
|
ParseError(err,t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// extract a required element from a scope, abort if the element cannot be found
|
||||||
|
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
|
||||||
|
{
|
||||||
|
const Element* el = sc[index];
|
||||||
|
if(!el) {
|
||||||
|
ParseError("did not find required element \"" + index + "\"",element);
|
||||||
|
}
|
||||||
|
return *el;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// extract required compound scope
|
||||||
|
const Scope& GetRequiredScope(const Element& el)
|
||||||
|
{
|
||||||
|
const Scope* const s = el.Compound();
|
||||||
|
if(!s) {
|
||||||
|
ParseError("expected compound scope",&el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// get token at a particular index
|
||||||
|
const Token& GetRequiredToken(const Element& el, unsigned int index)
|
||||||
|
{
|
||||||
|
const TokenList& t = el.Tokens();
|
||||||
|
if(index >= t.size()) {
|
||||||
|
ParseError(Formatter::format( "missing token at index " ) << index,&el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *t[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsID() with ParseError handling
|
||||||
|
uint64_t ParseTokenAsID(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const uint64_t i = ParseTokenAsID(t,err);
|
||||||
|
if(err) {
|
||||||
|
ParseError(err,t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsDim() with ParseError handling
|
||||||
|
size_t ParseTokenAsDim(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const size_t i = ParseTokenAsDim(t,err);
|
||||||
|
if(err) {
|
||||||
|
ParseError(err,t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsFloat() with ParseError handling
|
||||||
|
float ParseTokenAsFloat(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const float i = ParseTokenAsFloat(t,err);
|
||||||
|
if(err) {
|
||||||
|
ParseError(err,t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// wrapper around ParseTokenAsInt() with ParseError handling
|
||||||
|
int ParseTokenAsInt(const Token& t)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
const int i = ParseTokenAsInt(t,err);
|
||||||
|
if(err) {
|
||||||
|
ParseError(err,t);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // !FBX
|
} // !FBX
|
||||||
} // !Assimp
|
} // !Assimp
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,38 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out);
|
||||||
int ParseTokenAsInt(const Token& t, const char*& err_out);
|
int ParseTokenAsInt(const Token& t, const char*& err_out);
|
||||||
std::string ParseTokenAsString(const Token& t, const char*& err_out);
|
std::string ParseTokenAsString(const Token& t, const char*& err_out);
|
||||||
|
|
||||||
|
|
||||||
|
/* wrapper around ParseTokenAsXXX() with DOMError handling */
|
||||||
|
uint64_t ParseTokenAsID(const Token& t);
|
||||||
|
size_t ParseTokenAsDim(const Token& t);
|
||||||
|
float ParseTokenAsFloat(const Token& t);
|
||||||
|
int ParseTokenAsInt(const Token& t);
|
||||||
|
std::string ParseTokenAsString(const Token& t);
|
||||||
|
|
||||||
|
/* read data arrays */
|
||||||
|
void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<int>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<float>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
||||||
|
void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// extract a required element from a scope, abort if the element cannot be found
|
||||||
|
const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
|
||||||
|
|
||||||
|
// extract required compound scope
|
||||||
|
const Scope& GetRequiredScope(const Element& el);
|
||||||
|
// get token at a particular index
|
||||||
|
const Token& GetRequiredToken(const Element& el, unsigned int index);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// read a 4x4 matrix from an array of 16 floats
|
||||||
|
aiMatrix4x4 ReadMatrix(const Element& element);
|
||||||
|
|
||||||
} // ! FBX
|
} // ! FBX
|
||||||
} // ! Assimp
|
} // ! Assimp
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue