Merge pull request #47880 from RevoluPowered/fix-fbx-parser

FBX Improve Parser and File Compatibility
This commit is contained in:
Rémi Verschelde 2021-04-16 08:41:46 +02:00 committed by GitHub
commit 88015f4e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 221 additions and 375 deletions

View File

@ -277,7 +277,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
}
/// ALL below is related to properties
for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) {
for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) {
const std::string name = iter.first;
if (name.empty()) {
@ -317,7 +317,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
const FBXDocParser::PropertyTable *tbl = material->Props();
const FBXDocParser::PropertyTable *tbl = material;
FBXDocParser::PropertyPtr prop = tbl->Get(name);
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));

View File

@ -101,20 +101,6 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
return collection;
}
typedef int Vertex;
typedef int SurfaceId;
typedef int PolygonId;
typedef int DataIndex;
struct SurfaceData {
Ref<SurfaceTool> surface_tool;
OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
Ref<Material> material;
HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
Array morphs;
};
EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
mesh_geometry = p_mesh_geometry;
// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
@ -307,11 +293,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
// Triangulate the various polygons and add the indices.
for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) {
const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id);
triangulate_polygon(
surface->surface_tool,
surface,
*indices,
surface->vertices_map,
vertices);
}
}
@ -336,7 +320,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
morph_st->begin(Mesh::PRIMITIVE_TRIANGLES);
for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) {
const Vertex vertex = surface->vertices_map[vi];
const Vertex &vertex = surface->vertices_map[vi];
add_vertex(
state,
morph_st,
@ -398,6 +382,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
godot_mesh->set_mesh(mesh);
const String name = ImportUtils::FBXNodeToName(model->Name());
godot_mesh->set_name(name); // hurry up compiling >.<
mesh->set_name("mesh3d-" + name);
return godot_mesh;
}
@ -816,8 +803,10 @@ void FBXMeshData::add_vertex(
p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale);
}
void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, const Vector<Vertex> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const {
void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const {
Ref<SurfaceTool> st(surface->surface_tool);
const int polygon_vertex_count = p_polygon_vertex.size();
//const Vector<Vertex>& p_surface_vertex_map
if (polygon_vertex_count == 1) {
// point to triangle
st->add_index(p_polygon_vertex[0]);
@ -856,9 +845,9 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
is_simple_convex = true;
Vector3 first_vec;
for (int i = 0; i < polygon_vertex_count; i += 1) {
const Vector3 p1 = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
const Vector3 edge1 = p1 - p2;
const Vector3 edge2 = p3 - p2;
@ -893,7 +882,7 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
std::vector<Vector3> poly_vertices(polygon_vertex_count);
for (int i = 0; i < polygon_vertex_count; i += 1) {
poly_vertices[i] = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
}
const Vector3 poly_norm = get_poly_normal(poly_vertices);

View File

@ -32,6 +32,8 @@
#define FBX_MESH_DATA_H
#include "core/templates/hash_map.h"
#include "core/templates/local_vector.h"
#include "core/templates/ordered_hash_map.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@ -47,6 +49,20 @@ struct FBXMeshData;
struct FBXBone;
struct ImportState;
typedef int Vertex;
typedef int SurfaceId;
typedef int PolygonId;
typedef int DataIndex;
struct SurfaceData {
Ref<SurfaceTool> surface_tool;
OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
Ref<Material> material;
HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
Array morphs;
};
struct VertexWeightMapping {
Vector<real_t> weights;
Vector<int> bones;
@ -127,7 +143,7 @@ private:
const Vector3 &p_morph_value = Vector3(),
const Vector3 &p_morph_normal = Vector3());
void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const;
void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const;
/// This function is responsible to convert the FBX polygon vertex to
/// vertex index.

View File

@ -33,7 +33,7 @@
#include "tools/import_utils.h"
void PivotTransform::ReadTransformChain() {
const FBXDocParser::PropertyTable *props = fbx_model->Props();
const FBXDocParser::PropertyTable *props = fbx_model;
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
inherit_type = inheritType; // copy the inherit type we need it in the second step.

View File

@ -44,7 +44,6 @@
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/node.h"
#include "scene/resources/material.h"
@ -121,15 +120,27 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
print_verbose("[doc] opening fbx file: " + p_path);
print_verbose("[doc] fbx header: " + fbx_header_string);
bool corrupt = false;
// safer to check this way as there can be different formatted headers
if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) {
is_binary = true;
print_verbose("[doc] is binary");
FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size());
FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
} else {
print_verbose("[doc] is ascii");
FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size());
FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
}
if (corrupt) {
for (FBXDocParser::TokenPtr token : tokens) {
delete token;
}
tokens.clear();
ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
return memnew(Node3D);
}
// The import process explained:
@ -141,6 +152,16 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure
FBXDocParser::Parser parser(tokens, is_binary);
if (parser.IsCorrupt()) {
for (FBXDocParser::TokenPtr token : tokens) {
delete token;
}
tokens.clear();
ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
return memnew(Node3D);
}
FBXDocParser::ImportSettings settings;
settings.strictMode = false;
@ -153,12 +174,10 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// safety for version handling
if (doc.IsSafeToImport()) {
bool is_blender_fbx = false;
//const FBXDocParser::PropertyPtr app_vendor = p_document->GlobalSettingsPtr()->Props()
// p_document->Creator()
const FBXDocParser::PropertyTable *import_props = doc.GetMetadataProperties();
const FBXDocParser::PropertyPtr app_name = import_props->Get("Original|ApplicationName");
const FBXDocParser::PropertyPtr app_vendor = import_props->Get("Original|ApplicationVendor");
const FBXDocParser::PropertyPtr app_version = import_props->Get("Original|ApplicationVersion");
const FBXDocParser::PropertyTable &import_props = doc.GetMetadataProperties();
const FBXDocParser::PropertyPtr app_name = import_props.Get("Original|ApplicationName");
const FBXDocParser::PropertyPtr app_vendor = import_props.Get("Original|ApplicationVendor");
const FBXDocParser::PropertyPtr app_version = import_props.Get("Original|ApplicationVersion");
//
if (app_name) {
const FBXDocParser::TypedProperty<std::string> *app_name_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_name);
@ -200,6 +219,11 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
return spatial;
} else {
for (FBXDocParser::TokenPtr token : tokens) {
delete token;
}
tokens.clear();
ERR_PRINT(vformat("Cannot import FBX file: %s. It uses file format %d which is unsupported by Godot. Please re-export it or convert it to a newer format.", p_path, doc.FBXVersion()));
}
}
@ -892,7 +916,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
uint64_t target_id = target->ID();
String target_name = ImportUtils::FBXNodeToName(target->Name());
const FBXDocParser::PropertyTable *properties = curve_node->Props();
const FBXDocParser::PropertyTable *properties = curve_node;
bool got_x = false, got_y = false, got_z = false;
float offset_x = FBXDocParser::PropertyGet<float>(properties, "d|X", got_x);
float offset_y = FBXDocParser::PropertyGet<float>(properties, "d|Y", got_y);
@ -1047,7 +1071,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
Ref<FBXNode> target_node = state.fbx_target_map[target_id];
const FBXDocParser::Model *model = target_node->fbx_model;
const FBXDocParser::PropertyTable *props = model->Props();
const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model);
Map<StringName, FBXTrack> &track_data = track->value();
FBXTrack &translation_keys = track_data[StringName("T")];

View File

@ -130,9 +130,7 @@ AnimationCurve::~AnimationCurve() {
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
size_t whitelist_size /*= 0*/) :
Object(id, element, name), doc(doc) {
const ScopePtr sc = GetRequiredScope(element);
Object(id, element, name), target(), doc(doc) {
// find target node
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
@ -154,8 +152,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co
prop = con->PropertyName();
break;
}
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
}
// ------------------------------------------------------------------------------------------------
@ -187,10 +183,6 @@ const AnimationMap &AnimationCurveNode::Curves() const {
// ------------------------------------------------------------------------------------------------
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name), doc(doc) {
const ScopePtr sc = GetRequiredScope(element);
// note: the props table here bears little importance and is usually absent
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@ -248,11 +240,6 @@ const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_pro
// ------------------------------------------------------------------------------------------------
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name) {
const ScopePtr sc = GetRequiredScope(element);
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
// resolve attached animation layers
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
layers.reserve(conns.size());
@ -282,9 +269,5 @@ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std:
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack() {
if (props != nullptr) {
delete props;
props = nullptr;
}
}
} // namespace FBXDocParser

View File

@ -130,6 +130,7 @@ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset
line(offset),
column(BINARY_MARKER) {
#ifdef DEBUG_ENABLED
// contents is bad.. :/
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
#endif
// calc length
@ -232,9 +233,11 @@ unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const ch
}
// ------------------------------------------------------------------------------------------------
void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) {
void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) {
if (Offset(cursor, end) < 1) {
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
corrupt = true;
return;
}
const char type = *cursor;
@ -328,9 +331,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
cursor += comp_len;
break;
}
// string
} // string
case 'S': {
const char *sb, *se;
// 0 characters can legally happen in such strings
@ -338,11 +339,15 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
break;
}
default:
corrupt = true; // must exit
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
return;
}
if (cursor > end) {
corrupt = true; // must exit
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
return;
}
// the type code is contained in the returned range
@ -350,7 +355,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
// ------------------------------------------------------------------------------------------------
bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) {
bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) {
// the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@ -364,8 +369,12 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (end_offset > Offset(input, end)) {
TokenizeError("block offset is out of range", input, cursor);
corrupt = true;
return false;
} else if (end_offset < Offset(input, cursor)) {
TokenizeError("block offset is negative out of range", input, cursor);
corrupt = true;
return false;
}
// the second data word contains the number of properties in the scope
@ -375,7 +384,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
// now comes the name of the scope/key
const char *sbeg, *send;
const char *sbeg = nullptr, *send = nullptr;
ReadString(sbeg, send, input, cursor, end);
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
@ -383,7 +392,10 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// now come the individual properties
const char *begin_cursor = cursor;
for (unsigned int i = 0; i < prop_count; ++i) {
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt);
if (corrupt) {
return false;
}
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
@ -394,6 +406,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(begin_cursor, cursor) != prop_length) {
TokenizeError("property length not reached, something is wrong", input, cursor);
corrupt = true;
return false;
}
// at the end of each nested block, there is a NUL record to indicate
@ -410,13 +424,18 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// XXX this is vulnerable to stack overflowing ..
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt);
if (corrupt) {
return false;
}
}
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
if (cursor[i] != '\0') {
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
corrupt = true;
return false;
}
}
cursor += sentinel_block_length;
@ -424,6 +443,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(input, cursor) != end_offset) {
TokenizeError("scope length not reached, something is wrong", input, cursor);
corrupt = true;
return false;
}
return true;
@ -432,7 +453,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) {
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
if (length < 0x1b) {
//TokenizeError("file is too short",0);
}
@ -459,7 +480,7 @@ void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length)
const bool is64bits = version >= 7500;
const char *end = input + length;
while (cursor < end) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) {
break;
}
}

View File

@ -89,10 +89,6 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
const ScopePtr sc = GetRequiredScope(element);
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@ -101,10 +97,6 @@ Deformer::~Deformer() {
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
const ScopePtr sc = GetRequiredScope(element);
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
// used something.fbx as this is a cache name.
props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
}
Constraint::~Constraint() {

View File

@ -228,7 +228,7 @@ ObjectPtr LazyObject::LoadObject() {
// ------------------------------------------------------------------------------------------------
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
element(element), name(name), id(id) {
PropertyTable(element), element(element), name(name), id(id) {
}
// ------------------------------------------------------------------------------------------------
@ -237,17 +237,13 @@ Object::~Object() {
}
// ------------------------------------------------------------------------------------------------
FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
props(props), doc(doc) {
FileGlobalSettings::FileGlobalSettings(const Document &doc) :
PropertyTable(), doc(doc) {
// empty
}
// ------------------------------------------------------------------------------------------------
FileGlobalSettings::~FileGlobalSettings() {
if (props != nullptr) {
delete props;
props = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
@ -287,15 +283,12 @@ Document::~Document() {
delete v.second;
}
if (metadata_properties != nullptr) {
delete metadata_properties;
}
// clear globals import pointer
globals.reset();
}
// ------------------------------------------------------------------------------------------------
static const unsigned int LowerSupportedVersion = 7300;
static const unsigned int LowerSupportedVersion = 7100;
static const unsigned int UpperSupportedVersion = 7700;
bool Document::ReadHeader() {
@ -306,6 +299,11 @@ bool Document::ReadHeader() {
DOMError("no FBXHeaderExtension dictionary found");
}
if (parser.IsCorrupt()) {
DOMError("File is corrupt");
return false;
}
const ScopePtr shead = ehead->Compound();
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
@ -325,18 +323,11 @@ bool Document::ReadHeader() {
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
}
//
// Scene Info
//
const ElementPtr scene_info = shead->GetElement("SceneInfo");
if (scene_info) {
PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true));
if (fileExportProps) {
metadata_properties = fileExportProps;
}
metadata_properties.Setup(scene_info);
}
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
@ -358,23 +349,7 @@ bool Document::ReadHeader() {
void Document::ReadGlobalSettings() {
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
const ScopePtr sc = parser.GetRootScope();
const ElementPtr ehead = sc->GetElement("GlobalSettings");
if (nullptr == ehead || !ehead->Compound()) {
DOMWarning("no GlobalSettings dictionary found");
globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
return;
}
const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
//double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
if (!props) {
DOMError("GlobalSettings dictionary contains no property table");
}
globals = std::make_shared<FileGlobalSettings>(*this, props);
globals = std::make_shared<FileGlobalSettings>(*this);
}
// ------------------------------------------------------------------------------------------------
@ -445,58 +420,6 @@ void Document::ReadObjects() {
// ------------------------------------------------------------------------------------------------
void Document::ReadPropertyTemplates() {
const ScopePtr sc = parser.GetRootScope();
// read property templates from "Definitions" section
const ElementPtr edefs = sc->GetElement("Definitions");
if (!edefs || !edefs->Compound()) {
DOMWarning("no Definitions dictionary found");
return;
}
const ScopePtr sdefs = edefs->Compound();
const ElementCollection otypes = sdefs->GetCollection("ObjectType");
for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
const ElementPtr el = (*it).second;
const ScopePtr sc_2 = el->Compound();
if (!sc_2) {
DOMWarning("expected nested scope in ObjectType, ignoring", el);
continue;
}
const TokenList &tok = el->Tokens();
if (tok.empty()) {
DOMWarning("expected name for ObjectType element, ignoring", el);
continue;
}
const std::string &oname = ParseTokenAsString(tok[0]);
const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
const ElementPtr el_2 = (*iter).second;
const ScopePtr sc_3 = el_2->Compound();
if (!sc_3) {
DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
continue;
}
const TokenList &tok_2 = el_2->Tokens();
if (tok_2.empty()) {
DOMWarning("expected name for PropertyTemplate element, ignoring", el);
continue;
}
const std::string &pname = ParseTokenAsString(tok_2[0]);
const ElementPtr Properties70 = sc_3->GetElement("Properties70");
if (Properties70) {
// PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
const PropertyTable *props = new PropertyTable(Properties70, nullptr);
templates[oname + "." + pname] = props;
}
}
}
}
// ------------------------------------------------------------------------------------------------

View File

@ -130,7 +130,7 @@ private:
};
/** Base class for in-memory (DOM) representations of FBX objects */
class Object {
class Object : public PropertyTable {
public:
Object(uint64_t id, const ElementPtr element, const std::string &name);
@ -149,9 +149,9 @@ public:
}
protected:
const ElementPtr element;
const ElementPtr element = nullptr;
const std::string name;
const uint64_t id = 0;
const uint64_t id;
};
/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table,
@ -159,22 +159,13 @@ protected:
class NodeAttribute : public Object {
public:
NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~NodeAttribute();
const PropertyTable *Props() const {
return props;
}
private:
const PropertyTable *props;
};
/** DOM base class for FBX camera settings attached to a node */
class CameraSwitcher : public NodeAttribute {
public:
CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~CameraSwitcher();
int CameraID() const {
@ -190,26 +181,26 @@ public:
}
private:
int cameraId;
int cameraId = 0;
std::string cameraName;
std::string cameraIndexName;
};
#define fbx_stringize(a) #a
#define fbx_simple_property(name, type, default_value) \
type name() const { \
return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
#define fbx_simple_property(name, type, default_value) \
type name() const { \
return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \
}
// XXX improve logging
#define fbx_simple_enum_property(name, type, default_value) \
type name() const { \
const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
return static_cast<type>(default_value); \
} \
return static_cast<type>(ival); \
#define fbx_simple_enum_property(name, type, default_value) \
type name() const { \
const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \
if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
return static_cast<type>(default_value); \
} \
return static_cast<type>(ival); \
}
class FbxPoseNode;
@ -256,7 +247,7 @@ public:
}
private:
uint64_t target_id;
uint64_t target_id = 0;
Transform transform;
};
@ -264,7 +255,6 @@ private:
class Camera : public NodeAttribute {
public:
Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Camera();
fbx_simple_property(Position, Vector3, Vector3(0, 0, 0));
@ -380,7 +370,6 @@ public:
};
Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Model();
fbx_simple_property(QuaternionInterpolate, int, 0);
@ -466,10 +455,6 @@ public:
return culling;
}
const PropertyTable *Props() const {
return props;
}
/** Get material links */
const std::vector<const Material *> &GetMaterials() const {
return materials;
@ -498,13 +483,11 @@ private:
std::string shading;
std::string culling;
const PropertyTable *props = nullptr;
};
class ModelLimbNode : public Model {
public:
ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~ModelLimbNode();
};
@ -512,7 +495,6 @@ public:
class Texture : public Object {
public:
Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Texture();
const std::string &Type() const {
@ -539,10 +521,6 @@ public:
return uvScaling;
}
const PropertyTable *Props() const {
return props;
}
// return a 4-tuple
const unsigned int *Crop() const {
return crop;
@ -560,10 +538,8 @@ private:
std::string relativeFileName;
std::string fileName;
std::string alphaSource;
const PropertyTable *props = nullptr;
unsigned int crop[4] = { 0 };
const Video *media = nullptr;
};
@ -626,8 +602,8 @@ public:
private:
std::vector<const Texture *> textures;
BlendMode blendMode;
float alpha;
BlendMode blendMode = BlendMode::BlendMode_Additive;
float alpha = 0;
};
typedef std::map<std::string, const Texture *> TextureMap;
@ -656,10 +632,6 @@ public:
return relativeFileName;
}
const PropertyTable *Props() const {
return props;
}
const uint8_t *Content() const {
return content;
}
@ -687,7 +659,6 @@ private:
std::string type;
std::string relativeFileName;
std::string fileName;
const PropertyTable *props = nullptr;
uint64_t contentLength = 0;
uint8_t *content = nullptr;
@ -708,10 +679,6 @@ public:
return multilayer;
}
const PropertyTable *Props() const {
return props;
}
const TextureMap &Textures() const {
return textures;
}
@ -722,8 +689,7 @@ public:
private:
std::string shading;
bool multilayer;
const PropertyTable *props;
bool multilayer = false;
TextureMap textures;
LayeredTextureMap layeredTextures;
@ -791,10 +757,6 @@ public:
virtual ~AnimationCurveNode();
const PropertyTable *Props() const {
return props;
}
const AnimationMap &Curves() const;
/** Object the curve is assigned to, this can be NULL if the
@ -819,7 +781,6 @@ public:
private:
Object *target = nullptr;
const PropertyTable *props;
mutable AnimationMap curves;
std::string prop;
const Document &doc;
@ -837,18 +798,12 @@ public:
AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
virtual ~AnimationLayer();
const PropertyTable *Props() const {
//ai_assert(props.get());
return props;
}
/* the optional white list specifies a list of property names for which the caller
wants animations for. Curves not matching this list will not be added to the
animation layer. */
const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
private:
const PropertyTable *props;
const Document &doc;
};
@ -863,16 +818,11 @@ public:
fbx_simple_property(ReferenceStart, int64_t, 0L);
fbx_simple_property(ReferenceStop, int64_t, 0L);
const PropertyTable *Props() const {
return props;
}
const AnimationLayerList &Layers() const {
return layers;
}
private:
const PropertyTable *props = nullptr;
AnimationLayerList layers;
};
@ -881,14 +831,6 @@ class Deformer : public Object {
public:
Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Deformer();
const PropertyTable *Props() const {
//ai_assert(props.get());
return props;
}
private:
const PropertyTable *props;
};
/** Constraints are from Maya they can help us with BoneAttachments :) **/
@ -896,9 +838,6 @@ class Constraint : public Object {
public:
Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Constraint();
private:
const PropertyTable *props;
};
typedef std::vector<float> WeightArray;
@ -924,7 +863,7 @@ public:
}
private:
float percent;
float percent = 0;
WeightArray fullWeights;
std::vector<const ShapeGeometry *> shapeGeometries;
};
@ -1006,7 +945,7 @@ private:
Transform transformLink;
Transform transformAssociateModel;
SkinLinkMode link_mode;
bool valid_transformAssociateModel;
bool valid_transformAssociateModel = false;
const Model *node = nullptr;
};
@ -1037,8 +976,8 @@ public:
}
private:
float accuracy;
SkinType skinType;
float accuracy = 0;
SkinType skinType = SkinType::Skin_Linear;
std::vector<const Cluster *> clusters;
};
@ -1087,10 +1026,10 @@ public:
}
public:
uint64_t insertionOrder;
uint64_t insertionOrder = 0;
const std::string prop;
uint64_t src, dest;
uint64_t src = 0, dest = 0;
const Document &doc;
};
@ -1105,15 +1044,10 @@ typedef std::multimap<uint64_t, const Connection *> ConnectionMap;
/** DOM class for global document settings, a single instance per document can
* be accessed via Document.Globals(). */
class FileGlobalSettings {
class FileGlobalSettings : public PropertyTable {
public:
FileGlobalSettings(const Document &doc, const PropertyTable *props);
~FileGlobalSettings();
const PropertyTable *Props() const {
return props;
}
FileGlobalSettings(const Document &doc);
virtual ~FileGlobalSettings();
const Document &GetDocument() const {
return doc;
@ -1158,7 +1092,6 @@ public:
fbx_simple_property(CustomFrameRate, float, -1.0f);
private:
const PropertyTable *props = nullptr;
const Document &doc;
};
@ -1196,7 +1129,7 @@ public:
return globals.get();
}
const PropertyTable *GetMetadataProperties() const {
const PropertyTable &GetMetadataProperties() const {
return metadata_properties;
}
@ -1293,7 +1226,7 @@ private:
std::vector<uint64_t> materials;
std::vector<uint64_t> skins;
mutable std::vector<const AnimationStack *> animationStacksResolved;
PropertyTable *metadata_properties = nullptr;
PropertyTable metadata_properties;
std::shared_ptr<FileGlobalSettings> globals = nullptr;
};
} // namespace FBXDocParser

View File

@ -137,36 +137,5 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Element> eleme
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
}
// ------------------------------------------------------------------------------------------------
// fetch a property table and the corresponding property template
const PropertyTable *GetPropertyTable(const Document &doc,
const std::string &templateName,
const ElementPtr element,
const ScopePtr sc,
bool no_warn /*= false*/) {
// todo: make this an abstraction
const ElementPtr Properties70 = sc->GetElement("Properties70");
const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
if (templateName.length()) {
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
if (it != doc.Templates().end()) {
templateProps = (*it).second;
}
}
if (!Properties70 || !Properties70->Compound()) {
if (!no_warn) {
DOMWarning("property table (Properties70) not found", element);
}
if (templateProps) {
return new const PropertyTable(templateProps);
} else {
return new const PropertyTable();
}
}
return new PropertyTable(Properties70, templateProps);
}
} // namespace Util
} // namespace FBXDocParser

View File

@ -98,13 +98,6 @@ void DOMWarning(const std::string &message, const Element *element);
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
// fetch a property table and the corresponding property template
const PropertyTable *GetPropertyTable(const Document &doc,
const std::string &templateName,
const ElementPtr element,
const ScopePtr sc,
bool no_warn = false);
// ------------------------------------------------------------------------------------------------
template <typename T>
const T *ProcessSimpleConnection(const Connection &con,

View File

@ -118,8 +118,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
DOMWarning("shading mode not recognized: " + shading, element);
}
props = GetPropertyTable(doc, templateName, element, sc);
// resolve texture links
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
for (const Connection *con : conns) {
@ -163,10 +161,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
// ------------------------------------------------------------------------------------------------
Material::~Material() {
if (props != nullptr) {
delete props;
props = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
@ -219,17 +213,15 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
}
props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
bool ok;
const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
bool ok = true;
const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok);
if (ok) {
uvScaling.x = scaling.x;
uvScaling.y = scaling.y;
}
const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok);
const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok);
if (ok) {
uvTrans.x = trans.x;
uvTrans.y = trans.y;
@ -254,10 +246,6 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
}
Texture::~Texture() {
if (props != nullptr) {
delete props;
props = nullptr;
}
}
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
@ -390,18 +378,11 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s
// runtimeError.what());
}
}
props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
}
Video::~Video() {
if (content) {
delete[] content;
}
if (props != nullptr) {
delete props;
props = nullptr;
}
}
} // namespace FBXDocParser

View File

@ -98,16 +98,11 @@ Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const s
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
}
props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
ResolveLinks(element, doc);
}
// ------------------------------------------------------------------------------------------------
Model::~Model() {
if (props != nullptr) {
delete props;
props = nullptr;
}
}
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :

View File

@ -84,16 +84,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name), props() {
const ScopePtr sc = GetRequiredScope(element);
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
// hack on the deriving type but Null/LimbNode attributes are the only case in which
// the property table is by design absent and no warning should be generated
// for it.
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
Object(id, element, name) {
}
// ------------------------------------------------------------------------------------------------

View File

@ -131,6 +131,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (!n) {
print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str()));
parser.corrupt = true;
return;
}
const TokenType ty = n->Type();
@ -143,6 +145,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str()));
parser.corrupt = true;
return;
}
}
@ -150,11 +154,17 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
compound = new_Scope(parser);
parser.scopes.push_back(compound);
if (parser.corrupt) {
return;
}
// current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken();
if (n && n->Type() != TokenType_CLOSE_BRACKET) {
print_error("expected closing bracket" + String(n->StringContents().c_str()));
parser.corrupt = true;
return;
}
parser.AdvanceToNextToken();
@ -173,22 +183,31 @@ Scope::Scope(Parser &parser, bool topLevel) {
TokenPtr t = parser.CurrentToken();
if (t->Type() != TokenType_OPEN_BRACKET) {
print_error("expected open bracket" + String(t->StringContents().c_str()));
parser.corrupt = true;
return;
}
}
TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) {
print_error("unexpected end of file");
parser.corrupt = true;
return;
}
// note: empty scopes are allowed
while (n && n->Type() != TokenType_CLOSE_BRACKET) {
if (n->Type() != TokenType_KEY) {
print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str()));
parser.corrupt = true;
return;
}
const std::string str = n->StringContents();
if (parser.corrupt) {
return;
}
// std::multimap<std::string, ElementPtr> (key and value)
elements.insert(ElementMap::value_type(str, new_Element(n, parser)));
@ -216,7 +235,7 @@ Scope::~Scope() {
// ------------------------------------------------------------------------------------------------
Parser::Parser(const TokenList &tokens, bool is_binary) :
tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) {
corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) {
root = new_Scope(*this, true);
scopes.push_back(root);
}
@ -1230,6 +1249,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) {
ERR_FAIL_V_MSG(nullptr, "Invalid element supplied to parser");
}
// ------------------------------------------------------------------------------------------------
// extract optional compound scope
ScopePtr GetOptionalScope(const ElementPtr el) {
if (el) {
ScopePtr s = el->Compound();
TokenPtr token = el->KeyToken();
if (token && s) {
return s;
}
}
return nullptr;
}
// ------------------------------------------------------------------------------------------------
// get token at a particular index
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) {

View File

@ -199,6 +199,10 @@ public:
return is_binary;
}
bool IsCorrupt() const {
return corrupt;
}
private:
friend class Scope;
friend class Element;
@ -208,6 +212,7 @@ private:
TokenPtr CurrentToken() const;
private:
bool corrupt = false;
ScopeList scopes;
const TokenList &tokens;
@ -249,6 +254,8 @@ bool HasElement(const ScopePtr sc, const std::string &index);
// extract a required element from a scope, abort if the element cannot be found
ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now)
ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
// extract required compound scope
ScopePtr GetRequiredScope(const ElementPtr el);

View File

@ -145,19 +145,33 @@ std::string PeekPropertyName(const Element &element) {
} // namespace
// ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable() {
PropertyTable::PropertyTable() :
element(nullptr) {
}
// Is used when dealing with FBX Objects not metadata.
PropertyTable::PropertyTable(const ElementPtr element) :
element(element) {
Setup(element);
}
// ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable(const PropertyTable *templateProps) :
templateProps(templateProps), element() {
PropertyTable::~PropertyTable() {
for (PropertyMap::value_type &v : props) {
delete v.second;
}
}
// ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
templateProps(templateProps), element(element) {
const ScopePtr scope = GetRequiredScope(element);
ERR_FAIL_COND(!scope);
void PropertyTable::Setup(ElementPtr ptr) {
const ScopePtr sc = GetRequiredScope(ptr);
const ElementPtr Properties70 = sc->GetElement("Properties70");
const ScopePtr scope = GetOptionalScope(Properties70);
// no scope, no care.
if (!scope) {
return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it.
}
for (const ElementMap::value_type &v : scope->Elements()) {
if (v.first != "P") {
DOMWarning("expected only P elements in property table", v.second);
@ -181,13 +195,6 @@ PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *temp
}
}
// ------------------------------------------------------------------------------------------------
PropertyTable::~PropertyTable() {
for (PropertyMap::value_type &v : props) {
delete v.second;
}
}
// ------------------------------------------------------------------------------------------------
PropertyPtr PropertyTable::Get(const std::string &name) const {
PropertyMap::const_iterator it = props.find(name);
@ -203,10 +210,6 @@ PropertyPtr PropertyTable::Get(const std::string &name) const {
if (it == props.end()) {
// check property template
if (templateProps) {
return templateProps->Get(name);
}
return nullptr;
}
}

View File

@ -137,36 +137,31 @@ class PropertyTable {
public:
// in-memory property table with no source element
PropertyTable();
PropertyTable(const PropertyTable *templateProps);
PropertyTable(const ElementPtr element, const PropertyTable *templateProps);
~PropertyTable();
PropertyTable(const ElementPtr element);
virtual ~PropertyTable();
PropertyPtr Get(const std::string &name) const;
void Setup(ElementPtr ptr);
// PropertyTable's need not be coupled with FBX elements so this can be NULL
ElementPtr GetElement() const {
ElementPtr GetElement() {
return element;
}
PropertyMap &GetProperties() const {
PropertyMap &GetProperties() {
return props;
}
const LazyPropertyMap &GetLazyProperties() const {
const LazyPropertyMap &GetLazyProperties() {
return lazyProps;
}
const PropertyTable *TemplateProps() const {
return templateProps;
}
DirectPropertyMap GetUnparsedProperties() const;
private:
LazyPropertyMap lazyProps;
mutable PropertyMap props;
const PropertyTable *templateProps = nullptr;
const ElementPtr element = nullptr;
ElementPtr element = nullptr;
};
// ------------------------------------------------------------------------------------------------
@ -191,16 +186,11 @@ template <typename T>
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
PropertyPtr prop = in->Get(name);
if (nullptr == prop) {
if (!useTemplate) {
if (nullptr == in) {
result = false;
return T();
}
const PropertyTable *templ = in->TemplateProps();
if (nullptr == templ) {
result = false;
return T();
}
prop = templ->Get(name);
prop = in->Get(name);
if (nullptr == prop) {
result = false;
return T();

View File

@ -141,7 +141,7 @@ void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *
} // namespace
// ------------------------------------------------------------------------------------------------
void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
// line and column numbers numbers are one-based
unsigned int line = 1;
unsigned int column = 1;
@ -185,6 +185,8 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
case '\"':
if (token_begin) {
TokenizeError("unexpected double-quote", line, column);
corrupt = true;
return;
}
token_begin = cur;
in_double_quotes = true;

View File

@ -187,7 +187,7 @@ typedef std::vector<TokenPtr> TokenList;
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated.
* @print_error if something goes wrong */
void Tokenize(TokenList &output_tokens, const char *input, size_t length);
void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
/** Tokenizer function for binary FBX files.
*
@ -197,7 +197,7 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length);
* @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal.
* @print_error if something goes wrong */
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length);
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
} // namespace FBXDocParser
#endif // FBX_TOKENIZER_H