diff options
Diffstat (limited to 'modules/fbx')
31 files changed, 294 insertions, 440 deletions
diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub index 84220a66fa..0311fddfee 100644 --- a/modules/fbx/SCsub +++ b/modules/fbx/SCsub @@ -8,6 +8,9 @@ env_fbx = env_modules.Clone() # Make includes relative to the folder path specified here so our includes are clean env_fbx.Prepend(CPPPATH=["#modules/fbx/"]) +if env["builtin_zlib"]: + env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"]) + # Godot's own source files env_fbx.add_source_files(env.modules_sources, "tools/*.cpp") env_fbx.add_source_files(env.modules_sources, "data/*.cpp") diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp index 5995097b2f..d54ac86e9f 100644 --- a/modules/fbx/data/fbx_material.cpp +++ b/modules/fbx/data/fbx_material.cpp @@ -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())); diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 883651943e..304d1598f6 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -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; } @@ -417,6 +404,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) { int bind_id = 0; for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) { + ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + "."); Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()]; skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id); bind_id++; @@ -815,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]); @@ -855,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; @@ -892,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); diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index 77510ff2ec..575f833584 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -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. diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp index 622b589feb..1ac4922acf 100644 --- a/modules/fbx/data/fbx_skeleton.cpp +++ b/modules/fbx/data/fbx_skeleton.cpp @@ -69,7 +69,7 @@ void FBXSkeleton::init_skeleton(const ImportState &state) { // Make sure the bone name is unique. const String bone_name = bone->bone_name; int same_name_count = 0; - for (int y = x; y < skeleton_bone_count; y++) { + for (int y = x + 1; y < skeleton_bone_count; y++) { Ref<FBXBone> other_bone = skeleton_bones[y]; if (other_bone.is_valid()) { if (other_bone->bone_name == bone_name) { diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp index 1895af6f9f..f4055c830f 100644 --- a/modules/fbx/data/pivot_transform.cpp +++ b/modules/fbx/data/pivot_transform.cpp @@ -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. diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index 6576147b2b..edea1963a7 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -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" @@ -94,7 +93,7 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - ERR_FAIL_COND_V(!f, NULL); + ERR_FAIL_COND_V(!f, nullptr); { PackedByteArray data; @@ -104,6 +103,9 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl bool is_binary = false; data.resize(f->get_len()); + + ERR_FAIL_COND_V(data.size() < 64, NULL); + f->get_buffer(data.ptrw(), data.size()); PackedByteArray fbx_header; fbx_header.resize(64); @@ -118,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: @@ -138,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; @@ -150,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); @@ -197,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())); } } @@ -260,8 +287,9 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const //could use binary search, worth it? int idx = -1; for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) + if (p_times[i] > p_time) { break; + } idx++; } @@ -334,7 +362,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( ImportState state; state.is_blender_fbx = p_is_blender_fbx; state.path = p_path; - state.animation_player = NULL; + state.animation_player = nullptr; // create new root node for scene Node3D *scene_root = memnew(Node3D); @@ -610,8 +638,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene( for (const FBXDocParser::Geometry *mesh : geometry) { print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name); - if (mesh == nullptr) + if (mesh == nullptr) { continue; + } const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh); if (mesh_geometry) { @@ -628,7 +657,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( mesh_data_precached->mesh_node = fbx_node; // mesh node, mesh id - mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, (p_flags & IMPORT_USE_COMPRESSION) != 0); + mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, false); if (!state.MeshNodes.has(mesh_id)) { state.MeshNodes.insert(mesh_id, fbx_node); } @@ -887,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); @@ -985,7 +1014,6 @@ Node3D *EditorSceneImporterFBX::_generate_scene( int track_idx = animation->add_track(Animation::TYPE_TRANSFORM); // animation->track_set_path(track_idx, node_path); - // animation->track_set_path(track_idx, node_path); Ref<FBXBone> bone; // note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad. @@ -1042,7 +1070,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")]; @@ -1132,7 +1160,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( max_duration = animation_track_time; } - rot_values.push_back(final_rotation); + rot_values.push_back(final_rotation.normalized()); rot_times.push_back(animation_track_time); } diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h index 39f8648b0f..4bb2c9d21b 100644 --- a/modules/fbx/editor_scene_importer_fbx.h +++ b/modules/fbx/editor_scene_importer_fbx.h @@ -128,7 +128,7 @@ public: virtual void get_extensions(List<String> *r_extensions) const override; virtual uint32_t get_import_flags() const override; - virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) override; + virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; #endif // TOOLS_ENABLED diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h index f759c9117c..5c16383974 100644 --- a/modules/fbx/fbx_parser/ByteSwapper.h +++ b/modules/fbx/fbx_parser/ByteSwapper.h @@ -264,8 +264,9 @@ struct Getter { le = !le; if (le) { ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout); - } else + } else { ByteSwapper<T, false>()(inout); + } } }; diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp index b11e2c7f55..1690df6943 100644 --- a/modules/fbx/fbx_parser/FBXAnimation.cpp +++ b/modules/fbx/fbx_parser/FBXAnimation.cpp @@ -131,8 +131,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co const Document &doc, const char *const *target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/) : Object(id, element, name), target(), doc(doc) { - const ScopePtr sc = GetRequiredScope(element); - // 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 diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp index 1d2b7765c5..1eee10b251 100644 --- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp @@ -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; } } diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp index 4b774e6b2a..039718ae15 100644 --- a/modules/fbx/fbx_parser/FBXDeformer.cpp +++ b/modules/fbx/fbx_parser/FBXDeformer.cpp @@ -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() { diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp index bcf7fa1565..bb85d6ff7c 100644 --- a/modules/fbx/fbx_parser/FBXDocument.cpp +++ b/modules/fbx/fbx_parser/FBXDocument.cpp @@ -93,7 +93,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) : - doc(doc), element(element), id(id), flags() { + doc(doc), element(element), id(id) { // empty } @@ -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,22 +237,18 @@ 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; - } } // ------------------------------------------------------------------------------------------------ Document::Document(const Parser &parser, const ImportSettings &settings) : - settings(settings), parser(parser), SafeToImport(false) { + settings(settings), parser(parser) { // Cannot use array default initialization syntax because vc8 fails on it for (unsigned int &timeStamp : creationTimeStamp) { timeStamp = 0; @@ -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; - } - } - } } // ------------------------------------------------------------------------------------------------ diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h index b810197d7e..49b7c11c31 100644 --- a/modules/fbx/fbx_parser/FBXDocument.h +++ b/modules/fbx/fbx_parser/FBXDocument.h @@ -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; } @@ -670,7 +642,7 @@ public: uint8_t *RelinquishContent() { uint8_t *ptr = content; - content = 0; + content = nullptr; return ptr; } @@ -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 diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp index 835b66ab23..3930e005c3 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp @@ -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 templateProps; - } else { - return new const PropertyTable(); - } - } - - return new PropertyTable(Properties70, templateProps); -} } // namespace Util } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h index daa9de4a33..ba86191c4a 100644 --- a/modules/fbx/fbx_parser/FBXDocumentUtil.h +++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h @@ -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, diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h index 97ce496eaf..b016db174b 100644 --- a/modules/fbx/fbx_parser/FBXImportSettings.h +++ b/modules/fbx/fbx_parser/FBXImportSettings.h @@ -80,60 +80,52 @@ namespace FBXDocParser { /** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */ struct ImportSettings { - ImportSettings() : - strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) { - // empty - } - /** enable strict mode: * - only accept fbx 2012, 2013 files * - on the slightest error, give up. * * Basically, strict mode means that the fbx file will actually - * be validated. Strict mode is off by default. */ - bool strictMode; + * be validated.*/ + bool strictMode = true; /** specifies whether all geometry layers are read and scanned for * usable data channels. The FBX spec indicates that many readers * will only read the first channel and that this is in some way * the recommended way- in reality, however, it happens a lot that - * vertex data is spread among multiple layers. The default - * value for this option is true.*/ - bool readAllLayers; + * vertex data is spread among multiple layers.*/ + bool readAllLayers = true; /** specifies whether all materials are read, or only those that * are referenced by at least one mesh. Reading all materials * may make FBX reading a lot slower since all objects - * need to be processed . - * This bit is ignored unless readMaterials=true*/ - bool readAllMaterials; + * need to be processed. + * This bit is ignored unless readMaterials=true.*/ + bool readAllMaterials = true; /** import materials (true) or skip them and assign a default - * material. The default value is true.*/ - bool readMaterials; + * material.*/ + bool readMaterials = true; - /** import embedded textures? Default value is true.*/ - bool readTextures; + /** import embedded textures?*/ + bool readTextures = true; - /** import cameras? Default value is true.*/ - bool readCameras; + /** import cameras?*/ + bool readCameras = true; - /** import light sources? Default value is true.*/ - bool readLights; + /** import light sources?*/ + bool readLights = true; /** import animations (i.e. animation curves, the node - * skeleton is always imported). Default value is true. */ - bool readAnimations; + * skeleton is always imported).*/ + bool readAnimations = true; - /** read bones (vertex weights and deform info). - * Default value is true. */ - bool readWeights; + /** read bones (vertex weights and deform info).*/ + bool readWeights = true; /** preserve transformation pivots and offsets. Since these can * not directly be represented in assimp, additional dummy * nodes will be generated. Note that settings this to false - * can make animation import a lot slower. The default value - * is true. + * can make animation import a lot slower. * * The naming scheme for the generated nodes is: * <OriginalName>_$AssimpFbx$_<TransformName> @@ -149,24 +141,21 @@ struct ImportSettings { * Scaling * Rotation **/ - bool preservePivots; + bool preservePivots = true; /** do not import animation curves that specify a constant - * values matching the corresponding node transformation. - * The default value is true. */ - bool optimizeEmptyAnimationCurves; + * values matching the corresponding node transformation.*/ + bool optimizeEmptyAnimationCurves = true; - /** use legacy naming for embedded textures eg: (*0, *1, *2) - */ - bool useLegacyEmbeddedTextureNaming; + /** use legacy naming for embedded textures eg: (*0, *1, *2).*/ + bool useLegacyEmbeddedTextureNaming = false; - /** Empty bones shall be removed - */ - bool removeEmptyBones; + /** Empty bones shall be removed.*/ + bool removeEmptyBones = true; - /** Set to true to perform a conversion from cm to meter after the import - */ - bool convertToMeters; + /** Set to true to perform a conversion from cm to meter after + * the import.*/ + bool convertToMeters = false; }; } // namespace FBXDocParser diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp index 9970a2b0b1..bf8922267e 100644 --- a/modules/fbx/fbx_parser/FBXMaterial.cpp +++ b/modules/fbx/fbx_parser/FBXMaterial.cpp @@ -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,15 +161,11 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c // ------------------------------------------------------------------------------------------------ Material::~Material() { - if (props != nullptr) { - delete props; - props = nullptr; - } } // ------------------------------------------------------------------------------------------------ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) { + Object(id, element, name), uvScaling(1.0f, 1.0f) { const ScopePtr sc = GetRequiredScope(element); const ElementPtr Type = sc->GetElement("Type"); @@ -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) : @@ -267,10 +255,10 @@ LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Docu ElementPtr BlendModes = sc->GetElement("BlendModes"); ElementPtr Alphas = sc->GetElement("Alphas"); - if (BlendModes != 0) { + if (BlendModes != nullptr) { blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0)); } - if (Alphas != 0) { + if (Alphas != nullptr) { alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0)); } } @@ -297,7 +285,7 @@ void LayeredTexture::fillTexture(const Document &doc) { // ------------------------------------------------------------------------------------------------ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) : - Object(id, element, name), contentLength(0), content(0) { + Object(id, element, name) { const ScopePtr sc = GetRequiredScope(element); const ElementPtr Type = sc->GetElement("Type"); @@ -337,7 +325,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s DOMError("embedded content is not surrounded by quotation marks", element); } else { size_t targetLength = 0; - auto numTokens = Content->Tokens().size(); + const size_t numTokens = Content->Tokens().size(); // First time compute size (it could be large like 64Gb and it is good to allocate it once) for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) { const Token *dataToken = GetRequiredToken(Content, tokenIdx); @@ -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 diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp index ccc06550fe..a28e7565c6 100644 --- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp +++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp @@ -88,7 +88,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) : - Object(id, element, name), skin() { + Object(id, element, name) { const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); for (const Connection *con : conns) { const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element); diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp index 767994441f..03c9de0c35 100644 --- a/modules/fbx/fbx_parser/FBXModel.cpp +++ b/modules/fbx/fbx_parser/FBXModel.cpp @@ -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) : diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp index 2749fc9f4d..15184a0f5d 100644 --- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp +++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp @@ -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) { } // ------------------------------------------------------------------------------------------------ diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h index 21472f5b7b..b4003bbec5 100644 --- a/modules/fbx/fbx_parser/FBXParseTools.h +++ b/modules/fbx/fbx_parser/FBXParseTools.h @@ -61,7 +61,7 @@ inline bool IsLineEnd(char_t c) { // Special version of the function, providing higher accuracy and safety // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows. // ------------------------------------------------------------------------------------ -inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = 0, unsigned int *max_inout = 0) { +inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) { unsigned int cur = 0; uint64_t value = 0; diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp index 44c24ff926..2a76c3f67c 100644 --- a/modules/fbx/fbx_parser/FBXParser.cpp +++ b/modules/fbx/fbx_parser/FBXParser.cpp @@ -74,8 +74,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the FBX parser and the rudimentary DOM that we use */ -#include "thirdparty/zlib/zlib.h" #include <stdlib.h> /* strtol */ +#include <zlib.h> #include "ByteSwapper.h" #include "FBXParseTools.h" @@ -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), last(), current(), 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); } @@ -1231,6 +1250,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ +// 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) { if (el) { diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h index 37d27d3dca..8b248e8791 100644 --- a/modules/fbx/fbx_parser/FBXParser.h +++ b/modules/fbx/fbx_parser/FBXParser.h @@ -160,7 +160,7 @@ public: } ElementPtr FindElementCaseInsensitive(const std::string &elementName) const { - for (auto element = elements.begin(); element != elements.end(); ++element) { + for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) { if (element->first.compare(elementName)) { return element->second; } @@ -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); diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp index 8ab94e1ef4..1b3f29ec04 100644 --- a/modules/fbx/fbx_parser/FBXProperties.cpp +++ b/modules/fbx/fbx_parser/FBXProperties.cpp @@ -146,14 +146,32 @@ std::string PeekPropertyName(const Element &element) { // ------------------------------------------------------------------------------------------------ PropertyTable::PropertyTable() : - templateProps(), element() { + element(nullptr) { +} + +// Is used when dealing with FBX Objects not metadata. +PropertyTable::PropertyTable(const ElementPtr element) : + element(element) { + Setup(element); } // ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) : - templateProps(templateProps), element(element) { - const ScopePtr scope = GetRequiredScope(element); - ERR_FAIL_COND(!scope); +PropertyTable::~PropertyTable() { + for (PropertyMap::value_type &v : props) { + delete v.second; + } +} + +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); @@ -178,13 +196,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); if (it == props.end()) { @@ -199,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; } } @@ -216,8 +223,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const { // Loop through all the lazy properties (which is all the properties) for (const LazyPropertyMap::value_type &element : lazyProps) { // Skip parsed properties - if (props.end() != props.find(element.first)) + if (props.end() != props.find(element.first)) { continue; + } // Read the element's value. // Wrap the naked pointer (since the call site is required to acquire ownership) @@ -225,8 +233,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const { Property *prop = ReadTypedProperty(element.second); // Element could not be read. Skip it. - if (!prop) + if (!prop) { continue; + } // Add to result result[element.first] = prop; diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h index 27cacfaf76..bfd27ac94e 100644 --- a/modules/fbx/fbx_parser/FBXProperties.h +++ b/modules/fbx/fbx_parser/FBXProperties.h @@ -137,35 +137,31 @@ class PropertyTable { public: // in-memory property table with no source element PropertyTable(); - 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; }; // ------------------------------------------------------------------------------------------------ @@ -190,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) { - result = false; - return T(); - } - const PropertyTable *templ = in->TemplateProps(); - if (nullptr == templ) { + if (nullptr == in) { result = false; return T(); } - prop = templ->Get(name); + prop = in->Get(name); if (nullptr == prop) { result = false; return T(); diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp index ea4568fe32..81c5b128e8 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.cpp +++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp @@ -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; diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h index 1e7e5e6535..184d0fd894 100644 --- a/modules/fbx/fbx_parser/FBXTokenizer.h +++ b/modules/fbx/fbx_parser/FBXTokenizer.h @@ -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 diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp index 80ea5fab4c..1f14a69099 100644 --- a/modules/fbx/fbx_parser/FBXUtil.cpp +++ b/modules/fbx/fbx_parser/FBXUtil.cpp @@ -121,9 +121,10 @@ static const uint8_t base64DecodeTable[128] = { }; uint8_t DecodeBase64(char ch) { - const auto idx = static_cast<uint8_t>(ch); - if (idx > 127) + const uint8_t idx = static_cast<uint8_t>(ch); + if (idx > 127) { return 255; + } return base64DecodeTable[idx]; } @@ -211,8 +212,9 @@ std::string EncodeBase64(const char *data, size_t length) { EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); // add '=' at the end - for (size_t i = 0; i < 4 * extraBytes / 3; i++) + for (size_t i = 0; i < 4 * extraBytes / 3; i++) { encoded_string[encodedBytes - i - 1] = '='; + } } return encoded_string; } diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h index 6261138812..bea28ffeda 100644 --- a/modules/fbx/tools/import_utils.h +++ b/modules/fbx/tools/import_utils.h @@ -339,7 +339,7 @@ public: // } else { // Ref<Texture> texture = ResourceLoader::load(p_path); // ERR_FAIL_COND_V(texture.is_null(), Ref<Image>()); - // Ref<Image> image = texture->get_data(); + // Ref<Image> image = texture->get_image(); // ERR_FAIL_COND_V(image.is_null(), Ref<Image>()); // state.path_to_image_cache.insert(p_path, image); // return image; diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h index ced100aed2..fe0c92b22f 100644 --- a/modules/fbx/tools/validation_tools.h +++ b/modules/fbx/tools/validation_tools.h @@ -65,8 +65,9 @@ protected: Error err; FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err); if (!file || err) { - if (file) + if (file) { memdelete(file); + } print_error("ValidationTracker Error - failed to create file - path: %s\n" + path); return; } |