LumixEngine/src/renderer/editor/ofbx.cpp

3189 lines
77 KiB
C++
Raw Normal View History

2017-07-05 18:55:59 +02:00
#include "ofbx.h"
#include "miniz.h"
#include <cassert>
2019-07-29 18:03:08 +02:00
#include <math.h>
2017-08-30 00:08:16 +02:00
#include <ctype.h>
2017-07-05 18:55:59 +02:00
#include <memory>
2019-06-26 21:21:48 +02:00
#include <numeric>
2019-06-02 16:12:47 +02:00
#include <string>
2017-07-05 18:55:59 +02:00
#include <unordered_map>
#include <vector>
namespace ofbx
{
2017-07-10 20:05:47 +02:00
2017-07-07 18:10:32 +02:00
struct Error
{
2017-11-22 14:45:00 +01:00
Error() {}
2017-07-07 18:10:32 +02:00
Error(const char* msg) { s_message = msg; }
static const char* s_message;
};
const char* Error::s_message = "";
2017-07-10 20:05:47 +02:00
template <typename T> struct OptionalError
2017-07-07 18:10:32 +02:00
{
OptionalError(Error error)
: is_error(true)
2017-07-10 20:05:47 +02:00
{
}
2017-07-07 18:10:32 +02:00
OptionalError(T _value)
: value(_value)
, is_error(false)
{
}
2017-07-07 18:22:17 +02:00
T getValue() const
{
2017-07-10 20:05:47 +02:00
#ifdef _DEBUG
assert(error_checked);
#endif
2017-07-07 18:22:17 +02:00
return value;
}
bool isError()
{
2017-07-10 20:05:47 +02:00
#ifdef _DEBUG
error_checked = true;
#endif
2017-07-07 18:22:17 +02:00
return is_error;
}
2017-07-10 20:05:47 +02:00
2017-07-07 18:22:17 +02:00
private:
2017-07-07 18:10:32 +02:00
T value;
bool is_error;
2017-07-10 20:05:47 +02:00
#ifdef _DEBUG
bool error_checked = false;
#endif
2017-07-07 18:10:32 +02:00
};
2017-07-05 18:55:59 +02:00
#pragma pack(1)
struct Header
{
u8 magic[21];
u8 reserved[2];
u32 version;
};
#pragma pack()
struct Cursor
{
const u8* current;
const u8* begin;
const u8* end;
};
static void setTranslation(const Vec3& t, Matrix* mtx)
{
mtx->m[12] = t.x;
mtx->m[13] = t.y;
mtx->m[14] = t.z;
}
static Vec3 operator-(const Vec3& v)
{
2017-07-05 19:43:01 +02:00
return {-v.x, -v.y, -v.z};
2017-07-05 18:55:59 +02:00
}
static Matrix operator*(const Matrix& lhs, const Matrix& rhs)
{
Matrix res;
for (int j = 0; j < 4; ++j)
{
for (int i = 0; i < 4; ++i)
{
double tmp = 0;
for (int k = 0; k < 4; ++k)
{
tmp += lhs.m[i + k * 4] * rhs.m[k + j * 4];
}
res.m[i + j * 4] = tmp;
}
}
return res;
}
static Matrix makeIdentity()
{
2017-07-05 19:43:01 +02:00
return {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
2017-07-05 18:55:59 +02:00
}
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
static Matrix rotationX(double angle)
{
Matrix m = makeIdentity();
double c = cos(angle);
double s = sin(angle);
m.m[5] = m.m[10] = c;
m.m[9] = -s;
m.m[6] = s;
return m;
}
static Matrix rotationY(double angle)
{
Matrix m = makeIdentity();
double c = cos(angle);
double s = sin(angle);
m.m[0] = m.m[10] = c;
m.m[8] = s;
m.m[2] = -s;
return m;
}
static Matrix rotationZ(double angle)
{
Matrix m = makeIdentity();
double c = cos(angle);
double s = sin(angle);
m.m[0] = m.m[5] = c;
m.m[4] = -s;
m.m[1] = s;
return m;
}
static Matrix getRotationMatrix(const Vec3& euler, RotationOrder order)
2017-07-05 18:55:59 +02:00
{
const double TO_RAD = 3.1415926535897932384626433832795028 / 180.0;
Matrix rx = rotationX(euler.x * TO_RAD);
Matrix ry = rotationY(euler.y * TO_RAD);
Matrix rz = rotationZ(euler.z * TO_RAD);
2019-06-02 16:12:47 +02:00
switch (order)
{
default:
2019-06-02 16:12:47 +02:00
case RotationOrder::EULER_XYZ: return rz * ry * rx;
case RotationOrder::EULER_XZY: return ry * rz * rx;
case RotationOrder::EULER_YXZ: return rz * rx * ry;
case RotationOrder::EULER_YZX: return rx * rz * ry;
case RotationOrder::EULER_ZXY: return ry * rx * rz;
case RotationOrder::EULER_ZYX: return rx * ry * rz;
2019-12-14 19:27:26 +01:00
case RotationOrder::SPHERIC_XYZ: assert(false); Error::s_message = "Unsupported rotation order."; return rx * ry * rz;
}
2017-07-05 18:55:59 +02:00
}
2019-09-11 18:23:26 +02:00
double fbxTimeToSeconds(i64 value)
2017-07-05 18:55:59 +02:00
{
return double(value) / 46186158000L;
}
2019-09-11 18:23:26 +02:00
i64 secondsToFbxTime(double value)
2017-07-09 11:56:31 +02:00
{
return i64(value * 46186158000L);
2017-07-09 11:56:31 +02:00
}
2017-07-05 19:43:01 +02:00
static Vec3 operator*(const Vec3& v, float f)
2017-07-05 18:55:59 +02:00
{
2017-07-05 19:43:01 +02:00
return {v.x * f, v.y * f, v.z * f};
2017-07-05 18:55:59 +02:00
}
2017-07-05 19:43:01 +02:00
static Vec3 operator+(const Vec3& a, const Vec3& b)
2017-07-05 18:55:59 +02:00
{
return {a.x + b.x, a.y + b.y, a.z + b.z};
}
2017-07-05 19:43:01 +02:00
template <int SIZE> static bool copyString(char (&destination)[SIZE], const char* source)
{
const char* src = source;
char* dest = destination;
int length = SIZE;
if (!src) return false;
while (*src && length > 1)
{
*dest = *src;
--length;
++dest;
++src;
}
*dest = 0;
return *src == '\0';
}
2018-02-04 11:28:25 +01:00
u64 DataView::toU64() const
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
if (is_binary)
{
assert(end - begin == sizeof(u64));
return *(u64*)begin;
}
static_assert(sizeof(unsigned long long) >= sizeof(u64), "can't use strtoull");
return strtoull((const char*)begin, nullptr, 10);
}
i64 DataView::toI64() const
{
if (is_binary)
{
assert(end - begin == sizeof(i64));
return *(i64*)begin;
}
static_assert(sizeof(long long) >= sizeof(i64), "can't use atoll");
2018-02-04 11:28:25 +01:00
return atoll((const char*)begin);
2017-08-30 00:08:16 +02:00
}
int DataView::toInt() const
{
if (is_binary)
{
assert(end - begin == sizeof(int));
return *(int*)begin;
}
return atoi((const char*)begin);
}
u32 DataView::toU32() const
{
if (is_binary)
{
assert(end - begin == sizeof(u32));
return *(u32*)begin;
}
return (u32)atoll((const char*)begin);
2017-07-05 18:55:59 +02:00
}
double DataView::toDouble() const
{
2017-08-30 00:08:16 +02:00
if (is_binary)
{
assert(end - begin == sizeof(double));
return *(double*)begin;
}
return atof((const char*)begin);
}
float DataView::toFloat() const
{
if (is_binary)
{
assert(end - begin == sizeof(float));
return *(float*)begin;
}
return (float)atof((const char*)begin);
2017-07-05 18:55:59 +02:00
}
bool DataView::operator==(const char* rhs) const
{
const char* c = rhs;
const char* c2 = (const char*)begin;
while (*c && c2 != (const char*)end)
{
2019-11-23 23:37:49 +01:00
if (*c != *c2) return false;
2017-07-05 18:55:59 +02:00
++c;
++c2;
}
return c2 == (const char*)end && *c == '\0';
}
struct Property;
2017-10-29 22:23:51 +01:00
template <typename T> static bool parseArrayRaw(const Property& property, T* out, int max_size);
template <typename T> static bool parseBinaryArray(const Property& property, std::vector<T>* out);
2017-07-05 18:55:59 +02:00
struct Property : IElementProperty
{
Type getType() const override { return (Type)type; }
IElementProperty* getNext() const override { return next; }
DataView getValue() const override { return value; }
2017-07-05 19:43:01 +02:00
int getCount() const override
2017-07-05 18:55:59 +02:00
{
assert(type == ARRAY_DOUBLE || type == ARRAY_INT || type == ARRAY_FLOAT || type == ARRAY_LONG);
2017-08-30 00:08:16 +02:00
if (value.is_binary)
{
return int(*(u32*)value.begin);
}
return count;
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
bool getValues(double* values, int max_size) const override { return parseArrayRaw(*this, values, max_size); }
2017-07-05 18:55:59 +02:00
2017-08-30 00:08:16 +02:00
bool getValues(float* values, int max_size) const override { return parseArrayRaw(*this, values, max_size); }
2017-07-05 18:55:59 +02:00
2017-08-30 00:08:16 +02:00
bool getValues(u64* values, int max_size) const override { return parseArrayRaw(*this, values, max_size); }
2019-06-02 16:12:47 +02:00
bool getValues(i64* values, int max_size) const override { return parseArrayRaw(*this, values, max_size); }
2017-07-05 18:55:59 +02:00
2017-08-30 00:08:16 +02:00
bool getValues(int* values, int max_size) const override { return parseArrayRaw(*this, values, max_size); }
2017-07-05 18:55:59 +02:00
2019-11-23 23:37:49 +01:00
int count = 0;
u8 type = INTEGER;
2017-07-05 18:55:59 +02:00
DataView value;
Property* next = nullptr;
};
struct Element : IElement
{
IElement* getFirstChild() const override { return child; }
IElement* getSibling() const override { return sibling; }
DataView getID() const override { return id; }
IElementProperty* getFirstProperty() const override { return first_property; }
IElementProperty* getProperty(int idx) const
{
IElementProperty* prop = first_property;
for (int i = 0; i < idx; ++i)
{
if (prop == nullptr) return nullptr;
prop = prop->getNext();
}
2017-07-05 19:43:01 +02:00
return prop;
2017-07-05 18:55:59 +02:00
}
DataView id;
Element* child = nullptr;
Element* sibling = nullptr;
Property* first_property = nullptr;
};
2017-07-10 20:05:47 +02:00
static const Element* findChild(const Element& element, const char* id)
{
Element* const* iter = &element.child;
while (*iter)
{
if ((*iter)->id == id) return *iter;
iter = &(*iter)->sibling;
}
return nullptr;
}
static IElement* resolveProperty(const Object& obj, const char* name)
{
const Element* props = findChild((const Element&)obj.element, "Properties70");
if (!props) return nullptr;
Element* prop = props->child;
while (prop)
{
if (prop->first_property && prop->first_property->value == name)
{
return prop;
}
prop = prop->sibling;
}
return nullptr;
}
static int resolveEnumProperty(const Object& object, const char* name, int default_value)
{
Element* element = (Element*)resolveProperty(object, name);
if (!element) return default_value;
Property* x = (Property*)element->getProperty(4);
if (!x) return default_value;
return x->value.toInt();
}
2017-07-05 19:43:01 +02:00
static Vec3 resolveVec3Property(const Object& object, const char* name, const Vec3& default_value)
2017-07-05 18:55:59 +02:00
{
2017-07-10 20:05:47 +02:00
Element* element = (Element*)resolveProperty(object, name);
2017-07-05 18:55:59 +02:00
if (!element) return default_value;
Property* x = (Property*)element->getProperty(4);
if (!x || !x->next || !x->next->next) return default_value;
return {x->value.toDouble(), x->next->value.toDouble(), x->next->next->value.toDouble()};
}
Object::Object(const Scene& _scene, const IElement& _element)
: scene(_scene)
, element(_element)
, is_node(false)
2017-07-10 19:49:03 +02:00
, node_attribute(nullptr)
2017-07-05 18:55:59 +02:00
{
auto& e = (Element&)_element;
if (e.first_property && e.first_property->next)
{
e.first_property->next->value.toString(name);
}
else
{
name[0] = '\0';
}
}
2017-07-11 18:57:34 +02:00
static bool decompress(const u8* in, size_t in_size, u8* out, size_t out_size)
2017-07-05 18:55:59 +02:00
{
mz_stream stream = {};
mz_inflateInit(&stream);
stream.avail_in = (int)in_size;
stream.next_in = in;
stream.avail_out = (int)out_size;
stream.next_out = out;
2017-11-28 19:37:15 +01:00
int status = mz_inflate(&stream, Z_SYNC_FLUSH);
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
if (status != Z_STREAM_END) return false;
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
return mz_inflateEnd(&stream) == Z_OK;
2017-07-05 18:55:59 +02:00
}
2017-07-10 20:05:47 +02:00
template <typename T> static OptionalError<T> read(Cursor* cursor)
2017-07-05 18:55:59 +02:00
{
2017-07-07 18:10:32 +02:00
if (cursor->current + sizeof(T) > cursor->end) return Error("Reading past the end");
T value = *(const T*)cursor->current;
cursor->current += sizeof(T);
return value;
2017-07-05 18:55:59 +02:00
}
2017-07-07 18:10:32 +02:00
static OptionalError<DataView> readShortString(Cursor* cursor)
2017-07-05 18:55:59 +02:00
{
DataView value;
2017-07-07 18:10:32 +02:00
OptionalError<u8> length = read<u8>(cursor);
2017-07-07 18:22:17 +02:00
if (length.isError()) return Error();
2017-07-05 18:55:59 +02:00
2017-07-07 18:22:17 +02:00
if (cursor->current + length.getValue() > cursor->end) return Error("Reading past the end");
2017-07-05 18:55:59 +02:00
value.begin = cursor->current;
2017-07-07 18:22:17 +02:00
cursor->current += length.getValue();
2017-07-05 18:55:59 +02:00
value.end = cursor->current;
return value;
}
2017-07-07 18:10:32 +02:00
static OptionalError<DataView> readLongString(Cursor* cursor)
2017-07-05 18:55:59 +02:00
{
DataView value;
2017-07-07 18:10:32 +02:00
OptionalError<u32> length = read<u32>(cursor);
2017-07-07 18:22:17 +02:00
if (length.isError()) return Error();
2017-07-05 18:55:59 +02:00
2017-07-07 18:22:17 +02:00
if (cursor->current + length.getValue() > cursor->end) return Error("Reading past the end");
2017-07-05 18:55:59 +02:00
value.begin = cursor->current;
2017-07-07 18:22:17 +02:00
cursor->current += length.getValue();
2017-07-05 18:55:59 +02:00
value.end = cursor->current;
return value;
}
2017-07-07 18:10:32 +02:00
static OptionalError<Property*> readProperty(Cursor* cursor)
2017-07-05 18:55:59 +02:00
{
2017-07-07 18:45:46 +02:00
if (cursor->current == cursor->end) return Error("Reading past the end");
2018-10-16 21:28:03 +02:00
std::unique_ptr<Property> prop(new Property());
2017-07-05 18:55:59 +02:00
prop->next = nullptr;
prop->type = *cursor->current;
++cursor->current;
prop->value.begin = cursor->current;
switch (prop->type)
{
2017-07-07 18:45:46 +02:00
case 'S':
2017-07-07 18:10:32 +02:00
{
OptionalError<DataView> val = readLongString(cursor);
2017-07-07 18:45:46 +02:00
if (val.isError()) return Error();
2017-07-07 18:22:17 +02:00
prop->value = val.getValue();
2017-07-07 18:10:32 +02:00
break;
}
2017-07-05 18:55:59 +02:00
case 'Y': cursor->current += 2; break;
case 'C': cursor->current += 1; break;
case 'I': cursor->current += 4; break;
case 'F': cursor->current += 4; break;
case 'D': cursor->current += 8; break;
case 'L': cursor->current += 8; break;
case 'R':
{
2017-07-07 18:10:32 +02:00
OptionalError<u32> len = read<u32>(cursor);
2017-07-07 18:45:46 +02:00
if (len.isError()) return Error();
if (cursor->current + len.getValue() > cursor->end) return Error("Reading past the end");
2017-07-07 18:22:17 +02:00
cursor->current += len.getValue();
2017-07-05 18:55:59 +02:00
break;
}
case 'b':
case 'f':
case 'd':
case 'l':
case 'i':
{
2017-07-07 18:10:32 +02:00
OptionalError<u32> length = read<u32>(cursor);
OptionalError<u32> encoding = read<u32>(cursor);
OptionalError<u32> comp_len = read<u32>(cursor);
2019-06-02 16:12:47 +02:00
if (length.isError() | encoding.isError() | comp_len.isError()) return Error();
2017-07-07 18:45:46 +02:00
if (cursor->current + comp_len.getValue() > cursor->end) return Error("Reading past the end");
2017-07-07 18:22:17 +02:00
cursor->current += comp_len.getValue();
2017-07-05 18:55:59 +02:00
break;
}
2017-07-10 20:05:47 +02:00
default: return Error("Unknown property type");
2017-07-05 18:55:59 +02:00
}
prop->value.end = cursor->current;
2017-07-07 18:45:46 +02:00
return prop.release();
2017-07-05 18:55:59 +02:00
}
2017-07-11 23:40:48 +02:00
static void deleteElement(Element* el)
{
if (!el) return;
Element* iter = el;
2018-09-03 16:04:47 +02:00
// do not use recursion to delete siblings to avoid stack overflow
2017-07-11 23:40:48 +02:00
do
{
Element* next = iter->sibling;
2019-11-23 23:37:49 +01:00
Property* prop = iter->first_property;
while (prop) {
Property* tmp = prop->next;
delete prop;
prop = tmp;
}
2018-09-03 16:04:47 +02:00
deleteElement(iter->child);
2017-07-11 23:40:48 +02:00
delete iter;
iter = next;
} while (iter);
}
2017-07-12 18:25:55 +02:00
static OptionalError<u64> readElementOffset(Cursor* cursor, u16 version)
2017-07-05 18:55:59 +02:00
{
2017-07-12 18:25:55 +02:00
if (version >= 7500)
{
OptionalError<u64> tmp = read<u64>(cursor);
if (tmp.isError()) return Error();
return tmp.getValue();
}
OptionalError<u32> tmp = read<u32>(cursor);
if (tmp.isError()) return Error();
return tmp.getValue();
}
static OptionalError<Element*> readElement(Cursor* cursor, u32 version)
{
OptionalError<u64> end_offset = readElementOffset(cursor, version);
2017-07-07 18:22:17 +02:00
if (end_offset.isError()) return Error();
if (end_offset.getValue() == 0) return nullptr;
2017-07-07 18:10:32 +02:00
2017-07-12 18:25:55 +02:00
OptionalError<u64> prop_count = readElementOffset(cursor, version);
OptionalError<u64> prop_length = readElementOffset(cursor, version);
2017-07-07 18:22:17 +02:00
if (prop_count.isError() || prop_length.isError()) return Error();
2017-07-05 18:55:59 +02:00
2017-07-07 18:10:32 +02:00
OptionalError<DataView> id = readShortString(cursor);
2017-07-07 18:22:17 +02:00
if (id.isError()) return Error();
2017-07-07 18:10:32 +02:00
2017-07-11 23:40:48 +02:00
Element* element = new Element();
2017-07-05 18:55:59 +02:00
element->first_property = nullptr;
2017-07-07 18:22:17 +02:00
element->id = id.getValue();
2017-07-05 18:55:59 +02:00
element->child = nullptr;
element->sibling = nullptr;
Property** prop_link = &element->first_property;
2017-07-07 18:22:17 +02:00
for (u32 i = 0; i < prop_count.getValue(); ++i)
2017-07-05 18:55:59 +02:00
{
2017-07-07 18:10:32 +02:00
OptionalError<Property*> prop = readProperty(cursor);
2017-07-11 23:40:48 +02:00
if (prop.isError())
{
deleteElement(element);
return Error();
}
2017-07-10 20:05:47 +02:00
2017-07-07 18:22:17 +02:00
*prop_link = prop.getValue();
2017-07-05 18:55:59 +02:00
prop_link = &(*prop_link)->next;
}
2017-07-12 18:25:55 +02:00
if (cursor->current - cursor->begin >= (ptrdiff_t)end_offset.getValue()) return element;
2017-07-05 18:55:59 +02:00
2017-07-12 18:25:55 +02:00
int BLOCK_SENTINEL_LENGTH = version >= 7500 ? 25 : 13;
2017-07-05 18:55:59 +02:00
Element** link = &element->child;
2017-07-12 18:25:55 +02:00
while (cursor->current - cursor->begin < ((ptrdiff_t)end_offset.getValue() - BLOCK_SENTINEL_LENGTH))
2017-07-05 18:55:59 +02:00
{
2017-07-12 18:25:55 +02:00
OptionalError<Element*> child = readElement(cursor, version);
2017-07-11 23:40:48 +02:00
if (child.isError())
{
deleteElement(element);
return Error();
}
2017-07-07 18:10:32 +02:00
2017-07-07 18:22:17 +02:00
*link = child.getValue();
2017-07-05 18:55:59 +02:00
link = &(*link)->sibling;
}
2017-07-11 23:40:48 +02:00
if (cursor->current + BLOCK_SENTINEL_LENGTH > cursor->end)
{
2019-06-02 16:12:47 +02:00
deleteElement(element);
2017-07-11 23:40:48 +02:00
return Error("Reading past the end");
}
2017-07-10 20:05:47 +02:00
2017-07-07 18:10:32 +02:00
cursor->current += BLOCK_SENTINEL_LENGTH;
2017-07-11 23:40:48 +02:00
return element;
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
static bool isEndLine(const Cursor& cursor)
{
return *cursor.current == '\n';
}
static void skipInsignificantWhitespaces(Cursor* cursor)
{
while (cursor->current < cursor->end && isspace(*cursor->current) && *cursor->current != '\n')
{
++cursor->current;
}
}
static void skipLine(Cursor* cursor)
{
while (cursor->current < cursor->end && !isEndLine(*cursor))
{
++cursor->current;
}
if (cursor->current < cursor->end) ++cursor->current;
skipInsignificantWhitespaces(cursor);
}
static void skipWhitespaces(Cursor* cursor)
{
while (cursor->current < cursor->end && isspace(*cursor->current))
{
++cursor->current;
}
while (cursor->current < cursor->end && *cursor->current == ';') skipLine(cursor);
}
static bool isTextTokenChar(char c)
{
return isalnum(c) || c == '_';
}
static DataView readTextToken(Cursor* cursor)
{
DataView ret;
ret.begin = cursor->current;
while (cursor->current < cursor->end && isTextTokenChar(*cursor->current))
{
++cursor->current;
}
ret.end = cursor->current;
return ret;
}
static OptionalError<Property*> readTextProperty(Cursor* cursor)
{
2018-10-16 21:28:03 +02:00
std::unique_ptr<Property> prop(new Property());
2017-08-30 00:08:16 +02:00
prop->value.is_binary = false;
prop->next = nullptr;
if (*cursor->current == '"')
{
prop->type = 'S';
++cursor->current;
prop->value.begin = cursor->current;
while (cursor->current < cursor->end && *cursor->current != '"')
{
++cursor->current;
}
prop->value.end = cursor->current;
if (cursor->current < cursor->end) ++cursor->current; // skip '"'
return prop.release();
}
2019-06-02 16:12:47 +02:00
2017-08-30 00:08:16 +02:00
if (isdigit(*cursor->current) || *cursor->current == '-')
{
prop->type = 'L';
prop->value.begin = cursor->current;
if (*cursor->current == '-') ++cursor->current;
while (cursor->current < cursor->end && isdigit(*cursor->current))
{
++cursor->current;
}
prop->value.end = cursor->current;
if (cursor->current < cursor->end && *cursor->current == '.')
{
prop->type = 'D';
++cursor->current;
while (cursor->current < cursor->end && isdigit(*cursor->current))
{
++cursor->current;
}
if (cursor->current < cursor->end && (*cursor->current == 'e' || *cursor->current == 'E'))
2017-08-30 00:08:16 +02:00
{
// 10.5e-013
++cursor->current;
if (cursor->current < cursor->end && *cursor->current == '-') ++cursor->current;
while (cursor->current < cursor->end && isdigit(*cursor->current)) ++cursor->current;
}
prop->value.end = cursor->current;
}
return prop.release();
}
2019-06-02 16:12:47 +02:00
2019-11-23 23:37:49 +01:00
if (*cursor->current == 'T' || *cursor->current == 'Y' || *cursor->current == 'W')
2017-08-30 00:08:16 +02:00
{
// WTF is this
prop->type = *cursor->current;
prop->value.begin = cursor->current;
++cursor->current;
prop->value.end = cursor->current;
return prop.release();
}
if (*cursor->current == '*')
{
prop->type = 'l';
++cursor->current;
// Vertices: *10740 { a: 14.2760353088379,... }
while (cursor->current < cursor->end && *cursor->current != ':')
{
++cursor->current;
}
if (cursor->current < cursor->end) ++cursor->current; // skip ':'
skipInsignificantWhitespaces(cursor);
prop->value.begin = cursor->current;
2018-02-04 01:29:40 +01:00
prop->count = 0;
bool is_any = false;
2017-08-30 00:08:16 +02:00
while (cursor->current < cursor->end && *cursor->current != '}')
{
2018-02-04 01:29:40 +01:00
if (*cursor->current == ',')
{
if (is_any) ++prop->count;
is_any = false;
}
2019-06-02 16:12:47 +02:00
else if (!isspace(*cursor->current) && *cursor->current != '\n')
is_any = true;
2017-08-30 00:08:16 +02:00
if (*cursor->current == '.') prop->type = 'd';
++cursor->current;
}
2018-02-04 01:29:40 +01:00
if (is_any) ++prop->count;
2017-08-30 00:08:16 +02:00
prop->value.end = cursor->current;
if (cursor->current < cursor->end) ++cursor->current; // skip '}'
return prop.release();
}
assert(false);
return Error("TODO");
}
static OptionalError<Element*> readTextElement(Cursor* cursor)
{
DataView id = readTextToken(cursor);
if (cursor->current == cursor->end) return Error("Unexpected end of file");
2019-11-23 23:37:49 +01:00
if (*cursor->current != ':') return Error("Unexpected character");
2017-08-30 00:08:16 +02:00
++cursor->current;
2019-11-23 23:37:49 +01:00
skipInsignificantWhitespaces(cursor);
2017-08-30 00:08:16 +02:00
if (cursor->current == cursor->end) return Error("Unexpected end of file");
Element* element = new Element;
element->id = id;
Property** prop_link = &element->first_property;
while (cursor->current < cursor->end && *cursor->current != '\n' && *cursor->current != '{')
{
OptionalError<Property*> prop = readTextProperty(cursor);
if (prop.isError())
{
deleteElement(element);
return Error();
}
if (cursor->current < cursor->end && *cursor->current == ',')
{
++cursor->current;
skipWhitespaces(cursor);
}
skipInsignificantWhitespaces(cursor);
*prop_link = prop.getValue();
prop_link = &(*prop_link)->next;
}
2019-06-02 16:12:47 +02:00
2017-08-30 00:08:16 +02:00
Element** link = &element->child;
if (*cursor->current == '{')
{
++cursor->current;
skipWhitespaces(cursor);
while (cursor->current < cursor->end && *cursor->current != '}')
{
OptionalError<Element*> child = readTextElement(cursor);
if (child.isError())
{
deleteElement(element);
return Error();
}
skipWhitespaces(cursor);
*link = child.getValue();
link = &(*link)->sibling;
}
if (cursor->current < cursor->end) ++cursor->current; // skip '}'
}
return element;
}
static OptionalError<Element*> tokenizeText(const u8* data, size_t size)
{
Cursor cursor;
cursor.begin = data;
cursor.current = data;
cursor.end = data + size;
Element* root = new Element();
root->first_property = nullptr;
root->id.begin = nullptr;
root->id.end = nullptr;
root->child = nullptr;
root->sibling = nullptr;
Element** element = &root->child;
while (cursor.current < cursor.end)
{
if (*cursor.current == ';' || *cursor.current == '\r' || *cursor.current == '\n')
{
skipLine(&cursor);
}
else
{
OptionalError<Element*> child = readTextElement(&cursor);
if (child.isError())
{
deleteElement(root);
return Error();
}
*element = child.getValue();
if (!*element) return root;
element = &(*element)->sibling;
}
}
return root;
}
2019-06-02 16:12:47 +02:00
static OptionalError<Element*> tokenize(const u8* data, size_t size, u32& version)
2017-07-05 18:55:59 +02:00
{
Cursor cursor;
cursor.begin = data;
cursor.current = data;
cursor.end = data + size;
const Header* header = (const Header*)cursor.current;
cursor.current += sizeof(*header);
2019-06-02 16:12:47 +02:00
version = header->version;
2017-07-05 18:55:59 +02:00
2017-07-11 23:40:48 +02:00
Element* root = new Element();
2017-07-05 18:55:59 +02:00
root->first_property = nullptr;
root->id.begin = nullptr;
root->id.end = nullptr;
root->child = nullptr;
root->sibling = nullptr;
Element** element = &root->child;
for (;;)
{
2017-07-12 18:25:55 +02:00
OptionalError<Element*> child = readElement(&cursor, header->version);
2017-07-11 23:40:48 +02:00
if (child.isError())
{
deleteElement(root);
return Error();
}
2017-07-07 18:22:17 +02:00
*element = child.getValue();
2017-07-11 23:40:48 +02:00
if (!*element) return root;
2017-07-05 18:55:59 +02:00
element = &(*element)->sibling;
}
}
2017-07-05 19:43:01 +02:00
static void parseTemplates(const Element& root)
2017-07-05 18:55:59 +02:00
{
const Element* defs = findChild(root, "Definitions");
if (!defs) return;
std::unordered_map<std::string, Element*> templates;
Element* def = defs->child;
while (def)
{
if (def->id == "ObjectType")
{
Element* subdef = def->child;
while (subdef)
{
if (subdef->id == "PropertyTemplate")
{
DataView prop1 = def->first_property->value;
DataView prop2 = subdef->first_property->value;
std::string key((const char*)prop1.begin, prop1.end - prop1.begin);
key += std::string((const char*)prop1.begin, prop1.end - prop1.begin);
templates[key] = subdef;
}
subdef = subdef->sibling;
}
}
def = def->sibling;
}
// TODO
}
struct Scene;
Mesh::Mesh(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct MeshImpl : Mesh
{
MeshImpl(const Scene& _scene, const IElement& _element)
: Mesh(_scene, _element)
, scene(_scene)
{
is_node = true;
}
Matrix getGeometricMatrix() const override
{
Vec3 translation = resolveVec3Property(*this, "GeometricTranslation", {0, 0, 0});
Vec3 rotation = resolveVec3Property(*this, "GeometricRotation", {0, 0, 0});
Vec3 scale = resolveVec3Property(*this, "GeometricScaling", {1, 1, 1});
Matrix scale_mtx = makeIdentity();
scale_mtx.m[0] = (float)scale.x;
scale_mtx.m[5] = (float)scale.y;
scale_mtx.m[10] = (float)scale.z;
Matrix mtx = getRotationMatrix(rotation, RotationOrder::EULER_XYZ);
2017-07-05 18:55:59 +02:00
setTranslation(translation, &mtx);
return scale_mtx * mtx;
}
Type getType() const override { return Type::MESH; }
const Pose* getPose() const override { return pose; }
2017-07-05 19:43:01 +02:00
const Geometry* getGeometry() const override { return geometry; }
2017-07-08 12:44:23 +02:00
const Material* getMaterial(int index) const override { return materials[index]; }
int getMaterialCount() const override { return (int)materials.size(); }
2017-07-05 18:55:59 +02:00
const Pose* pose = nullptr;
2017-07-10 16:45:32 +02:00
const Geometry* geometry = nullptr;
2017-07-05 18:55:59 +02:00
const Scene& scene;
2017-07-08 12:44:23 +02:00
std::vector<const Material*> materials;
2017-07-05 18:55:59 +02:00
};
Material::Material(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct MaterialImpl : Material
{
MaterialImpl(const Scene& _scene, const IElement& _element)
: Material(_scene, _element)
{
2017-07-06 21:21:48 +02:00
for (const Texture*& tex : textures) tex = nullptr;
2017-07-05 18:55:59 +02:00
}
Type getType() const override { return Type::MATERIAL; }
2017-07-06 21:21:48 +02:00
2017-07-10 20:05:47 +02:00
const Texture* getTexture(Texture::TextureType type) const override { return textures[type]; }
2017-11-22 14:45:00 +01:00
Color getDiffuseColor() const override { return diffuse_color; }
2019-06-26 21:21:48 +02:00
Color getSpecularColor() const override { return specular_color; }
2017-07-06 21:21:48 +02:00
const Texture* textures[Texture::TextureType::COUNT];
2017-11-22 14:45:00 +01:00
Color diffuse_color;
2019-06-26 21:21:48 +02:00
Color specular_color;
2017-07-05 18:55:59 +02:00
};
struct LimbNodeImpl : Object
{
LimbNodeImpl(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
{
is_node = true;
}
Type getType() const override { return Type::LIMB_NODE; }
};
struct NullImpl : Object
{
NullImpl(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
{
is_node = true;
}
Type getType() const override { return Type::NULL_NODE; }
};
NodeAttribute::NodeAttribute(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct NodeAttributeImpl : NodeAttribute
{
NodeAttributeImpl(const Scene& _scene, const IElement& _element)
: NodeAttribute(_scene, _element)
{
}
2017-07-10 19:49:03 +02:00
Type getType() const override { return Type::NODE_ATTRIBUTE; }
2017-07-05 18:55:59 +02:00
DataView getAttributeType() const override { return attribute_type; }
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
DataView attribute_type;
};
Geometry::Geometry(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct GeometryImpl : Geometry
{
enum VertexDataMapping
{
BY_POLYGON_VERTEX,
BY_POLYGON,
BY_VERTEX
};
2017-07-10 18:15:14 +02:00
struct NewVertex
{
~NewVertex() { delete next; }
2017-07-10 20:05:47 +02:00
2017-07-10 18:15:14 +02:00
int index = -1;
NewVertex* next = nullptr;
};
2017-07-05 18:55:59 +02:00
std::vector<Vec3> vertices;
std::vector<Vec3> normals;
2018-04-11 12:49:29 +02:00
std::vector<Vec2> uvs[s_uvs_max];
2017-07-05 18:55:59 +02:00
std::vector<Vec4> colors;
std::vector<Vec3> tangents;
2017-07-08 12:44:23 +02:00
std::vector<int> materials;
2017-07-05 18:55:59 +02:00
2017-07-06 21:21:48 +02:00
const Skin* skin = nullptr;
2019-06-26 21:21:48 +02:00
std::vector<int> indices;
2017-07-05 18:55:59 +02:00
std::vector<int> to_old_vertices;
2017-07-10 18:15:14 +02:00
std::vector<NewVertex> to_new_vertices;
2017-07-05 18:55:59 +02:00
GeometryImpl(const Scene& _scene, const IElement& _element)
: Geometry(_scene, _element)
{
}
2017-07-06 21:21:48 +02:00
2017-07-05 18:55:59 +02:00
Type getType() const override { return Type::GEOMETRY; }
int getVertexCount() const override { return (int)vertices.size(); }
2019-06-26 21:21:48 +02:00
const int* getFaceIndices() const override { return indices.empty() ? nullptr : &indices[0]; }
int getIndexCount() const override { return (int)indices.size(); }
2017-07-05 18:55:59 +02:00
const Vec3* getVertices() const override { return &vertices[0]; }
const Vec3* getNormals() const override { return normals.empty() ? nullptr : &normals[0]; }
2018-04-11 12:49:29 +02:00
const Vec2* getUVs(int index = 0) const override { return index < 0 || index >= s_uvs_max || uvs[index].empty() ? nullptr : &uvs[index][0]; }
2017-07-05 18:55:59 +02:00
const Vec4* getColors() const override { return colors.empty() ? nullptr : &colors[0]; }
const Vec3* getTangents() const override { return tangents.empty() ? nullptr : &tangents[0]; }
2017-07-06 21:21:48 +02:00
const Skin* getSkin() const override { return skin; }
2017-07-08 13:09:24 +02:00
const int* getMaterials() const override { return materials.empty() ? nullptr : &materials[0]; }
2017-07-05 18:55:59 +02:00
};
Cluster::Cluster(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
{
}
struct ClusterImpl : Cluster
{
ClusterImpl(const Scene& _scene, const IElement& _element)
: Cluster(_scene, _element)
{
}
const int* getIndices() const override { return &indices[0]; }
2017-08-30 00:08:16 +02:00
int getIndicesCount() const override { return (int)indices.size(); }
2017-07-05 18:55:59 +02:00
const double* getWeights() const override { return &weights[0]; }
int getWeightsCount() const override { return (int)weights.size(); }
2017-10-29 22:23:51 +01:00
Matrix getTransformMatrix() const override { return transform_matrix; }
Matrix getTransformLinkMatrix() const override { return transform_link_matrix; }
2017-07-10 16:45:32 +02:00
Object* getLink() const override { return link; }
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
bool postprocess()
2017-07-05 19:43:01 +02:00
{
2017-07-10 16:45:32 +02:00
assert(skin);
2017-07-05 18:55:59 +02:00
GeometryImpl* geom = (GeometryImpl*)skin->resolveObjectLinkReverse(Object::Type::GEOMETRY);
2017-07-11 18:57:34 +02:00
if (!geom) return false;
2017-07-05 18:55:59 +02:00
std::vector<int> old_indices;
const Element* indexes = findChild((const Element&)element, "Indexes");
if (indexes && indexes->first_property)
{
2017-07-11 18:57:34 +02:00
if (!parseBinaryArray(*indexes->first_property, &old_indices)) return false;
2017-07-05 18:55:59 +02:00
}
std::vector<double> old_weights;
const Element* weights_el = findChild((const Element&)element, "Weights");
if (weights_el && weights_el->first_property)
{
2017-07-11 18:57:34 +02:00
if (!parseBinaryArray(*weights_el->first_property, &old_weights)) return false;
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
if (old_indices.size() != old_weights.size()) return false;
2017-07-05 19:43:01 +02:00
2017-07-10 18:15:14 +02:00
indices.reserve(old_indices.size());
weights.reserve(old_indices.size());
int* ir = old_indices.empty() ? nullptr : &old_indices[0];
double* wr = old_weights.empty() ? nullptr : &old_weights[0];
2017-07-05 18:55:59 +02:00
for (int i = 0, c = (int)old_indices.size(); i < c; ++i)
{
2017-07-10 18:15:14 +02:00
int old_idx = ir[i];
double w = wr[i];
GeometryImpl::NewVertex* n = &geom->to_new_vertices[old_idx];
2017-09-12 00:56:12 +02:00
if (n->index == -1) continue; // skip vertices which aren't indexed.
2017-07-05 18:55:59 +02:00
while (n)
{
2017-07-10 18:15:14 +02:00
indices.push_back(n->index);
2017-07-05 18:55:59 +02:00
weights.push_back(w);
n = n->next;
}
}
2017-07-11 18:57:34 +02:00
return true;
2017-07-05 18:55:59 +02:00
}
2017-07-10 16:45:32 +02:00
Object* link = nullptr;
Skin* skin = nullptr;
2017-07-05 18:55:59 +02:00
std::vector<int> indices;
std::vector<double> weights;
Matrix transform_matrix;
Matrix transform_link_matrix;
Type getType() const override { return Type::CLUSTER; }
};
AnimationStack::AnimationStack(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
AnimationLayer::AnimationLayer(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
AnimationCurve::AnimationCurve(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
AnimationCurveNode::AnimationCurveNode(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct AnimationStackImpl : AnimationStack
{
AnimationStackImpl(const Scene& _scene, const IElement& _element)
: AnimationStack(_scene, _element)
{
}
2017-10-29 22:23:51 +01:00
const AnimationLayer* getLayer(int index) const override
2017-07-05 18:55:59 +02:00
{
2017-07-06 21:21:48 +02:00
return resolveObjectLink<AnimationLayer>(index);
2017-07-05 18:55:59 +02:00
}
Type getType() const override { return Type::ANIMATION_STACK; }
};
struct AnimationCurveImpl : AnimationCurve
{
AnimationCurveImpl(const Scene& _scene, const IElement& _element)
: AnimationCurve(_scene, _element)
{
}
int getKeyCount() const override { return (int)times.size(); }
const i64* getKeyTime() const override { return &times[0]; }
2017-07-05 18:55:59 +02:00
const float* getKeyValue() const override { return &values[0]; }
std::vector<i64> times;
2017-07-05 18:55:59 +02:00
std::vector<float> values;
Type getType() const override { return Type::ANIMATION_CURVE; }
};
Skin::Skin(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
struct SkinImpl : Skin
{
SkinImpl(const Scene& _scene, const IElement& _element)
: Skin(_scene, _element)
{
}
2017-07-10 16:45:32 +02:00
int getClusterCount() const override { return (int)clusters.size(); }
const Cluster* getCluster(int idx) const override { return clusters[idx]; }
2017-07-05 18:55:59 +02:00
Type getType() const override { return Type::SKIN; }
2017-07-10 16:45:32 +02:00
std::vector<Cluster*> clusters;
2017-07-05 18:55:59 +02:00
};
Texture::Texture(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
2017-07-05 19:43:01 +02:00
{
}
2017-07-05 18:55:59 +02:00
Pose::Pose(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
{
}
struct PoseImpl : Pose
{
PoseImpl(const Scene& _scene, const IElement& _element)
: Pose(_scene, _element)
{
}
bool postprocess(Scene* scene);
Matrix getMatrix() const override { return matrix; }
const Object* getNode() const override { return node; }
Type getType() const override { return Type::POSE; }
Matrix matrix;
Object* node = nullptr;
DataView node_id;
};
2017-07-05 18:55:59 +02:00
struct TextureImpl : Texture
{
TextureImpl(const Scene& _scene, const IElement& _element)
: Texture(_scene, _element)
{
}
DataView getRelativeFileName() const override { return relative_filename; }
DataView getFileName() const override { return filename; }
DataView filename;
DataView relative_filename;
Type getType() const override { return Type::TEXTURE; }
};
struct Root : Object
{
Root(const Scene& _scene, const IElement& _element)
: Object(_scene, _element)
{
2017-07-05 19:43:01 +02:00
copyString(name, "RootNode");
2017-07-05 18:55:59 +02:00
is_node = true;
}
Type getType() const override { return Type::ROOT; }
};
struct Scene : IScene
{
struct Connection
{
2017-07-05 19:43:01 +02:00
enum Type
{
2017-07-05 18:55:59 +02:00
OBJECT_OBJECT,
OBJECT_PROPERTY
};
2019-11-23 23:37:49 +01:00
Type type = OBJECT_OBJECT;
u64 from = 0;
u64 to = 0;
2017-07-05 18:55:59 +02:00
DataView property;
};
struct ObjectPair
{
const Element* element;
Object* object;
};
2017-10-29 22:23:51 +01:00
int getAnimationStackCount() const override { return (int)m_animation_stacks.size(); }
2017-07-06 18:49:04 +02:00
int getMeshCount() const override { return (int)m_meshes.size(); }
2017-10-29 22:50:33 +01:00
float getSceneFrameRate() const override { return m_scene_frame_rate; }
2018-09-03 16:04:47 +02:00
const GlobalSettings* getGlobalSettings() const override { return &m_settings; }
2017-07-05 18:55:59 +02:00
2017-07-10 20:05:47 +02:00
const Object* const* getAllObjects() const override { return m_all_objects.empty() ? nullptr : &m_all_objects[0]; }
2017-07-09 17:56:16 +02:00
2017-07-10 20:05:47 +02:00
int getAllObjectCount() const override { return (int)m_all_objects.size(); }
2017-07-09 17:56:16 +02:00
2017-07-06 18:49:04 +02:00
const AnimationStack* getAnimationStack(int index) const override
{
assert(index >= 0);
assert(index < m_animation_stacks.size());
return m_animation_stacks[index];
}
2017-07-05 18:55:59 +02:00
2017-07-06 18:49:04 +02:00
const Mesh* getMesh(int index) const override
2017-07-05 18:55:59 +02:00
{
2017-07-06 18:49:04 +02:00
assert(index >= 0);
assert(index < m_meshes.size());
return m_meshes[index];
2017-07-05 18:55:59 +02:00
}
2017-07-06 18:49:04 +02:00
const TakeInfo* getTakeInfo(const char* name) const override
2017-07-05 18:55:59 +02:00
{
2017-07-06 18:49:04 +02:00
for (const TakeInfo& info : m_take_infos)
2017-07-05 18:55:59 +02:00
{
2017-07-06 18:49:04 +02:00
if (info.name == name) return &info;
2017-07-05 18:55:59 +02:00
}
return nullptr;
}
2017-07-09 17:56:16 +02:00
const IElement* getRootElement() const override { return m_root_element; }
const Object* getRoot() const override { return m_root; }
2017-07-06 18:49:04 +02:00
2017-07-05 18:55:59 +02:00
void destroy() override { delete this; }
2019-11-23 23:37:49 +01:00
~Scene() override
2017-07-05 18:55:59 +02:00
{
for (auto iter : m_object_map)
{
delete iter.second.object;
}
2019-06-02 16:12:47 +02:00
2017-07-11 23:32:56 +02:00
deleteElement(m_root_element);
2017-07-05 18:55:59 +02:00
}
2017-07-07 18:10:32 +02:00
Element* m_root_element = nullptr;
Root* m_root = nullptr;
2017-10-29 22:50:33 +01:00
float m_scene_frame_rate = -1;
2018-09-03 16:04:47 +02:00
GlobalSettings m_settings;
2017-07-05 18:55:59 +02:00
std::unordered_map<u64, ObjectPair> m_object_map;
2017-07-09 17:56:16 +02:00
std::vector<Object*> m_all_objects;
2017-07-06 18:49:04 +02:00
std::vector<Mesh*> m_meshes;
std::vector<AnimationStack*> m_animation_stacks;
2017-07-05 18:55:59 +02:00
std::vector<Connection> m_connections;
std::vector<u8> m_data;
std::vector<TakeInfo> m_take_infos;
};
bool PoseImpl::postprocess(Scene* scene)
{
node = scene->m_object_map[node_id.toU64()].object;
if (node && node->getType() == Object::Type::MESH) {
static_cast<MeshImpl*>(node)->pose = this;
}
return true;
}
2017-07-05 18:55:59 +02:00
struct AnimationCurveNodeImpl : AnimationCurveNode
{
AnimationCurveNodeImpl(const Scene& _scene, const IElement& _element)
: AnimationCurveNode(_scene, _element)
{
2019-07-21 22:20:59 +02:00
default_values[0] = default_values[1] = default_values[2] = 0;
Element* dx = static_cast<Element*>(resolveProperty(*this, "d|X"));
Element* dy = static_cast<Element*>(resolveProperty(*this, "d|Y"));
Element* dz = static_cast<Element*>(resolveProperty(*this, "d|Z"));
2019-07-21 22:20:59 +02:00
if (dx) {
Property* x = (Property*)dx->getProperty(4);
if (x) default_values[0] = (float)x->value.toDouble();
}
if (dy) {
Property* y = (Property*)dy->getProperty(4);
if (y) default_values[1] = (float)y->value.toDouble();
}
if (dz) {
Property* z = (Property*)dz->getProperty(4);
if (z) default_values[2] = (float)z->value.toDouble();
}
2017-07-05 18:55:59 +02:00
}
const Object* getBone() const override
{
return bone;
}
2019-09-11 18:23:26 +02:00
const AnimationCurve* getCurve(int idx) const override {
assert(idx >= 0 && idx < 3);
return curves[idx].curve;
}
2017-07-05 18:55:59 +02:00
Vec3 getNodeLocalTransform(double time) const override
{
i64 fbx_time = secondsToFbxTime(time);
2017-07-09 11:56:31 +02:00
2019-07-21 22:20:59 +02:00
auto getCoord = [&](const Curve& curve, i64 fbx_time, int idx) {
if (!curve.curve) return default_values[idx];
2017-07-10 20:05:47 +02:00
const i64* times = curve.curve->getKeyTime();
2017-07-09 11:56:31 +02:00
const float* values = curve.curve->getKeyValue();
int count = curve.curve->getKeyCount();
if (fbx_time < times[0]) fbx_time = times[0];
if (fbx_time > times[count - 1]) fbx_time = times[count - 1];
for (int i = 1; i < count; ++i)
2017-07-05 18:55:59 +02:00
{
2017-07-09 11:56:31 +02:00
if (times[i] >= fbx_time)
{
float t = float(double(fbx_time - times[i - 1]) / double(times[i] - times[i - 1]));
return values[i - 1] * (1 - t) + values[i] * t;
}
2017-07-05 18:55:59 +02:00
}
2017-07-09 11:56:31 +02:00
return values[0];
};
2017-07-05 19:43:01 +02:00
2019-07-21 22:20:59 +02:00
return {getCoord(curves[0], fbx_time, 0), getCoord(curves[1], fbx_time, 1), getCoord(curves[2], fbx_time, 2)};
2017-07-05 18:55:59 +02:00
}
struct Curve
{
2017-07-10 16:45:32 +02:00
const AnimationCurve* curve = nullptr;
const Scene::Connection* connection = nullptr;
2017-07-05 18:55:59 +02:00
};
2017-07-09 11:56:31 +02:00
Curve curves[3];
2017-07-11 20:33:32 +02:00
Object* bone = nullptr;
DataView bone_link_property;
2017-07-05 18:55:59 +02:00
Type getType() const override { return Type::ANIMATION_CURVE_NODE; }
2019-07-21 22:20:59 +02:00
float default_values[3];
2017-07-05 18:55:59 +02:00
enum Mode
{
TRANSLATION,
ROTATION,
SCALE
} mode = TRANSLATION;
};
2017-07-11 20:33:32 +02:00
struct AnimationLayerImpl : AnimationLayer
{
AnimationLayerImpl(const Scene& _scene, const IElement& _element)
: AnimationLayer(_scene, _element)
{
}
Type getType() const override { return Type::ANIMATION_LAYER; }
const AnimationCurveNode* getCurveNode(int index) const override
{
if (index >= curve_nodes.size() || index < 0) return nullptr;
return curve_nodes[index];
}
2017-07-11 20:33:32 +02:00
2017-07-11 21:50:49 +02:00
const AnimationCurveNode* getCurveNode(const Object& bone, const char* prop) const override
2017-07-11 20:33:32 +02:00
{
for (const AnimationCurveNodeImpl* node : curve_nodes)
{
if (node->bone_link_property == prop && node->bone == &bone) return node;
}
return nullptr;
}
std::vector<AnimationCurveNodeImpl*> curve_nodes;
};
2017-07-11 18:57:34 +02:00
struct OptionalError<Object*> parseTexture(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
TextureImpl* texture = new TextureImpl(scene, element);
const Element* texture_filename = findChild(element, "FileName");
if (texture_filename && texture_filename->first_property)
{
texture->filename = texture_filename->first_property->value;
}
const Element* texture_relative_filename = findChild(element, "RelativeFilename");
if (texture_relative_filename && texture_relative_filename->first_property)
{
texture->relative_filename = texture_relative_filename->first_property->value;
}
return texture;
}
struct OptionalError<Object*> parsePose(const Scene& scene, const Element& element)
{
PoseImpl* pose = new PoseImpl(scene, element);
const Element* pose_node = findChild(element, "PoseNode");
if (pose_node) {
const Element* node = findChild(*pose_node, "Node");
const Element* matrix = findChild(*pose_node, "Matrix");
if (matrix->first_property) {
parseArrayRaw(*matrix->first_property, &pose->matrix, sizeof(pose->matrix));
}
pose->node_id = node->first_property->value;
}
return pose;
}
2019-06-02 16:12:47 +02:00
template <typename T>
static OptionalError<Object*> parse(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
T* obj = new T(scene, element);
return obj;
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseCluster(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
2018-10-16 21:28:03 +02:00
std::unique_ptr<ClusterImpl> obj(new ClusterImpl(scene, element));
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
const Element* transform_link = findChild(element, "TransformLink");
if (transform_link && transform_link->first_property)
{
2017-08-30 00:08:16 +02:00
if (!parseArrayRaw(
2017-07-11 18:57:34 +02:00
*transform_link->first_property, &obj->transform_link_matrix, sizeof(obj->transform_link_matrix)))
{
return Error("Failed to parse TransformLink");
}
2017-07-05 18:55:59 +02:00
}
const Element* transform = findChild(element, "Transform");
if (transform && transform->first_property)
{
2017-08-30 00:08:16 +02:00
if (!parseArrayRaw(*transform->first_property, &obj->transform_matrix, sizeof(obj->transform_matrix)))
2017-07-11 18:57:34 +02:00
{
return Error("Failed to parse Transform");
}
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
return obj.release();
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseNodeAttribute(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
NodeAttributeImpl* obj = new NodeAttributeImpl(scene, element);
const Element* type_flags = findChild(element, "TypeFlags");
if (type_flags && type_flags->first_property)
{
obj->attribute_type = type_flags->first_property->value;
}
return obj;
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseLimbNode(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
if (!element.first_property
|| !element.first_property->next
|| !element.first_property->next->next
|| element.first_property->next->next->value != "LimbNode")
{
return Error("Invalid limb node");
}
2017-07-05 18:55:59 +02:00
LimbNodeImpl* obj = new LimbNodeImpl(scene, element);
return obj;
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseMesh(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
if (!element.first_property
|| !element.first_property->next
|| !element.first_property->next->next
|| element.first_property->next->next->value != "Mesh")
{
return Error("Invalid mesh");
}
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
return new MeshImpl(scene, element);
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseMaterial(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
MaterialImpl* material = new MaterialImpl(scene, element);
2017-11-22 14:45:00 +01:00
const Element* prop = findChild(element, "Properties70");
2019-06-02 16:12:47 +02:00
material->diffuse_color = {1, 1, 1};
2017-07-05 18:55:59 +02:00
if (prop) prop = prop->child;
2017-07-05 19:43:01 +02:00
while (prop)
2017-07-05 18:55:59 +02:00
{
if (prop->id == "P" && prop->first_property)
{
if (prop->first_property->value == "DiffuseColor")
{
2017-11-22 14:45:00 +01:00
material->diffuse_color.r = (float)prop->getProperty(4)->getValue().toDouble();
material->diffuse_color.g = (float)prop->getProperty(5)->getValue().toDouble();
material->diffuse_color.b = (float)prop->getProperty(6)->getValue().toDouble();
2017-07-05 18:55:59 +02:00
}
2019-06-26 21:21:48 +02:00
else if (prop->first_property->value == "SpecularColor")
{
material->specular_color.r = (float)prop->getProperty(4)->getValue().toDouble();
material->specular_color.g = (float)prop->getProperty(5)->getValue().toDouble();
material->specular_color.b = (float)prop->getProperty(6)->getValue().toDouble();
}
2017-07-05 18:55:59 +02:00
}
prop = prop->sibling;
2017-11-22 14:45:00 +01:00
}
2017-07-05 18:55:59 +02:00
return material;
}
2019-06-02 16:12:47 +02:00
template <typename T> static bool parseTextArrayRaw(const Property& property, T* out, int max_size);
2017-08-30 00:08:16 +02:00
template <typename T> static bool parseArrayRaw(const Property& property, T* out, int max_size)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
if (property.value.is_binary)
{
assert(out);
int elem_size = 1;
switch (property.type)
{
case 'l': elem_size = 8; break;
case 'd': elem_size = 8; break;
case 'f': elem_size = 4; break;
case 'i': elem_size = 4; break;
default: return false;
}
const u8* data = property.value.begin + sizeof(u32) * 3;
if (data > property.value.end) return false;
u32 count = property.getCount();
u32 enc = *(const u32*)(property.value.begin + 4);
u32 len = *(const u32*)(property.value.begin + 8);
if (enc == 0)
{
if ((int)len > max_size) return false;
if (data + len > property.value.end) return false;
memcpy(out, data, len);
return true;
}
else if (enc == 1)
{
if (int(elem_size * count) > max_size) return false;
return decompress(data, len, (u8*)out, elem_size * count);
}
return false;
}
return parseTextArrayRaw(property, out, max_size);
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
template <typename T> const char* fromString(const char* str, const char* end, T* val);
template <> const char* fromString<int>(const char* str, const char* end, int* val)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
*val = atoi(str);
const char* iter = str;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
return (const char*)iter;
}
2017-07-05 18:55:59 +02:00
2017-08-30 00:08:16 +02:00
template <> const char* fromString<u64>(const char* str, const char* end, u64* val)
{
*val = strtoull(str, nullptr, 10);
const char* iter = str;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
return (const char*)iter;
}
template <> const char* fromString<i64>(const char* str, const char* end, i64* val)
{
*val = atoll(str);
2017-08-30 00:08:16 +02:00
const char* iter = str;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
return (const char*)iter;
}
template <> const char* fromString<double>(const char* str, const char* end, double* val)
{
*val = atof(str);
const char* iter = str;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
return (const char*)iter;
}
template <> const char* fromString<float>(const char* str, const char* end, float* val)
{
*val = (float)atof(str);
const char* iter = str;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
return (const char*)iter;
}
const char* fromString(const char* str, const char* end, double* val, int count)
{
const char* iter = str;
for (int i = 0; i < count; ++i)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
*val = atof(iter);
++val;
while (iter < end && *iter != ',') ++iter;
if (iter < end) ++iter; // skip ','
if (iter == end) return iter;
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
return (const char*)iter;
}
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
2017-08-30 00:08:16 +02:00
template <> const char* fromString<Vec2>(const char* str, const char* end, Vec2* val)
{
return fromString(str, end, &val->x, 2);
}
template <> const char* fromString<Vec3>(const char* str, const char* end, Vec3* val)
{
return fromString(str, end, &val->x, 3);
}
template <> const char* fromString<Vec4>(const char* str, const char* end, Vec4* val)
{
return fromString(str, end, &val->x, 4);
}
template <> const char* fromString<Matrix>(const char* str, const char* end, Matrix* val)
{
return fromString(str, end, &val->m[0], 16);
}
2019-06-02 16:12:47 +02:00
template <typename T> static void parseTextArray(const Property& property, std::vector<T>* out)
2017-08-30 00:08:16 +02:00
{
const u8* iter = property.value.begin;
2019-06-02 16:12:47 +02:00
for (int i = 0; i < property.count; ++i)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
T val;
iter = (const u8*)fromString<T>((const char*)iter, (const char*)property.value.end, &val);
out->push_back(val);
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
}
2019-06-02 16:12:47 +02:00
template <typename T> static bool parseTextArrayRaw(const Property& property, T* out_raw, int max_size)
2017-08-30 00:08:16 +02:00
{
const u8* iter = property.value.begin;
2019-06-02 16:12:47 +02:00
2017-08-30 00:08:16 +02:00
T* out = out_raw;
while (iter < property.value.end)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
iter = (const u8*)fromString<T>((const char*)iter, (const char*)property.value.end, out);
++out;
if (out - out_raw == max_size / sizeof(T)) return true;
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
return out - out_raw == max_size / sizeof(T);
2017-07-05 18:55:59 +02:00
}
2017-08-30 00:08:16 +02:00
template <typename T> static bool parseBinaryArray(const Property& property, std::vector<T>* out)
2017-07-05 18:55:59 +02:00
{
assert(out);
2017-08-30 00:08:16 +02:00
if (property.value.is_binary)
2017-07-05 18:55:59 +02:00
{
2017-08-30 00:08:16 +02:00
u32 count = property.getCount();
int elem_size = 1;
switch (property.type)
{
case 'd': elem_size = 8; break;
case 'f': elem_size = 4; break;
case 'i': elem_size = 4; break;
default: return false;
}
int elem_count = sizeof(T) / elem_size;
out->resize(count / elem_count);
2017-07-05 18:55:59 +02:00
2017-11-06 13:30:20 +01:00
if (count == 0) return true;
2017-08-30 00:08:16 +02:00
return parseArrayRaw(property, &(*out)[0], int(sizeof((*out)[0]) * out->size()));
}
else
{
parseTextArray(property, out);
return true;
}
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
template <typename T> static bool parseDoubleVecData(Property& property, std::vector<T>* out_vec)
2017-07-05 18:55:59 +02:00
{
assert(out_vec);
2017-08-30 00:08:16 +02:00
if (!property.value.is_binary)
{
parseTextArray(property, out_vec);
return true;
}
2017-07-05 18:55:59 +02:00
if (property.type == 'd')
{
2017-07-11 18:57:34 +02:00
return parseBinaryArray(property, out_vec);
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
assert(property.type == 'f');
assert(sizeof((*out_vec)[0].x) == sizeof(double));
std::vector<float> tmp;
if (!parseBinaryArray(property, &tmp)) return false;
int elem_count = sizeof((*out_vec)[0]) / sizeof((*out_vec)[0].x);
out_vec->resize(tmp.size() / elem_count);
double* out = &(*out_vec)[0].x;
for (int i = 0, c = (int)tmp.size(); i < c; ++i)
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
out[i] = tmp[i];
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
return true;
2017-07-05 18:55:59 +02:00
}
template <typename T>
2017-07-11 18:57:34 +02:00
static bool parseVertexData(const Element& element,
2017-07-05 19:43:01 +02:00
const char* name,
const char* index_name,
std::vector<T>* out,
std::vector<int>* out_indices,
GeometryImpl::VertexDataMapping* mapping)
2017-07-05 18:55:59 +02:00
{
assert(out);
assert(mapping);
const Element* data_element = findChild(element, name);
2019-06-02 16:12:47 +02:00
if (!data_element || !data_element->first_property) return false;
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
const Element* mapping_element = findChild(element, "MappingInformationType");
const Element* reference_element = findChild(element, "ReferenceInformationType");
if (mapping_element && mapping_element->first_property)
{
if (mapping_element->first_property->value == "ByPolygonVertex")
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
*mapping = GeometryImpl::BY_POLYGON_VERTEX;
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
else if (mapping_element->first_property->value == "ByPolygon")
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
*mapping = GeometryImpl::BY_POLYGON;
}
else if (mapping_element->first_property->value == "ByVertice" ||
2019-06-02 16:12:47 +02:00
mapping_element->first_property->value == "ByVertex")
2017-07-11 18:57:34 +02:00
{
*mapping = GeometryImpl::BY_VERTEX;
}
else
{
return false;
}
}
if (reference_element && reference_element->first_property)
{
if (reference_element->first_property->value == "IndexToDirect")
{
const Element* indices_element = findChild(element, index_name);
if (indices_element && indices_element->first_property)
2017-07-05 18:55:59 +02:00
{
2017-07-11 18:57:34 +02:00
if (!parseBinaryArray(*indices_element->first_property, out_indices)) return false;
2017-07-05 18:55:59 +02:00
}
}
2017-07-11 18:57:34 +02:00
else if (reference_element->first_property->value != "Direct")
{
return false;
}
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
return parseDoubleVecData(*data_element->first_property, out);
2017-07-05 18:55:59 +02:00
}
2019-06-26 21:21:48 +02:00
static int decodeIndex(int idx)
{
return (idx < 0) ? (-idx - 1) : idx;
}
static int codeIndex(int idx, bool last)
{
return last ? (-idx - 1) : idx;
}
2017-07-05 18:55:59 +02:00
template <typename T>
2017-07-05 19:43:01 +02:00
static void splat(std::vector<T>* out,
2017-07-05 18:55:59 +02:00
GeometryImpl::VertexDataMapping mapping,
const std::vector<T>& data,
const std::vector<int>& indices,
2018-02-03 14:08:35 +01:00
const std::vector<int>& original_indices)
2017-07-05 18:55:59 +02:00
{
assert(out);
assert(!data.empty());
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
if (mapping == GeometryImpl::BY_POLYGON_VERTEX)
{
if (indices.empty())
{
out->resize(data.size());
memcpy(&(*out)[0], &data[0], sizeof(data[0]) * data.size());
}
else
{
out->resize(indices.size());
2017-08-30 00:08:16 +02:00
int data_size = (int)data.size();
2017-07-05 18:55:59 +02:00
for (int i = 0, c = (int)indices.size(); i < c; ++i)
{
2019-06-02 16:12:47 +02:00
if (indices[i] < data_size)
(*out)[i] = data[indices[i]];
else
(*out)[i] = T();
2017-07-05 18:55:59 +02:00
}
}
}
2017-07-05 19:43:01 +02:00
else if (mapping == GeometryImpl::BY_VERTEX)
2017-07-05 18:55:59 +02:00
{
// v0 v1 ...
// uv0 uv1 ...
assert(indices.empty());
2017-07-05 19:43:01 +02:00
2018-02-03 14:08:35 +01:00
out->resize(original_indices.size());
2017-07-05 18:55:59 +02:00
2017-08-30 00:08:16 +02:00
int data_size = (int)data.size();
2018-02-03 14:08:35 +01:00
for (int i = 0, c = (int)original_indices.size(); i < c; ++i)
2017-07-05 18:55:59 +02:00
{
2019-06-26 21:21:48 +02:00
int idx = decodeIndex(original_indices[i]);
2019-06-02 16:12:47 +02:00
if (idx < data_size)
(*out)[i] = data[idx];
else
(*out)[i] = T();
2017-07-05 18:55:59 +02:00
}
}
else
{
assert(false);
}
}
2017-07-10 18:15:14 +02:00
template <typename T> static void remap(std::vector<T>* out, const std::vector<int>& map)
2017-07-05 18:55:59 +02:00
{
if (out->empty()) return;
std::vector<T> old;
old.swap(*out);
2017-08-30 00:08:16 +02:00
int old_size = (int)old.size();
2017-07-05 18:55:59 +02:00
for (int i = 0, c = (int)map.size(); i < c; ++i)
{
2019-06-02 16:12:47 +02:00
if (map[i] < old_size)
out->push_back(old[map[i]]);
else
out->push_back(T());
2017-07-05 18:55:59 +02:00
}
}
2017-07-11 18:57:34 +02:00
static OptionalError<Object*> parseAnimationCurve(const Scene& scene, const Element& element)
2017-07-05 18:55:59 +02:00
{
2018-10-16 21:28:03 +02:00
std::unique_ptr<AnimationCurveImpl> curve(new AnimationCurveImpl(scene, element));
2017-07-05 18:55:59 +02:00
const Element* times = findChild(element, "KeyTime");
const Element* values = findChild(element, "KeyValueFloat");
2017-07-11 18:57:34 +02:00
if (times && times->first_property)
2017-07-05 18:55:59 +02:00
{
curve->times.resize(times->first_property->getCount());
2017-07-11 18:57:34 +02:00
if (!times->first_property->getValues(&curve->times[0], (int)curve->times.size() * sizeof(curve->times[0])))
{
return Error("Invalid animation curve");
}
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
if (values && values->first_property)
2017-07-05 18:55:59 +02:00
{
curve->values.resize(values->first_property->getCount());
2017-07-11 18:57:34 +02:00
if (!values->first_property->getValues(&curve->values[0], (int)curve->values.size() * sizeof(curve->values[0])))
{
return Error("Invalid animation curve");
}
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
if (curve->times.size() != curve->values.size()) return Error("Invalid animation curve");
return curve.release();
2017-07-05 18:55:59 +02:00
}
2017-07-08 12:44:23 +02:00
static int getTriCountFromPoly(const std::vector<int>& indices, int* idx)
{
int count = 1;
while (indices[*idx + 1 + count] >= 0)
{
++count;
2017-11-28 19:37:15 +01:00
}
2017-07-08 12:44:23 +02:00
*idx = *idx + 2 + count;
return count;
}
2017-07-10 18:15:14 +02:00
static void add(GeometryImpl::NewVertex& vtx, int index)
{
if (vtx.index == -1)
{
vtx.index = index;
}
else if (vtx.next)
{
add(*vtx.next, index);
}
else
{
vtx.next = new GeometryImpl::NewVertex;
vtx.next->index = index;
}
}
2019-06-26 21:21:48 +02:00
static void triangulate(
const std::vector<int>& old_indices,
std::vector<int>* to_old_vertices,
std::vector<int>* to_old_indices)
2017-07-05 18:55:59 +02:00
{
2019-06-26 21:21:48 +02:00
assert(to_old_vertices);
assert(to_old_indices);
2017-07-05 18:55:59 +02:00
2019-06-26 21:21:48 +02:00
auto getIdx = [&old_indices](int i) -> int {
int idx = old_indices[i];
return decodeIndex(idx);
};
int in_polygon_idx = 0;
for (int i = 0; i < old_indices.size(); ++i)
2019-06-02 16:12:47 +02:00
{
2019-06-26 21:21:48 +02:00
int idx = getIdx(i);
if (in_polygon_idx <= 2)
{
to_old_vertices->push_back(idx);
to_old_indices->push_back(i);
}
else
{
to_old_vertices->push_back(old_indices[i - in_polygon_idx]);
to_old_indices->push_back(i - in_polygon_idx);
to_old_vertices->push_back(old_indices[i - 1]);
to_old_indices->push_back(i - 1);
to_old_vertices->push_back(idx);
to_old_indices->push_back(i);
}
++in_polygon_idx;
if (old_indices[i] < 0)
{
in_polygon_idx = 0;
}
2018-10-15 22:01:11 +02:00
}
2019-06-26 21:21:48 +02:00
}
2017-07-05 18:55:59 +02:00
2019-06-26 21:21:48 +02:00
static void buildGeometryVertexData(
const std::unique_ptr<GeometryImpl>& geom,
const std::vector<Vec3>& vertices,
const std::vector<int>& original_indices,
std::vector<int>& to_old_indices,
bool triangulationEnabled)
{
if (triangulationEnabled) {
triangulate(original_indices, &geom->to_old_vertices, &to_old_indices);
geom->vertices.resize(geom->to_old_vertices.size());
geom->indices.resize(geom->vertices.size());
for (int i = 0, c = (int)geom->to_old_vertices.size(); i < c; ++i)
{
geom->vertices[i] = vertices[geom->to_old_vertices[i]];
geom->indices[i] = codeIndex(i, i % 3 == 2);
}
} else {
geom->vertices = vertices;
geom->to_old_vertices.resize(original_indices.size());
for (size_t i = 0; i < original_indices.size(); ++i) {
geom->to_old_vertices[i] = decodeIndex(original_indices[i]);
}
geom->indices = original_indices;
to_old_indices.resize(original_indices.size());
iota(to_old_indices.begin(), to_old_indices.end(), 0);
2017-07-05 18:55:59 +02:00
}
2017-09-12 00:56:12 +02:00
geom->to_new_vertices.resize(vertices.size()); // some vertices can be unused, so this isn't necessarily the same size as to_old_vertices.
2017-07-10 18:15:14 +02:00
const int* to_old_vertices = geom->to_old_vertices.empty() ? nullptr : &geom->to_old_vertices[0];
for (int i = 0, c = (int)geom->to_old_vertices.size(); i < c; ++i)
{
int old = to_old_vertices[i];
add(geom->to_new_vertices[old], i);
}
2019-06-26 21:21:48 +02:00
}
2017-07-08 12:44:23 +02:00
2019-06-26 21:21:48 +02:00
static OptionalError<Object*> parseGeometryMaterials(
const std::unique_ptr<GeometryImpl>& geom,
const Element& element,
const std::vector<int>& original_indices)
{
2017-07-08 12:44:23 +02:00
const Element* layer_material_element = findChild(element, "LayerElementMaterial");
if (layer_material_element)
{
const Element* mapping_element = findChild(*layer_material_element, "MappingInformationType");
const Element* reference_element = findChild(*layer_material_element, "ReferenceInformationType");
std::vector<int> tmp;
2017-07-11 18:57:34 +02:00
if (!mapping_element || !reference_element) return Error("Invalid LayerElementMaterial");
2017-07-10 20:05:47 +02:00
if (mapping_element->first_property->value == "ByPolygon" &&
reference_element->first_property->value == "IndexToDirect")
2017-07-08 12:44:23 +02:00
{
geom->materials.reserve(geom->vertices.size() / 3);
for (int& i : geom->materials) i = -1;
const Element* indices_element = findChild(*layer_material_element, "Materials");
2017-07-11 18:57:34 +02:00
if (!indices_element || !indices_element->first_property) return Error("Invalid LayerElementMaterial");
2017-07-08 12:44:23 +02:00
2017-07-11 18:57:34 +02:00
if (!parseBinaryArray(*indices_element->first_property, &tmp)) return Error("Failed to parse material indices");
int tmp_i = 0;
for (int poly = 0, c = (int)tmp.size(); poly < c; ++poly)
{
int tri_count = getTriCountFromPoly(original_indices, &tmp_i);
for (int i = 0; i < tri_count; ++i)
2017-07-08 12:44:23 +02:00
{
2017-07-11 18:57:34 +02:00
geom->materials.push_back(tmp[poly]);
2017-07-08 12:44:23 +02:00
}
}
}
else
{
2017-07-11 18:57:34 +02:00
if (mapping_element->first_property->value != "AllSame") return Error("Mapping not supported");
2017-07-08 12:44:23 +02:00
}
2017-07-10 18:15:14 +02:00
}
2019-06-26 21:21:48 +02:00
return {nullptr};
}
2017-07-08 12:44:23 +02:00
2019-06-26 21:21:48 +02:00
static OptionalError<Object*> parseGeometryUVs(
const std::unique_ptr<GeometryImpl>& geom,
const Element& element,
const std::vector<int>& original_indices,
const std::vector<int>& to_old_indices)
{
2017-07-05 18:55:59 +02:00
const Element* layer_uv_element = findChild(element, "LayerElementUV");
2019-06-02 16:12:47 +02:00
while (layer_uv_element)
{
const int uv_index =
layer_uv_element->first_property ? layer_uv_element->first_property->getValue().toInt() : 0;
if (uv_index >= 0 && uv_index < Geometry::s_uvs_max)
{
std::vector<Vec2>& uvs = geom->uvs[uv_index];
std::vector<Vec2> tmp;
std::vector<int> tmp_indices;
GeometryImpl::VertexDataMapping mapping;
if (!parseVertexData(*layer_uv_element, "UV", "UVIndex", &tmp, &tmp_indices, &mapping))
return Error("Invalid UVs");
if (!tmp.empty() && (tmp_indices.empty() || tmp_indices[0] != -1))
{
uvs.resize(tmp_indices.empty() ? tmp.size() : tmp_indices.size());
splat(&uvs, mapping, tmp, tmp_indices, original_indices);
remap(&uvs, to_old_indices);
}
}
do
{
layer_uv_element = layer_uv_element->sibling;
} while (layer_uv_element && layer_uv_element->id != "LayerElementUV");
}
2019-06-26 21:21:48 +02:00
return {nullptr};
}
2017-07-05 18:55:59 +02:00
2019-06-26 21:21:48 +02:00
static OptionalError<Object*> parseGeometryTangents(
const std::unique_ptr<GeometryImpl>& geom,
const Element& element,
const std::vector<int>& original_indices,
const std::vector<int>& to_old_indices)
{
2017-07-05 18:55:59 +02:00
const Element* layer_tangent_element = findChild(element, "LayerElementTangents");
2019-06-30 16:26:49 +02:00
if (!layer_tangent_element ) {
layer_tangent_element = findChild(element, "LayerElementTangent");
}
layer_tangent_element = findChild(element, "LayerElementTangent");
2017-07-05 18:55:59 +02:00
if (layer_tangent_element)
{
std::vector<Vec3> tmp;
std::vector<int> tmp_indices;
GeometryImpl::VertexDataMapping mapping;
if (findChild(*layer_tangent_element, "Tangents"))
{
2019-06-02 16:12:47 +02:00
if (!parseVertexData(*layer_tangent_element, "Tangents", "TangentsIndex", &tmp, &tmp_indices, &mapping))
return Error("Invalid tangets");
2017-07-05 18:55:59 +02:00
}
else
{
2019-06-02 16:12:47 +02:00
if (!parseVertexData(*layer_tangent_element, "Tangent", "TangentIndex", &tmp, &tmp_indices, &mapping))
return Error("Invalid tangets");
2017-07-05 18:55:59 +02:00
}
2018-02-03 21:32:14 +01:00
if (!tmp.empty())
{
splat(&geom->tangents, mapping, tmp, tmp_indices, original_indices);
remap(&geom->tangents, to_old_indices);
}
2017-07-05 18:55:59 +02:00
}
2019-06-26 21:21:48 +02:00
return {nullptr};
}
2017-07-05 18:55:59 +02:00
2019-06-26 21:21:48 +02:00
static OptionalError<Object*> parseGeometryColors(
const std::unique_ptr<GeometryImpl>& geom,
const Element& element,
const std::vector<int>& original_indices,
const std::vector<int>& to_old_indices)
{
2017-07-05 18:55:59 +02:00
const Element* layer_color_element = findChild(element, "LayerElementColor");
if (layer_color_element)
{
std::vector<Vec4> tmp;
std::vector<int> tmp_indices;
GeometryImpl::VertexDataMapping mapping;
2019-06-02 16:12:47 +02:00
if (!parseVertexData(*layer_color_element, "Colors", "ColorIndex", &tmp, &tmp_indices, &mapping))
return Error("Invalid colors");
2018-02-03 21:32:14 +01:00
if (!tmp.empty())
{
splat(&geom->colors, mapping, tmp, tmp_indices, original_indices);
remap(&geom->colors, to_old_indices);
}
2017-07-05 18:55:59 +02:00
}
2019-06-26 21:21:48 +02:00
return {nullptr};
}
2017-07-05 18:55:59 +02:00
2019-06-26 21:21:48 +02:00
static OptionalError<Object*> parseGeometryNormals(
const std::unique_ptr<GeometryImpl>& geom,
const Element& element,
const std::vector<int>& original_indices,
const std::vector<int>& to_old_indices)
{
2017-07-05 18:55:59 +02:00
const Element* layer_normal_element = findChild(element, "LayerElementNormal");
if (layer_normal_element)
{
std::vector<Vec3> tmp;
std::vector<int> tmp_indices;
GeometryImpl::VertexDataMapping mapping;
2019-06-02 16:12:47 +02:00
if (!parseVertexData(*layer_normal_element, "Normals", "NormalsIndex", &tmp, &tmp_indices, &mapping))
return Error("Invalid normals");
2018-02-03 21:32:14 +01:00
if (!tmp.empty())
{
splat(&geom->normals, mapping, tmp, tmp_indices, original_indices);
remap(&geom->normals, to_old_indices);
}
2017-07-05 18:55:59 +02:00
}
2019-06-26 21:21:48 +02:00
return {nullptr};
}
static OptionalError<Object*> parseGeometry(const Scene& scene, const Element& element, bool triangulate)
{
assert(element.first_property);
const Element* vertices_element = findChild(element, "Vertices");
if (!vertices_element || !vertices_element->first_property)
{
return new GeometryImpl(scene, element);
}
const Element* polys_element = findChild(element, "PolygonVertexIndex");
if (!polys_element || !polys_element->first_property) return Error("Indices missing");
std::unique_ptr<GeometryImpl> geom(new GeometryImpl(scene, element));
std::vector<Vec3> vertices;
if (!parseDoubleVecData(*vertices_element->first_property, &vertices)) return Error("Failed to parse vertices");
std::vector<int> original_indices;
if (!parseBinaryArray(*polys_element->first_property, &original_indices)) return Error("Failed to parse indices");
std::vector<int> to_old_indices;
buildGeometryVertexData(geom, vertices, original_indices, to_old_indices, triangulate);
OptionalError<Object*> materialParsingError = parseGeometryMaterials(geom, element, original_indices);
if (materialParsingError.isError()) return materialParsingError;
OptionalError<Object*> uvParsingError = parseGeometryUVs(geom, element, original_indices, to_old_indices);
if (uvParsingError.isError()) return uvParsingError;
OptionalError<Object*> tangentsParsingError = parseGeometryTangents(geom, element, original_indices, to_old_indices);
if (tangentsParsingError.isError()) return tangentsParsingError;
OptionalError<Object*> colorsParsingError = parseGeometryColors(geom, element, original_indices, to_old_indices);
if (colorsParsingError.isError()) return colorsParsingError;
OptionalError<Object*> normalsParsingError = parseGeometryNormals(geom, element, original_indices, to_old_indices);
if (normalsParsingError.isError()) return normalsParsingError;
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
return geom.release();
}
static bool isString(const Property* prop)
{
if (!prop) return false;
return prop->getType() == Property::STRING;
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
static bool isLong(const Property* prop)
{
if (!prop) return false;
return prop->getType() == Property::LONG;
}
static bool parseConnections(const Element& root, Scene* scene)
2017-07-05 18:55:59 +02:00
{
assert(scene);
const Element* connections = findChild(root, "Connections");
2017-07-11 18:57:34 +02:00
if (!connections) return true;
2017-07-05 18:55:59 +02:00
const Element* connection = connections->child;
while (connection)
{
2017-07-11 18:57:34 +02:00
if (!isString(connection->first_property)
|| !isLong(connection->first_property->next)
|| !isLong(connection->first_property->next->next))
{
Error::s_message = "Invalid connection";
return false;
}
2017-07-05 18:55:59 +02:00
Scene::Connection c;
2018-02-04 11:28:25 +01:00
c.from = connection->first_property->next->value.toU64();
c.to = connection->first_property->next->next->value.toU64();
2017-07-05 18:55:59 +02:00
if (connection->first_property->value == "OO")
{
c.type = Scene::Connection::OBJECT_OBJECT;
}
else if (connection->first_property->value == "OP")
{
c.type = Scene::Connection::OBJECT_PROPERTY;
2017-07-11 18:57:34 +02:00
if (!connection->first_property->next->next->next)
{
Error::s_message = "Invalid connection";
return false;
}
2017-07-05 18:55:59 +02:00
c.property = connection->first_property->next->next->next->value;
}
else
{
assert(false);
2017-07-11 18:57:34 +02:00
Error::s_message = "Not supported";
return false;
2017-07-05 18:55:59 +02:00
}
scene->m_connections.push_back(c);
connection = connection->sibling;
}
2017-07-11 18:57:34 +02:00
return true;
2017-07-05 18:55:59 +02:00
}
2017-07-11 18:57:34 +02:00
static bool parseTakes(Scene* scene)
2017-07-05 18:55:59 +02:00
{
const Element* takes = findChild((const Element&)*scene->getRootElement(), "Takes");
2017-07-11 18:57:34 +02:00
if (!takes) return true;
2017-07-05 18:55:59 +02:00
const Element* object = takes->child;
while (object)
{
if (object->id == "Take")
{
2017-07-11 18:57:34 +02:00
if (!isString(object->first_property))
{
Error::s_message = "Invalid name in take";
return false;
}
2017-07-05 18:55:59 +02:00
TakeInfo take;
take.name = object->first_property->value;
const Element* filename = findChild(*object, "FileName");
2017-07-11 18:57:34 +02:00
if (filename)
{
if (!isString(filename->first_property))
{
Error::s_message = "Invalid filename in take";
return false;
}
take.filename = filename->first_property->value;
}
2017-07-05 18:55:59 +02:00
const Element* local_time = findChild(*object, "LocalTime");
if (local_time)
{
2017-07-11 18:57:34 +02:00
if (!isLong(local_time->first_property) || !isLong(local_time->first_property->next))
{
Error::s_message = "Invalid local time in take";
return false;
}
take.local_time_from = fbxTimeToSeconds(local_time->first_property->value.toI64());
take.local_time_to = fbxTimeToSeconds(local_time->first_property->next->value.toI64());
2017-07-05 18:55:59 +02:00
}
const Element* reference_time = findChild(*object, "ReferenceTime");
if (reference_time)
{
2017-07-11 18:57:34 +02:00
if (!isLong(reference_time->first_property) || !isLong(reference_time->first_property->next))
{
Error::s_message = "Invalid reference time in take";
return false;
}
take.reference_time_from = fbxTimeToSeconds(reference_time->first_property->value.toI64());
take.reference_time_to = fbxTimeToSeconds(reference_time->first_property->next->value.toI64());
2017-07-05 18:55:59 +02:00
}
scene->m_take_infos.push_back(take);
}
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
object = object->sibling;
}
2017-07-11 18:57:34 +02:00
return true;
2017-07-05 18:55:59 +02:00
}
2018-09-03 16:04:47 +02:00
static float getFramerateFromTimeMode(FrameRate time_mode, float custom_frame_rate)
2017-10-29 22:50:33 +01:00
{
switch (time_mode)
{
case FrameRate_DEFAULT: return 1;
case FrameRate_120: return 120;
case FrameRate_100: return 100;
case FrameRate_60: return 60;
case FrameRate_50: return 50;
case FrameRate_48: return 48;
case FrameRate_30: return 30;
case FrameRate_30_DROP: return 30;
case FrameRate_NTSC_DROP_FRAME: return 29.9700262f;
case FrameRate_NTSC_FULL_FRAME: return 29.9700262f;
case FrameRate_PAL: return 25;
case FrameRate_CINEMA: return 24;
case FrameRate_1000: return 1000;
case FrameRate_CINEMA_ND: return 23.976f;
2018-09-03 16:04:47 +02:00
case FrameRate_CUSTOM: return custom_frame_rate;
2017-10-29 22:50:33 +01:00
}
return -1;
}
static void parseGlobalSettings(const Element& root, Scene* scene)
{
for (Element* settings = root.child; settings; settings = settings->sibling)
2017-10-29 22:50:33 +01:00
{
if (settings->id == "GlobalSettings")
{
for (Element* props70 = settings->child; props70; props70 = props70->sibling)
2017-10-29 22:50:33 +01:00
{
if (props70->id == "Properties70")
{
for (Element* node = props70->child; node; node = node->sibling)
2017-10-29 22:50:33 +01:00
{
2018-09-03 16:04:47 +02:00
if (!node->first_property)
continue;
#define get_property(name, field, type, getter) if(node->first_property->value == name) \
2018-09-03 16:04:47 +02:00
{ \
IElementProperty* prop = node->getProperty(4); \
2018-09-03 16:04:47 +02:00
if (prop) \
{ \
DataView value = prop->getValue(); \
2019-06-02 16:12:47 +02:00
scene->m_settings.field = (type)value.getter(); \
2018-09-03 16:04:47 +02:00
} \
2017-10-29 22:50:33 +01:00
}
2018-09-03 16:04:47 +02:00
#define get_time_property(name, field, type, getter) if(node->first_property->value == name) \
{ \
IElementProperty* prop = node->getProperty(4); \
if (prop) \
{ \
DataView value = prop->getValue(); \
scene->m_settings.field = fbxTimeToSeconds((type)value.getter()); \
} \
}
2019-06-02 16:12:47 +02:00
get_property("UpAxis", UpAxis, UpVector, toInt);
get_property("UpAxisSign", UpAxisSign, int, toInt);
get_property("FrontAxis", FrontAxis, FrontVector, toInt);
get_property("FrontAxisSign", FrontAxisSign, int, toInt);
get_property("CoordAxis", CoordAxis, CoordSystem, toInt);
get_property("CoordAxisSign", CoordAxisSign, int, toInt);
get_property("OriginalUpAxis", OriginalUpAxis, int, toInt);
get_property("OriginalUpAxisSign", OriginalUpAxisSign, int, toInt);
get_property("UnitScaleFactor", UnitScaleFactor, float, toDouble);
get_property("OriginalUnitScaleFactor", OriginalUnitScaleFactor, float, toDouble);
get_time_property("TimeSpanStart", TimeSpanStart, u64, toU64);
get_time_property("TimeSpanStop", TimeSpanStop, u64, toU64);
2019-06-02 16:12:47 +02:00
get_property("TimeMode", TimeMode, FrameRate, toInt);
get_property("CustomFrameRate", CustomFrameRate, float, toDouble);
2018-09-03 16:04:47 +02:00
#undef get_property
2018-09-03 16:04:47 +02:00
scene->m_scene_frame_rate = getFramerateFromTimeMode(scene->m_settings.TimeMode, scene->m_settings.CustomFrameRate);
2017-10-29 22:50:33 +01:00
}
break;
}
}
break;
}
}
}
2019-07-07 16:58:18 +02:00
static bool parseObjects(const Element& root, Scene* scene, u64 flags)
2017-07-05 18:55:59 +02:00
{
2019-07-07 16:58:18 +02:00
const bool triangulate = (flags & (u64)LoadFlags::TRIANGULATE) != 0;
const bool ignore_geometry = (flags & (u64)LoadFlags::IGNORE_GEOMETRY) != 0;
2017-07-05 18:55:59 +02:00
const Element* objs = findChild(root, "Objects");
2017-07-11 18:57:34 +02:00
if (!objs) return true;
2017-07-05 18:55:59 +02:00
scene->m_root = new Root(*scene, root);
scene->m_root->id = 0;
scene->m_object_map[0] = {&root, scene->m_root};
const Element* object = objs->child;
while (object)
{
2017-07-11 18:57:34 +02:00
if (!isLong(object->first_property))
{
Error::s_message = "Invalid";
return false;
}
2017-07-05 19:43:01 +02:00
2018-02-04 11:28:25 +01:00
u64 id = object->first_property->value.toU64();
2017-07-05 19:43:01 +02:00
scene->m_object_map[id] = {object, nullptr};
2017-07-05 18:55:59 +02:00
object = object->sibling;
}
for (auto iter : scene->m_object_map)
{
2017-07-11 18:57:34 +02:00
OptionalError<Object*> obj = nullptr;
2017-07-05 18:55:59 +02:00
if (iter.second.object == scene->m_root) continue;
if (iter.second.element->id == "Geometry")
{
2017-07-05 19:43:01 +02:00
Property* last_prop = iter.second.element->first_property;
while (last_prop->next) last_prop = last_prop->next;
2019-07-07 16:58:18 +02:00
if (last_prop && last_prop->value == "Mesh" && !ignore_geometry)
2017-07-05 18:55:59 +02:00
{
2019-06-26 21:21:48 +02:00
obj = parseGeometry(*scene, *iter.second.element, triangulate);
2017-07-05 18:55:59 +02:00
}
}
else if (iter.second.element->id == "Material")
{
obj = parseMaterial(*scene, *iter.second.element);
}
else if (iter.second.element->id == "AnimationStack")
{
2017-07-11 18:57:34 +02:00
obj = parse<AnimationStackImpl>(*scene, *iter.second.element);
if (!obj.isError())
{
AnimationStackImpl* stack = (AnimationStackImpl*)obj.getValue();
scene->m_animation_stacks.push_back(stack);
}
2017-07-05 18:55:59 +02:00
}
else if (iter.second.element->id == "AnimationLayer")
{
obj = parse<AnimationLayerImpl>(*scene, *iter.second.element);
}
else if (iter.second.element->id == "AnimationCurve")
{
obj = parseAnimationCurve(*scene, *iter.second.element);
}
else if (iter.second.element->id == "AnimationCurveNode")
{
obj = parse<AnimationCurveNodeImpl>(*scene, *iter.second.element);
}
else if (iter.second.element->id == "Deformer")
{
IElementProperty* class_prop = iter.second.element->getProperty(2);
if (class_prop)
{
if (class_prop->getValue() == "Cluster")
obj = parseCluster(*scene, *iter.second.element);
else if (class_prop->getValue() == "Skin")
obj = parse<SkinImpl>(*scene, *iter.second.element);
}
}
else if (iter.second.element->id == "NodeAttribute")
{
obj = parseNodeAttribute(*scene, *iter.second.element);
}
else if (iter.second.element->id == "Model")
{
IElementProperty* class_prop = iter.second.element->getProperty(2);
if (class_prop)
{
if (class_prop->getValue() == "Mesh")
2017-07-06 18:49:04 +02:00
{
2017-07-11 18:57:34 +02:00
obj = parseMesh(*scene, *iter.second.element);
if (!obj.isError())
{
Mesh* mesh = (Mesh*)obj.getValue();
scene->m_meshes.push_back(mesh);
obj = mesh;
}
2017-07-06 18:49:04 +02:00
}
2017-07-05 18:55:59 +02:00
else if (class_prop->getValue() == "LimbNode")
obj = parseLimbNode(*scene, *iter.second.element);
2018-10-28 21:05:49 +01:00
else
obj = parse<NullImpl>(*scene, *iter.second.element);
2017-07-05 18:55:59 +02:00
}
}
else if (iter.second.element->id == "Texture")
{
obj = parseTexture(*scene, *iter.second.element);
}
else if (iter.second.element->id == "Pose")
{
obj = parsePose(*scene, *iter.second.element);
}
2017-07-05 18:55:59 +02:00
2017-07-11 18:57:34 +02:00
if (obj.isError()) return false;
scene->m_object_map[iter.first].object = obj.getValue();
if (obj.getValue())
2017-07-09 17:56:16 +02:00
{
2017-07-11 18:57:34 +02:00
scene->m_all_objects.push_back(obj.getValue());
obj.getValue()->id = iter.first;
2017-07-09 17:56:16 +02:00
}
2017-07-05 18:55:59 +02:00
}
2017-07-10 16:45:32 +02:00
for (const Scene::Connection& con : scene->m_connections)
{
Object* parent = scene->m_object_map[con.to].object;
Object* child = scene->m_object_map[con.from].object;
if (!child) continue;
2017-07-12 18:09:40 +02:00
if (!parent) continue;
2017-07-10 19:49:03 +02:00
2017-07-11 20:33:32 +02:00
switch (child->getType())
2017-07-10 19:49:03 +02:00
{
2017-07-11 20:33:32 +02:00
case Object::Type::NODE_ATTRIBUTE:
if (parent->node_attribute)
{
Error::s_message = "Invalid node attribute";
return false;
}
parent->node_attribute = (NodeAttribute*)child;
break;
case Object::Type::ANIMATION_CURVE_NODE:
if (parent->isNode())
{
AnimationCurveNodeImpl* node = (AnimationCurveNodeImpl*)child;
node->bone = parent;
node->bone_link_property = con.property;
}
break;
2017-07-10 19:49:03 +02:00
}
2017-07-10 16:45:32 +02:00
switch (parent->getType())
{
case Object::Type::MESH:
{
MeshImpl* mesh = (MeshImpl*)parent;
switch (child->getType())
{
case Object::Type::GEOMETRY:
2017-07-11 18:57:34 +02:00
if (mesh->geometry)
{
Error::s_message = "Invalid mesh";
return false;
}
2017-07-10 16:45:32 +02:00
mesh->geometry = (Geometry*)child;
break;
2017-07-10 20:05:47 +02:00
case Object::Type::MATERIAL: mesh->materials.push_back((Material*)child); break;
2017-07-10 16:45:32 +02:00
}
break;
}
case Object::Type::SKIN:
{
SkinImpl* skin = (SkinImpl*)parent;
if (child->getType() == Object::Type::CLUSTER)
{
ClusterImpl* cluster = (ClusterImpl*)child;
skin->clusters.push_back(cluster);
2017-07-11 18:57:34 +02:00
if (cluster->skin)
{
Error::s_message = "Invalid cluster";
return false;
}
2017-07-10 16:45:32 +02:00
cluster->skin = skin;
}
break;
}
case Object::Type::MATERIAL:
{
MaterialImpl* mat = (MaterialImpl*)parent;
if (child->getType() == Object::Type::TEXTURE)
{
Texture::TextureType type = Texture::COUNT;
2017-07-10 20:05:47 +02:00
if (con.property == "NormalMap")
type = Texture::NORMAL;
else if (con.property == "DiffuseColor")
type = Texture::DIFFUSE;
2019-06-26 21:21:48 +02:00
else if (con.property == "SpecularColor")
type = Texture::SPECULAR;
2017-07-10 16:45:32 +02:00
if (type == Texture::COUNT) break;
2017-07-11 18:57:34 +02:00
if (mat->textures[type])
{
2019-06-02 16:12:47 +02:00
break; // This may happen for some models (eg. 2 normal maps in use)
2017-07-11 18:57:34 +02:00
}
2017-07-10 16:45:32 +02:00
mat->textures[type] = (Texture*)child;
}
break;
}
case Object::Type::GEOMETRY:
{
GeometryImpl* geom = (GeometryImpl*)parent;
if (child->getType() == Object::Type::SKIN) geom->skin = (Skin*)child;
break;
}
case Object::Type::CLUSTER:
{
ClusterImpl* cluster = (ClusterImpl*)parent;
if (child->getType() == Object::Type::LIMB_NODE || child->getType() == Object::Type::MESH || child->getType() == Object::Type::NULL_NODE)
2017-07-10 16:45:32 +02:00
{
2019-06-02 16:12:47 +02:00
if (cluster->link && cluster->link != child)
2017-07-11 18:57:34 +02:00
{
Error::s_message = "Invalid cluster";
return false;
}
2017-07-10 16:45:32 +02:00
cluster->link = child;
}
break;
}
2017-07-11 20:33:32 +02:00
case Object::Type::ANIMATION_LAYER:
{
if (child->getType() == Object::Type::ANIMATION_CURVE_NODE)
{
((AnimationLayerImpl*)parent)->curve_nodes.push_back((AnimationCurveNodeImpl*)child);
}
}
break;
2017-07-10 16:45:32 +02:00
case Object::Type::ANIMATION_CURVE_NODE:
{
AnimationCurveNodeImpl* node = (AnimationCurveNodeImpl*)parent;
if (child->getType() == Object::Type::ANIMATION_CURVE)
{
2019-07-21 22:20:59 +02:00
char tmp[32];
con.property.toString(tmp);
if (strcmp(tmp, "d|X") == 0)
2017-07-10 16:45:32 +02:00
{
node->curves[0].connection = &con;
node->curves[0].curve = (AnimationCurve*)child;
}
2019-07-21 22:20:59 +02:00
else if (strcmp(tmp, "d|Y") == 0)
2017-07-10 16:45:32 +02:00
{
node->curves[1].connection = &con;
node->curves[1].curve = (AnimationCurve*)child;
}
2019-07-21 22:20:59 +02:00
else if (strcmp(tmp, "d|Z") == 0)
2017-07-10 16:45:32 +02:00
{
node->curves[2].connection = &con;
node->curves[2].curve = (AnimationCurve*)child;
}
}
break;
}
}
}
if (!ignore_geometry) {
for (auto iter : scene->m_object_map)
2017-07-05 18:55:59 +02:00
{
Object* obj = iter.second.object;
if (!obj) continue;
switch (obj->getType()) {
case Object::Type::CLUSTER:
if (!((ClusterImpl*)iter.second.object)->postprocess()) {
Error::s_message = "Failed to postprocess cluster";
return false;
}
break;
case Object::Type::POSE:
if (!((PoseImpl*)iter.second.object)->postprocess(scene)) {
Error::s_message = "Failed to postprocess pose";
return false;
}
break;
2017-11-28 19:37:15 +01:00
}
2017-07-05 18:55:59 +02:00
}
}
2017-07-11 18:57:34 +02:00
return true;
2017-07-05 18:55:59 +02:00
}
RotationOrder Object::getRotationOrder() const
{
// This assumes that the default rotation order is EULER_XYZ.
return (RotationOrder) resolveEnumProperty(*this, "RotationOrder", (int) RotationOrder::EULER_XYZ);
}
2017-07-05 18:55:59 +02:00
Vec3 Object::getRotationOffset() const
{
return resolveVec3Property(*this, "RotationOffset", {0, 0, 0});
}
Vec3 Object::getRotationPivot() const
{
return resolveVec3Property(*this, "RotationPivot", {0, 0, 0});
}
Vec3 Object::getPostRotation() const
{
return resolveVec3Property(*this, "PostRotation", {0, 0, 0});
}
Vec3 Object::getScalingOffset() const
{
return resolveVec3Property(*this, "ScalingOffset", {0, 0, 0});
}
Vec3 Object::getScalingPivot() const
{
return resolveVec3Property(*this, "ScalingPivot", {0, 0, 0});
}
2017-07-06 21:21:48 +02:00
Matrix Object::evalLocal(const Vec3& translation, const Vec3& rotation) const
2017-07-05 18:55:59 +02:00
{
2018-09-03 16:04:47 +02:00
return evalLocal(translation, rotation, getLocalScaling());
}
Matrix Object::evalLocal(const Vec3& translation, const Vec3& rotation, const Vec3& scaling) const
{
2017-07-05 18:55:59 +02:00
Vec3 rotation_pivot = getRotationPivot();
Vec3 scaling_pivot = getScalingPivot();
RotationOrder rotation_order = getRotationOrder();
2017-07-05 18:55:59 +02:00
Matrix s = makeIdentity();
s.m[0] = scaling.x;
s.m[5] = scaling.y;
s.m[10] = scaling.z;
Matrix t = makeIdentity();
setTranslation(translation, &t);
Matrix r = getRotationMatrix(rotation, rotation_order);
Matrix r_pre = getRotationMatrix(getPreRotation(), RotationOrder::EULER_XYZ);
2017-09-12 00:56:12 +02:00
Matrix r_post_inv = getRotationMatrix(-getPostRotation(), RotationOrder::EULER_ZYX);
2017-07-05 18:55:59 +02:00
Matrix r_off = makeIdentity();
setTranslation(getRotationOffset(), &r_off);
Matrix r_p = makeIdentity();
setTranslation(rotation_pivot, &r_p);
Matrix r_p_inv = makeIdentity();
setTranslation(-rotation_pivot, &r_p_inv);
Matrix s_off = makeIdentity();
setTranslation(getScalingOffset(), &s_off);
Matrix s_p = makeIdentity();
setTranslation(scaling_pivot, &s_p);
Matrix s_p_inv = makeIdentity();
setTranslation(-scaling_pivot, &s_p_inv);
// http://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm
return t * r_off * r_p * r_pre * r * r_post_inv * r_p_inv * s_off * s_p * s * s_p_inv;
}
Vec3 Object::getLocalTranslation() const
{
2017-07-05 19:43:01 +02:00
return resolveVec3Property(*this, "Lcl Translation", {0, 0, 0});
2017-07-05 18:55:59 +02:00
}
Vec3 Object::getPreRotation() const
{
2017-07-05 19:43:01 +02:00
return resolveVec3Property(*this, "PreRotation", {0, 0, 0});
2017-07-05 18:55:59 +02:00
}
Vec3 Object::getLocalRotation() const
{
return resolveVec3Property(*this, "Lcl Rotation", {0, 0, 0});
}
Vec3 Object::getLocalScaling() const
{
return resolveVec3Property(*this, "Lcl Scaling", {1, 1, 1});
}
Matrix Object::getGlobalTransform() const
{
const Object* parent = getParent();
if (!parent) return evalLocal(getLocalTranslation(), getLocalRotation());
2017-07-05 19:43:01 +02:00
2017-07-05 18:55:59 +02:00
return parent->getGlobalTransform() * evalLocal(getLocalTranslation(), getLocalRotation());
}
2018-09-03 16:04:47 +02:00
Matrix Object::getLocalTransform() const
{
2019-06-02 16:12:47 +02:00
return evalLocal(getLocalTranslation(), getLocalRotation(), getLocalScaling());
2018-09-03 16:04:47 +02:00
}
2017-07-05 18:55:59 +02:00
Object* Object::resolveObjectLinkReverse(Object::Type type) const
{
2018-02-04 11:28:25 +01:00
u64 id = element.getFirstProperty() ? element.getFirstProperty()->getValue().toU64() : 0;
2017-07-05 18:55:59 +02:00
for (auto& connection : scene.m_connections)
{
if (connection.from == id && connection.to != 0)
{
const Scene::ObjectPair& pair = scene.m_object_map.find(connection.to)->second;
Object* obj = pair.object;
2017-07-05 18:55:59 +02:00
if (obj && obj->getType() == type) return obj;
}
}
return nullptr;
}
2017-07-05 19:43:01 +02:00
const IScene& Object::getScene() const
2017-07-05 18:55:59 +02:00
{
return scene;
}
Object* Object::resolveObjectLink(int idx) const
{
2018-02-04 11:28:25 +01:00
u64 id = element.getFirstProperty() ? element.getFirstProperty()->getValue().toU64() : 0;
2017-07-05 18:55:59 +02:00
for (auto& connection : scene.m_connections)
{
if (connection.to == id && connection.from != 0)
{
Object* obj = scene.m_object_map.find(connection.from)->second.object;
if (obj)
{
if (idx == 0) return obj;
--idx;
}
}
}
return nullptr;
}
Object* Object::resolveObjectLink(Object::Type type, const char* property, int idx) const
{
2018-02-04 11:28:25 +01:00
u64 id = element.getFirstProperty() ? element.getFirstProperty()->getValue().toU64() : 0;
2017-07-05 18:55:59 +02:00
for (auto& connection : scene.m_connections)
{
if (connection.to == id && connection.from != 0)
{
Object* obj = scene.m_object_map.find(connection.from)->second.object;
if (obj && obj->getType() == type)
{
if (property == nullptr || connection.property == property)
{
if (idx == 0) return obj;
--idx;
}
}
}
}
return nullptr;
}
Object* Object::getParent() const
{
Object* parent = nullptr;
for (auto& connection : scene.m_connections)
{
if (connection.from == id && connection.from != connection.to)
2017-07-05 18:55:59 +02:00
{
Object* obj = scene.m_object_map.find(connection.to)->second.object;
if (obj && obj->is_node)
{
assert(parent == nullptr);
parent = obj;
}
}
}
return parent;
}
2019-07-07 16:58:18 +02:00
IScene* load(const u8* data, int size, u64 flags)
2017-07-05 18:55:59 +02:00
{
2018-10-16 21:28:03 +02:00
std::unique_ptr<Scene> scene(new Scene());
2017-07-05 18:55:59 +02:00
scene->m_data.resize(size);
memcpy(&scene->m_data[0], data, size);
2019-06-02 16:12:47 +02:00
u32 version;
2019-11-23 23:37:49 +01:00
const bool is_binary = size >= 18 && strncmp((const char*)data, "Kaydara FBX Binary", 18) == 0;
OptionalError<Element*> root(nullptr);
if (is_binary) {
root = tokenize(&scene->m_data[0], size, version);
if (version < 6200)
{
Error::s_message = "Unsupported FBX file format version. Minimum supported version is 6.2";
return nullptr;
}
if (root.isError())
{
Error::s_message = "";
if (root.isError()) return nullptr;
}
2019-06-02 16:12:47 +02:00
}
2019-11-23 23:37:49 +01:00
else {
2017-08-30 00:08:16 +02:00
root = tokenizeText(&scene->m_data[0], size);
if (root.isError()) return nullptr;
}
2017-07-11 18:57:34 +02:00
2017-07-07 18:22:17 +02:00
scene->m_root_element = root.getValue();
2017-07-11 18:57:34 +02:00
assert(scene->m_root_element);
2019-06-02 16:12:47 +02:00
// if (parseTemplates(*root.getValue()).isError()) return nullptr;
if (!parseConnections(*root.getValue(), scene.get())) return nullptr;
if (!parseTakes(scene.get())) return nullptr;
2019-07-07 16:58:18 +02:00
if (!parseObjects(*root.getValue(), scene.get(), flags)) return nullptr;
2017-10-29 22:50:33 +01:00
parseGlobalSettings(*root.getValue(), scene.get());
2017-07-11 18:57:34 +02:00
return scene.release();
2017-07-05 18:55:59 +02:00
}
2017-07-07 18:10:32 +02:00
const char* getError()
{
return Error::s_message;
}
2017-07-05 18:55:59 +02:00
} // namespace ofbx