- fbx: refactor parsing code, move all parsing stuff to FBXParser.cpp. Parsing errors now carry the prefix "FBX-Parser".

pull/14/head
Alexander Gessler 2012-08-10 23:24:58 +02:00
parent ef0dcaaea2
commit 315285faf0
7 changed files with 411 additions and 385 deletions

View File

@ -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);
} }
} }

View File

@ -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()) {

View File

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

View File

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

View File

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

View File

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

View File

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