- fbx: refactor, move DOM utility functions to separate unit.
parent
ffbac847ef
commit
ef0dcaaea2
|
@ -418,6 +418,7 @@ SET(FBX_SRCS
|
||||||
FBXNodeAttribute.cpp
|
FBXNodeAttribute.cpp
|
||||||
FBXDeformer.cpp
|
FBXDeformer.cpp
|
||||||
FBXBinaryTokenizer.cpp
|
FBXBinaryTokenizer.cpp
|
||||||
|
FBXDocumentUtil.cpp
|
||||||
)
|
)
|
||||||
SOURCE_GROUP( FBX FILES ${FBX_SRCS})
|
SOURCE_GROUP( FBX FILES ${FBX_SRCS})
|
||||||
|
|
||||||
|
|
|
@ -57,393 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
namespace Util {
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
|
||||||
void DOMError(const std::string& message, const Token& token)
|
|
||||||
{
|
|
||||||
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void DOMError(const std::string& message, const Element* element /*= NULL*/)
|
|
||||||
{
|
|
||||||
if(element) {
|
|
||||||
DOMError(message,element->KeyToken());
|
|
||||||
}
|
|
||||||
throw DeadlyImportError("FBX-DOM " + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// print warning, do return
|
|
||||||
void DOMWarning(const std::string& message, const Token& token)
|
|
||||||
{
|
|
||||||
if(DefaultLogger::get()) {
|
|
||||||
DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
|
|
||||||
{
|
|
||||||
if(element) {
|
|
||||||
DOMWarning(message,element->KeyToken());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(DefaultLogger::get()) {
|
|
||||||
DefaultLogger::get()->warn("FBX-DOM: " + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// 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
|
|
||||||
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
|
||||||
const std::string& templateName,
|
|
||||||
const Element &element,
|
|
||||||
const Scope& sc)
|
|
||||||
{
|
|
||||||
const Element* const Properties70 = sc["Properties70"];
|
|
||||||
boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
|
|
||||||
static_cast<const PropertyTable*>(NULL));
|
|
||||||
|
|
||||||
if(templateName.length()) {
|
|
||||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
|
||||||
if(it != doc.Templates().end()) {
|
|
||||||
templateProps = (*it).second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Properties70) {
|
|
||||||
DOMWarning("material property table (Properties70) not found",&element);
|
|
||||||
if(templateProps) {
|
|
||||||
return templateProps;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return boost::make_shared<const PropertyTable>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
|
|
||||||
}
|
|
||||||
} // !Util
|
|
||||||
|
|
||||||
using namespace Util;
|
using namespace Util;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,448 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2012, 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 FBXDocumentUtil.cpp
|
||||||
|
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
|
||||||
|
*/
|
||||||
|
#include "AssimpPCH.h"
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "FBXParser.h"
|
||||||
|
#include "FBXDocument.h"
|
||||||
|
#include "FBXUtil.h"
|
||||||
|
#include "FBXDocumentUtil.h"
|
||||||
|
#include "FBXProperties.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
namespace FBX {
|
||||||
|
namespace Util {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
||||||
|
void DOMError(const std::string& message, const Token& token)
|
||||||
|
{
|
||||||
|
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void DOMError(const std::string& message, const Element* element /*= NULL*/)
|
||||||
|
{
|
||||||
|
if(element) {
|
||||||
|
DOMError(message,element->KeyToken());
|
||||||
|
}
|
||||||
|
throw DeadlyImportError("FBX-DOM " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// print warning, do return
|
||||||
|
void DOMWarning(const std::string& message, const Token& token)
|
||||||
|
{
|
||||||
|
if(DefaultLogger::get()) {
|
||||||
|
DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
|
||||||
|
{
|
||||||
|
if(element) {
|
||||||
|
DOMWarning(message,element->KeyToken());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(DefaultLogger::get()) {
|
||||||
|
DefaultLogger::get()->warn("FBX-DOM: " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||||
|
const std::string& templateName,
|
||||||
|
const Element &element,
|
||||||
|
const Scope& sc)
|
||||||
|
{
|
||||||
|
const Element* const Properties70 = sc["Properties70"];
|
||||||
|
boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
|
||||||
|
static_cast<const PropertyTable*>(NULL));
|
||||||
|
|
||||||
|
if(templateName.length()) {
|
||||||
|
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||||
|
if(it != doc.Templates().end()) {
|
||||||
|
templateProps = (*it).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Properties70) {
|
||||||
|
DOMWarning("material property table (Properties70) not found",&element);
|
||||||
|
if(templateProps) {
|
||||||
|
return templateProps;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return boost::make_shared<const PropertyTable>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
|
||||||
|
}
|
||||||
|
} // !Util
|
||||||
|
} // !FBX
|
||||||
|
} // !Assimp
|
||||||
|
|
||||||
|
#endif
|
|
@ -2087,6 +2087,10 @@
|
||||||
RelativePath="..\..\code\FBXDocument.h"
|
RelativePath="..\..\code\FBXDocument.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\FBXDocumentUtil.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\FBXDocumentUtil.h"
|
RelativePath="..\..\code\FBXDocumentUtil.h"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue