- fbx: refactor, move DOM utility functions to separate unit.

This commit is contained in:
Alexander Gessler
2012-08-10 23:02:38 +02:00
parent ffbac847ef
commit ef0dcaaea2
4 changed files with 453 additions and 387 deletions

View File

@@ -57,393 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
using namespace Util;