diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp index eab93468b28e..71011d37d116 100644 --- a/modules/fbx/data/fbx_material.cpp +++ b/modules/fbx/data/fbx_material.cpp @@ -351,9 +351,6 @@ Ref FBXMaterial::import_material(ImportState &state) { } } - // FBX culling normally is front only. - spatial_material->set_cull_mode(SpatialMaterial::CULL_FRONT); - // Set the material features. for (int x = 0; x < material_info.features.size(); x++) { if (spatial_material.is_null()) { @@ -407,8 +404,8 @@ Ref FBXMaterial::import_material(ImportState &state) { } else if (extension == "TGA") { // The stored file is a TGA. - image = Image::_tga_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail."); + //image = Image::_tga_mem_loader_func(mapping.texture->Media()->Content(), mapping.texture->Media()->ContentLength()); + //ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail."); } else if (extension == "WEBP") { diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 68d8353b41ef..8da1c86d30f0 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -471,39 +471,39 @@ void FBXMeshData::reorganize_vertices( uv_raw = &r_uv_2_raw; this_vert_poly_uv = &this_vert_poly_uv2; } - - if (need_duplication) { - // Let's see if we already duplicated this vertex. - if (duplicated_vertices.has(index)) { - Vertex similar_vertex = -1; - // Let's see if one of the new vertices has the same data of this. - const Vector *new_vertices = duplicated_vertices.getptr(index); - for (int j = 0; j < new_vertices->size(); j += 1) { - const Vertex new_vertex = (*new_vertices)[j]; - if (r_uv_1.has(new_vertex)) { - if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - similar_vertex = new_vertex; - break; - } - } else if (r_uv_2.has(new_vertex)) { - if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - similar_vertex = new_vertex; - break; - } - } - } - - if (similar_vertex != -1) { - // Update polygon. - if (is_end_of_polygon(r_polygon_indices, pv)) { - r_polygon_indices[pv] = ~similar_vertex; - } else { - r_polygon_indices[pv] = similar_vertex; - } - need_duplication = false; - } - } - } + // FIXME: breaks UV2 on some meshes try sphere with lightmap unpack on the second uv coordinates + // if (need_duplication) { + // // Let's see if we already duplicated this vertex. + // if (duplicated_vertices.has(index)) { + // Vertex similar_vertex = -1; + // // Let's see if one of the new vertices has the same data of this. + // const Vector *new_vertices = duplicated_vertices.getptr(index); + // for (int j = 0; j < new_vertices->size(); j += 1) { + // const Vertex new_vertex = (*new_vertices)[j]; + // if (r_uv_1.has(new_vertex)) { + // if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { + // similar_vertex = new_vertex; + // break; + // } + // } else if (r_uv_2.has(new_vertex)) { + // if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { + // similar_vertex = new_vertex; + // break; + // } + // } + // } + // + // if (similar_vertex != -1) { + // // Update polygon. + // if (is_end_of_polygon(r_polygon_indices, pv)) { + // r_polygon_indices[pv] = ~similar_vertex; + // } else { + // r_polygon_indices[pv] = similar_vertex; + // } + // need_duplication = false; + // } + // } + // } if (need_duplication) { const Vertex old_index = index; @@ -594,13 +594,13 @@ void FBXMeshData::add_vertex( } if (p_uvs_0.has(p_vertex)) { - print_verbose("uv1: " + p_uvs_0[p_vertex]); + print_verbose("uv1: [" + itos(p_vertex) + "] " + p_uvs_0[p_vertex]); // Inverts Y UV. p_surface_tool->add_uv(Vector2(p_uvs_0[p_vertex].x, 1 - p_uvs_0[p_vertex].y)); } if (p_uvs_1.has(p_vertex)) { - print_verbose("uv2: " + p_uvs_1[p_vertex]); + print_verbose("uv2: [" + itos(p_vertex) + "] " + p_uvs_1[p_vertex]); // Inverts Y UV. p_surface_tool->add_uv2(Vector2(p_uvs_1[p_vertex].x, 1 - p_uvs_1[p_vertex].y)); } @@ -635,22 +635,23 @@ void FBXMeshData::triangulate_polygon(Ref st, Vector p_polygon } else if (polygon_vertex_count == 3) { // triangle to triangle st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[1]); st->add_index(p_polygon_vertex[2]); + st->add_index(p_polygon_vertex[1]); return; } else if (polygon_vertex_count == 4) { - // quad to triangle + // quad to triangle - this code is awesome for import times + // it prevents triangles being generated slowly st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[1]); st->add_index(p_polygon_vertex[2]); + st->add_index(p_polygon_vertex[1]); st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[3]); st->add_index(p_polygon_vertex[0]); + st->add_index(p_polygon_vertex[3]); return; } else { // non triangulated - we must run the triangulation algorithm bool is_simple_convex = false; - + // this code is 'slow' but required it triangulates all the unsupported geometry. // Doesn't allow for bigger polygons because those are unlikely be convex if (polygon_vertex_count <= 6) { // Start from true, check if it's false. @@ -852,27 +853,36 @@ template HashMap FBXMeshData::extract_per_vertex_data( int p_vertex_count, const std::vector &p_edge_map, - const std::vector &p_polygon_indices, - const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, + const std::vector &p_mesh_indices, + const Assimp::FBX::MeshGeometry::MappingData &p_mapping_data, R (*collector_function)(const Vector > *p_vertex_data, R p_fall_back), R p_fall_back) const { - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); + /* When index_to_direct is set + * index size is 184 ( contains index for the data array [values 0, 96] ) + * data size is 96 (contains uv coordinates) + * this means index is simple data reduction basically + */ + + ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap()), "FBX file is missing indexing array"); + ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index && p_mapping_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); // Aggregate vertex data. HashMap > > aggregate_vertex_data; - switch (p_fbx_data.map_type) { + switch (p_mapping_data.map_type) { case Assimp::FBX::MeshGeometry::MapType::none: { // No data nothing to do. return (HashMap()); } case Assimp::FBX::MeshGeometry::MapType::vertex: { - if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct, (HashMap()), "We will support in future"); + + if (p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { // The data is mapped per vertex directly. - ERR_FAIL_COND_V_MSG((int)p_fbx_data.data.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR01"); - for (size_t vertex_index = 0; vertex_index < p_fbx_data.data.size(); vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[vertex_index] }); + ERR_FAIL_COND_V_MSG((int)p_mapping_data.data.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR01"); + for (size_t vertex_index = 0; vertex_index < p_mapping_data.data.size(); vertex_index += 1) { + aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[vertex_index] }); } } else { // The data is mapped per vertex using a reference. @@ -880,27 +890,42 @@ HashMap FBXMeshData::extract_per_vertex_data( // * Note that the reference_id is the id of data into the data array. // // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG((int)p_fbx_data.index.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR02"); - for (size_t vertex_index = 0; vertex_index < p_fbx_data.index.size(); vertex_index += 1) { - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[vertex_index], (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR03.") - aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[p_fbx_data.index[vertex_index]] }); + ERR_FAIL_COND_V_MSG((int)p_mapping_data.index.size() != p_vertex_count, (HashMap()), "FBX file corrupted: #ERR02"); + for (size_t vertex_index = 0; vertex_index < p_mapping_data.index.size(); vertex_index += 1) { + ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[vertex_index], (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR03.") + aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[p_mapping_data.index[vertex_index]] }); } } } break; case Assimp::FBX::MeshGeometry::MapType::polygon_vertex: { - if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + if (p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct) { + // The data is mapped using each index from the indexes array then direct to the data (data reduction algorithm) + ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR04"); + int polygon_id = -1; + for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { + if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { + polygon_id += 1; + } + const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); + ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap()), "FBX file corrupted: #ERR05"); + ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap()), "FBX file corrupted: #ERR06"); + const int index_to_direct = p_mapping_data.index[polygon_vertex_index]; + T value = p_mapping_data.data[index_to_direct]; + aggregate_vertex_data[vertex_index].push_back({ polygon_id, value }); + } + } else if (p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { // The data are mapped per polygon vertex directly. - ERR_FAIL_COND_V_MSG((int)p_polygon_indices.size() != (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR04"); + ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR04"); int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_fbx_data.data.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.data.size(); polygon_vertex_index += 1) { + if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { polygon_id += 1; } - const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap()), "FBX file corrupted: #ERR05"); ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap()), "FBX file corrupted: #ERR06"); - aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_fbx_data.data[polygon_vertex_index] }); + aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[polygon_vertex_index] }); } } else { // The data is mapped per polygon_vertex using a reference. @@ -908,42 +933,42 @@ HashMap FBXMeshData::extract_per_vertex_data( // * Note that the reference_id is the id of data into the data array. // // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_polygon_indices.size() != p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR7"); + ERR_FAIL_COND_V_MSG(p_mesh_indices.size() != p_mapping_data.index.size(), (HashMap()), "FBX file corrupted: #ERR7"); int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_fbx_data.index.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { + if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { polygon_id += 1; } - const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap()), "FBX file corrupted: #ERR8"); ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap()), "FBX file seems corrupted: #ERR9.") - ERR_FAIL_COND_V_MSG(p_fbx_data.index[polygon_vertex_index] < 0, (HashMap()), "FBX file seems corrupted: #ERR10.") - ERR_FAIL_COND_V_MSG(p_fbx_data.index[polygon_vertex_index] >= (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR11.") - aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_fbx_data.data[p_fbx_data.index[polygon_vertex_index]] }); + ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap()), "FBX file seems corrupted: #ERR10.") + ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR11.") + aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] }); } } } break; case Assimp::FBX::MeshGeometry::MapType::polygon: { - if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + if (p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { // The data are mapped per polygon directly. - const int polygon_count = count_polygons(p_polygon_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR12"); + const int polygon_count = count_polygons(p_mesh_indices); + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR12"); // Advance each polygon vertex, each new polygon advance the polygon index. int polygon_index = -1; for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_polygon_indices.size(); + polygon_vertex_index < p_mesh_indices.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR13"); + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR13"); } - const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR14"); - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_fbx_data.data[polygon_index] }); + aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[polygon_index] }); } ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap()), "FBX file seems corrupted: #ERR16. Not all Polygons are present in the file.") } else { @@ -952,41 +977,41 @@ HashMap FBXMeshData::extract_per_vertex_data( // * Note that the reference_id is the id of data into the data array. // // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - const int polygon_count = count_polygons(p_polygon_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR17"); + const int polygon_count = count_polygons(p_mesh_indices); + ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR17"); // Advance each polygon vertex, each new polygon advance the polygon index. int polygon_index = -1; for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_polygon_indices.size(); + polygon_vertex_index < p_mesh_indices.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_polygon_indices, polygon_vertex_index)) { + if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR18"); - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR19"); + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR18"); + ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[polygon_index], (int)p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR19"); } - const int vertex_index = get_vertex_from_polygon_vertex(p_polygon_indices, polygon_vertex_index); + const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR20"); - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_fbx_data.data[p_fbx_data.index[polygon_index]] }); + aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[p_mapping_data.index[polygon_index]] }); } ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap()), "FBX file seems corrupted: #ERR22. Not all Polygons are present in the file.") } } break; case Assimp::FBX::MeshGeometry::MapType::edge: { - if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + if (p_mapping_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { // The data are mapped per edge directly. - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_fbx_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR23"); - for (size_t edge_index = 0; edge_index < p_fbx_data.data.size(); edge_index += 1) { + ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.data.size(), (HashMap()), "FBX file seems corrupted: #ERR23"); + for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { const Assimp::FBX::MeshGeometry::Edge edge = Assimp::FBX::MeshGeometry::get_edge(p_edge_map, edge_index); ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR24"); ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR25"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR26"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR27"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_fbx_data.data[edge_index] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_fbx_data.data[edge_index] }); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.data.size(), (HashMap()), "FBX file corrupted: #ERR26"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.data.size(), (HashMap()), "FBX file corrupted: #ERR27"); + aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[edge_index] }); + aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[edge_index] }); } } else { // The data is mapped per edge using a reference. @@ -994,27 +1019,27 @@ HashMap FBXMeshData::extract_per_vertex_data( // * Note that the reference_id is the id of data into the data array. // // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_fbx_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR28"); - for (size_t edge_index = 0; edge_index < p_fbx_data.data.size(); edge_index += 1) { + ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.index.size(), (HashMap()), "FBX file seems corrupted: #ERR28"); + for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { const Assimp::FBX::MeshGeometry::Edge edge = Assimp::FBX::MeshGeometry::get_edge(p_edge_map, edge_index); ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR29"); ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap()), "FBX file corrupted: #ERR30"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR31"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_fbx_data.index.size(), (HashMap()), "FBX file corrupted: #ERR32"); - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[edge.vertex_0], (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR33"); - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[edge.vertex_1], (int)p_fbx_data.data.size(), (HashMap()), "FBX file corrupted: #ERR34"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_fbx_data.data[p_fbx_data.index[edge_index]] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_fbx_data.data[p_fbx_data.index[edge_index]] }); + ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.index.size(), (HashMap()), "FBX file corrupted: #ERR31"); + ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.index.size(), (HashMap()), "FBX file corrupted: #ERR32"); + ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_0], (int)p_mapping_data.data.size(), (HashMap()), "FBX file corrupted: #ERR33"); + ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_1], (int)p_mapping_data.data.size(), (HashMap()), "FBX file corrupted: #ERR34"); + aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); + aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); } } } break; case Assimp::FBX::MeshGeometry::MapType::all_the_same: { // No matter the mode, no matter the data size; The first always win // and is set to all the vertices. - ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap()), "FBX file seems corrupted: #ERR35"); - if (p_fbx_data.data.size() > 0) { + ERR_FAIL_COND_V_MSG(p_mapping_data.data.size() <= 0, (HashMap()), "FBX file seems corrupted: #ERR35"); + if (p_mapping_data.data.size() > 0) { for (int vertex_index = 0; vertex_index < p_vertex_count; vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_fbx_data.data[0] }); + aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[0] }); } } } break; @@ -1040,8 +1065,8 @@ HashMap FBXMeshData::extract_per_vertex_data( // Sanitize the data now, if the file is broken we can try import it anyway. bool problem_found = false; - for (size_t i = 0; i < p_polygon_indices.size(); i += 1) { - const Vertex vertex = get_vertex_from_polygon_vertex(p_polygon_indices, i); + for (size_t i = 0; i < p_mesh_indices.size(); i += 1) { + const Vertex vertex = get_vertex_from_polygon_vertex(p_mesh_indices, i); if (result.has(vertex) == false) { result[vertex] = p_fall_back; problem_found = true; @@ -1061,7 +1086,8 @@ HashMap FBXMeshData::extract_per_polygon( const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, T p_fallback_value) const { - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); + ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.data.size() == 0, (HashMap()), "invalid index to direct array"); + ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index && p_fbx_data.index.size() == 0, (HashMap()), "The FBX seems corrupted"); const int polygon_count = count_polygons(p_polygon_indices); @@ -1080,7 +1106,24 @@ HashMap FBXMeshData::extract_per_polygon( ERR_FAIL_V_MSG((HashMap()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per polygon vertex. This should not happen."); } break; case Assimp::FBX::MeshGeometry::MapType::polygon: { - if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { + if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::index_to_direct) { + // The data is stored efficiently index_to_direct allows less data in the FBX file. + for (int polygon_index = 0; + polygon_index < polygon_count; + polygon_index += 1) { + + if (p_fbx_data.index.size() == 0) { + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap()), "FBX file is corrupted: #ERR62"); + aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); + } else { + ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap()), "FBX file is corrupted: #ERR62"); + + const int index_to_direct = p_fbx_data.index[polygon_index]; + T value = p_fbx_data.data[index_to_direct]; + aggregate_polygon_data[polygon_index].push_back(value); + } + } + } else if (p_fbx_data.ref_type == Assimp::FBX::MeshGeometry::ReferenceType::direct) { // The data are mapped per polygon directly. ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap()), "FBX file is corrupted: #ERR51"); diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index 6604902573b6..f0117e31d10a 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -303,8 +303,8 @@ struct FBXMeshData : Reference { HashMap extract_per_vertex_data( int p_vertex_count, const std::vector &p_edges, - const std::vector &p_face_indices, - const Assimp::FBX::MeshGeometry::MappingData &p_fbx_data, + const std::vector &p_mesh_indices, + const Assimp::FBX::MeshGeometry::MappingData &p_mapping_data, R (*collector_function)(const Vector > *p_vertex_data, R p_fall_back), R p_fall_back) const; diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp index 3aeafeaf668f..671cb353650e 100644 --- a/modules/fbx/data/fbx_skeleton.cpp +++ b/modules/fbx/data/fbx_skeleton.cpp @@ -49,7 +49,7 @@ void FBXSkeleton::init_skeleton(const ImportState &state) { } else { // root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton) fbx_node->godot_node->add_child(skeleton); - skeleton->set_owner(state.root); + skeleton->set_owner(state.root_owner); skeleton->set_name("Skeleton"); print_verbose("created armature skeleton for root"); } diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index 2879d1542db1..996a59c1c223 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -743,7 +743,7 @@ EditorSceneImporterFBX::_generate_scene(const String &p_path, print_verbose("Creating animation player"); state.animation_player = memnew(AnimationPlayer); state.root->add_child(state.animation_player); - state.animation_player->set_owner(state.root); + state.animation_player->set_owner(state.root_owner); } Ref animation; @@ -815,7 +815,7 @@ EditorSceneImporterFBX::_generate_scene(const String &p_path, String target_name = ImportUtils::FBXNodeToName(target->Name()); const Assimp::FBX::PropertyTable &properties = curve_node->Props(); - bool got_x, got_y, got_z; + bool got_x = false, got_y = false, got_z = false; float offset_x = Assimp::FBX::PropertyGet(properties, "d|X", got_x); float offset_y = Assimp::FBX::PropertyGet(properties, "d|Y", got_y); float offset_z = Assimp::FBX::PropertyGet(properties, "d|Z", got_z); diff --git a/thirdparty/assimp_fbx/FBXBinaryTokenizer.cpp b/thirdparty/assimp_fbx/FBXBinaryTokenizer.cpp index b769ed1e2b93..a71b3e3f7423 100644 --- a/thirdparty/assimp_fbx/FBXBinaryTokenizer.cpp +++ b/thirdparty/assimp_fbx/FBXBinaryTokenizer.cpp @@ -96,20 +96,16 @@ namespace FBX { //} // ------------------------------------------------------------------------------------------------ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset) : -#ifdef DEBUG - contents(sbegin, static_cast(send - sbegin)), -#endif sbegin(sbegin), send(send), type(type), line(offset), column(BINARY_MARKER) { - //ai_assert(sbegin); - //ai_assert(send); - - // binary tokens may have zero length because they are sometimes dummies - // inserted by TokenizeBinary() - //ai_assert(send >= sbegin); +#ifdef DEBUG_ENABLED + contents = std::string(sbegin, static_cast(send - sbegin)); +#endif + // calc length + // measure from sBegin to sEnd and validate? } namespace { @@ -410,8 +406,6 @@ 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) { - //ai_assert(input); - //ASSIMP_LOG_DEBUG("Tokenizing binary FBX file"); if (length < 0x1b) { //TokenizeError("file is too short",0); diff --git a/thirdparty/assimp_fbx/FBXMaterial.cpp b/thirdparty/assimp_fbx/FBXMaterial.cpp index a1a016e6ebbb..494b320cfe0d 100644 --- a/thirdparty/assimp_fbx/FBXMaterial.cpp +++ b/thirdparty/assimp_fbx/FBXMaterial.cpp @@ -261,7 +261,21 @@ Video::Video(uint64_t id, const Element &element, const Document &doc, const std const Scope &sc = GetRequiredScope(element); const Element *const Type = sc["Type"]; - const Element *const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows + // File Version 7500 Crashes if this is not checked fully. + // As of writing this comment 7700 exists, in August 2020 + Element * FileName = nullptr; + if(HasElement(sc, "Filename") ) + { + FileName = (Element*) sc["Filename"]; + } + else if(HasElement(sc, "FileName")) + { + FileName = (Element*) sc["FileName"]; + } + else { + print_error("file has invalid video material returning..."); + return; + } const Element *const RelativeFilename = sc["RelativeFilename"]; const Element *const Content = sc["Content"]; diff --git a/thirdparty/assimp_fbx/FBXMeshGeometry.cpp b/thirdparty/assimp_fbx/FBXMeshGeometry.cpp index da92a67238f4..7ad6dcba007f 100644 --- a/thirdparty/assimp_fbx/FBXMeshGeometry.cpp +++ b/thirdparty/assimp_fbx/FBXMeshGeometry.cpp @@ -92,14 +92,11 @@ const Skin *Geometry::DeformerSkin() const { // ------------------------------------------------------------------------------------------------ MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::string &name, const Document &doc) : Geometry(id, element, name, doc) { - const Scope *sc = element.Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Mesh), no data scope found"); - } + print_verbose("mesh name: " + String(name.c_str()) ); - if (!HasElement(*sc, "Vertices")) { - return; // this happened! - } + const Scope *sc = element.Compound(); + ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash"); + ERR_FAIL_COND_MSG(!HasElement(*sc, "Vertices"), "Detected mesh with no vertexes, didn't populate the mesh"); // must have Mesh elements: const Element &Vertices = GetRequiredElement(*sc, "Vertices", &element); @@ -110,84 +107,90 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::strin ParseVectorDataArray(m_edges, element_edges); } - // optional Mesh elements: - const ElementCollection &Layer = sc->GetCollection("Layer"); - // read mesh data into arrays - // todo: later we can actually store arrays for these :) - // and not vector3 ParseVectorDataArray(m_vertices, Vertices); ParseVectorDataArray(m_face_indices, PolygonVertexIndex); - if (m_vertices.empty()) { - print_error("encountered mesh with no vertices"); - } + ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertexes in FBX file, did you mean to delete it?"); + ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?"); - if (m_face_indices.empty()) { - print_error("encountered mesh with no faces"); - } + // Retrieve layer elements, for all of the mesh + const ElementCollection &Layer = sc->GetCollection("Layer"); + + // Store all layers + std::vector> valid_layers; // now read the sub mesh information from the geometry (normals, uvs, etc) for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { - //const TokenList &tokens = (*it).second->Tokens(); - const Scope &layer = GetRequiredScope(*(*it).second); - const ElementCollection &LayerElement = layer.GetCollection("LayerElement"); + const Scope *layer = GetRequiredScope(it->second); + const ElementCollection &LayerElement = layer->GetCollection("LayerElement"); for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { - std::string layer_name = (*eit).first; - Element *element_layer = (*eit).second; + std::string layer_name = eit->first; + Element *element_layer = eit->second; const Scope &layer_element = GetRequiredScope(*element_layer); + + // Actual usable 'type' LayerElementUV, LayerElementNormal, etc const Element &Type = GetRequiredElement(layer_element, "Type"); const Element &TypedIndex = GetRequiredElement(layer_element, "TypedIndex"); const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0)); const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0)); - // get object / mesh directly from the FBX by the element ID. - const Scope &top = GetRequiredScope(element); - - // Get collection of elements from the NormalLayerMap - // this must contain our proper elements. - const ElementCollection candidates = top.GetCollection(type); - - /* typedef std::vector< Scope* > ScopeList; - * typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; - * typedef std::pair ElementCollection; - */ - - for (ElementMap::const_iterator cand_iter = candidates.first; cand_iter != candidates.second; ++cand_iter) { - std::string val = (*cand_iter).first; - //Element *element = (*canditer).second; - - const Scope &layer_scope = GetRequiredScope(*(*cand_iter).second); - const Token &layer_token = GetRequiredToken(*(*cand_iter).second, 0); - const int index = ParseTokenAsInt(layer_token); - if (index == typedIndex) { - const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(layer_scope, "MappingInformationType"), 0)); - - const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(layer_scope, "ReferenceInformationType"), 0)); - - // Not required: - // LayerElementTangent - // LayerElementBinormal - perpendicular to tangent. - if (type == "LayerElementUV") { - if (index == 0) { - m_uv_0 = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); - } else if (index == 1) { - m_uv_1 = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); - } - } else if (type == "LayerElementMaterial") { - m_material_allocation_ids = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Materials"); - } else if (type == "LayerElementNormal") { - m_normals = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Normals"); - } else if (type == "LayerElementColor") { - m_colors = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Colors"); + // we only need the layer name and the typed index. + valid_layers.push_back(std::tuple(typedIndex, type)); + } + } + + // get object / mesh directly from the FBX by the element ID. + const Scope &top = GetRequiredScope(element); + + // iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc) + for( size_t x = 0; x < valid_layers.size(); x++) { + const int layer_id = std::get<0>(valid_layers[x]); + const std::string &layer_type_name = std::get<1>(valid_layers[x]); + + // Get collection of elements from the XLayerMap (example: LayerElementUV) + // this must contain our proper elements. + + // This is stupid, because it means we select them ALL not just the one we want. + // but it's fine we can match by id. + GetRequiredElement(top, layer_type_name); + const ElementCollection &candidates = top.GetCollection(layer_type_name); + + ElementMap::const_iterator iter; + for( iter = candidates.first; iter != candidates.second; ++iter) + { + const Scope *layer_scope = GetRequiredScope(iter->second); + TokenPtr layer_token = GetRequiredToken(iter->second, 0); + const int index = ParseTokenAsInt(*layer_token); + + ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid"); + + if (index == layer_id) { + const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken( + GetRequiredElement(*layer_scope, "MappingInformationType"), 0)); + + const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken( + GetRequiredElement(*layer_scope, "ReferenceInformationType"), 0)); + + if (layer_type_name == "LayerElementUV") { + if (index == 0) { + m_uv_0 = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); + } else if (index == 1) { + m_uv_1 = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "UV"); } + } else if (layer_type_name == "LayerElementMaterial") { + m_material_allocation_ids = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Materials"); + } else if (layer_type_name == "LayerElementNormal") { + m_normals = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Normals"); + } else if (layer_type_name == "LayerElementColor") { + m_colors = resolve_vertex_data_array(layer_scope, MappingInformationType, ReferenceInformationType, "Colors"); } } } } + print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size()) ); + // Compose the edge of the mesh. // You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6 for (size_t i = 0; i < m_edges.size(); i += 1) { @@ -196,7 +199,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element &element, const std::strin int polygon_vertex_1; if (polygon_vertex_0 < 0) { // The polygon_vertex_0 points to the end of a polygon, so it's - // connected with the begining of polygon in the edge list. + // connected with the beginning of polygon in the edge list. // Fist invert the vertex. polygon_vertex_0 = ~polygon_vertex_0; @@ -268,12 +271,12 @@ const MeshGeometry::MappingData &MeshGeometry::get_normals() const { } const MeshGeometry::MappingData &MeshGeometry::get_uv_0() const { - print_verbose("uv 0 size: " + itos(m_uv_0.data.size())); + print_verbose("get uv_0 " + m_uv_0.debug_info() ); return m_uv_0; } const MeshGeometry::MappingData &MeshGeometry::get_uv_1() const { - print_verbose("uv 1 size: " + itos(m_uv_1.data.size())); + print_verbose("get uv_1 " + m_uv_1.debug_info() ); return m_uv_1; } @@ -301,26 +304,29 @@ MeshGeometry::Edge MeshGeometry::get_edge(const std::vector &p_map, int p_ template MeshGeometry::MappingData MeshGeometry::resolve_vertex_data_array( - const Scope &source, + const Scope *source, const std::string &MappingInformationType, const std::string &ReferenceInformationType, const std::string &dataElementName) { + ERR_FAIL_COND_V_MSG(source == nullptr, MappingData(), "Invalid scope operator preventing memory corruption"); + // UVIndex, MaterialIndex, NormalIndex, etc.. std::string indexDataElementName = dataElementName + "Index"; // goal: expand everything to be per vertex ReferenceType l_ref_type = ReferenceType::direct; - // purposefully merging legacy to IndexToDirect - if (ReferenceInformationType == "IndexToDirect" || ReferenceInformationType == "Index") { - // set non legacy index to direct mapping + // Read the reference type into the enumeration + if (ReferenceInformationType == "IndexToDirect") { l_ref_type = ReferenceType::index_to_direct; - - // override invalid files - should not happen but if it does we're safe. - if (!HasElement(source, indexDataElementName)) { - l_ref_type = ReferenceType::direct; - } + } else if (ReferenceInformationType == "Index") { + // set non legacy index to direct mapping + l_ref_type = ReferenceType::index; + } else if(ReferenceInformationType == "Direct") { + l_ref_type = ReferenceType::direct; + } else { + ERR_FAIL_V_MSG(MappingData(), "invalid reference type has the FBX format changed?"); } MapType l_map_type = MapType::none; @@ -347,10 +353,10 @@ MeshGeometry::MappingData MeshGeometry::resolve_vertex_data_array( tempData.ref_type = l_ref_type; // parse data into array - ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName)); + ParseVectorDataArray(tempData.data, GetRequiredElement(*source, dataElementName)); // index array wont always exist - const Element *element = GetOptionalElement(source, indexDataElementName); + const Element *element = GetOptionalElement(*source, indexDataElementName); if (element) { ParseVectorDataArray(tempData.index, *element); } diff --git a/thirdparty/assimp_fbx/FBXMeshGeometry.h b/thirdparty/assimp_fbx/FBXMeshGeometry.h index efe2e50ddc46..5da3044ffcec 100644 --- a/thirdparty/assimp_fbx/FBXMeshGeometry.h +++ b/thirdparty/assimp_fbx/FBXMeshGeometry.h @@ -114,7 +114,8 @@ class MeshGeometry : public Geometry { enum class ReferenceType { direct = 0, - index_to_direct = 1 + index = 1, + index_to_direct = 2 }; template @@ -125,6 +126,11 @@ class MeshGeometry : public Geometry { /// The meaning of the indices depends from the `MapType`. /// If `ref_type` is `direct` this map is hollow. std::vector index; + + String debug_info() const + { + return "indexes: " + itos(index.size()) + " data: " +itos(data.size()); + } }; struct Edge { @@ -170,7 +176,7 @@ class MeshGeometry : public Geometry { template MappingData resolve_vertex_data_array( - const Scope &source, + const Scope *source, const std::string &MappingInformationType, const std::string &ReferenceInformationType, const std::string &dataElementName); diff --git a/thirdparty/assimp_fbx/FBXParser.cpp b/thirdparty/assimp_fbx/FBXParser.cpp index 256208319fd1..bdf501140e09 100644 --- a/thirdparty/assimp_fbx/FBXParser.cpp +++ b/thirdparty/assimp_fbx/FBXParser.cpp @@ -337,6 +337,7 @@ int ParseTokenAsInt(const Token &t, const char *&err_out) { return 0; } + // binary files are simple to parse if (t.IsBinary()) { const char *data = t.begin(); if (data[0] != 'I') { @@ -349,6 +350,9 @@ int ParseTokenAsInt(const Token &t, const char *&err_out) { return static_cast(ival); } + + // ASCII files are unsafe. + const size_t length = static_cast(t.end() - t.begin()); if (length == 0) { err_out = "expected valid integer number after asterisk"; @@ -1151,6 +1155,38 @@ const Scope &GetRequiredScope(const Element &el) { return *s; } +// ------------------------------------------------------------------------------------------------ +// extract required compound scope +const Scope *GetRequiredScope(const Element *el) { + if(el) { + const Scope *s = el->Compound(); + if (s) { + return s; + } + + ERR_FAIL_V_MSG(nullptr,"expected compound scope " + String(el->KeyToken().StringContents().c_str())); + } + + ERR_FAIL_V_MSG(nullptr, "Invalid element supplied to parser"); +} + + +// ------------------------------------------------------------------------------------------------ +// get token at a particular index +TokenPtr GetRequiredToken(const Element *el, unsigned int index) { + if(el) { + const TokenList& x = el->Tokens(); + + if (index >= x.size()) { + ERR_FAIL_V_MSG(nullptr,"missing token at index: " + itos(index) + " " + String(el->KeyToken().StringContents().c_str())); + } + + return x[index]; + } + + return nullptr; +} + // ------------------------------------------------------------------------------------------------ // get token at a particular index const Token &GetRequiredToken(const Element &el, unsigned int index) { diff --git a/thirdparty/assimp_fbx/FBXParser.h b/thirdparty/assimp_fbx/FBXParser.h index 7204c34ea499..0059eb22ec27 100644 --- a/thirdparty/assimp_fbx/FBXParser.h +++ b/thirdparty/assimp_fbx/FBXParser.h @@ -103,9 +103,9 @@ class Element { } private: - const Token &key_token; + const Token key_token; TokenList tokens; - std::unique_ptr compound; + std::shared_ptr compound = nullptr; }; /** FBX data entity that consists of a 'scope', a collection @@ -126,7 +126,7 @@ class Scope { const Element *operator[](const std::string &index) const { ElementMap::const_iterator it = elements.find(index); - return it == elements.end() ? NULL : (*it).second; + return it == elements.end() ? nullptr : (*it).second; } const Element *FindElementCaseInsensitive(const std::string &elementName) const { @@ -178,9 +178,9 @@ class Parser { private: const TokenList &tokens; - TokenPtr last, current; + TokenPtr last = nullptr, current = nullptr; TokenList::const_iterator cursor; - std::unique_ptr root; + std::shared_ptr root = nullptr; const bool is_binary; }; @@ -215,12 +215,15 @@ bool HasElement(const Scope &sc, const std::string &index); // extract a required element from a scope, abort if the element cannot be found const Element &GetRequiredElement(const Scope &sc, const std::string &index, const Element *element = nullptr); +const Scope *GetRequiredScope(const Element *el); // New in 2020. (less likely to destroy application) const Element *GetOptionalElement(const Scope &sc, const std::string &index, const Element *element = nullptr); // extract required compound scope const Scope &GetRequiredScope(const Element &el); // get token at a particular index const Token &GetRequiredToken(const Element &el, unsigned int index); +TokenPtr GetRequiredToken(const Element *el, unsigned int index); // New 2020 +// ------------------------------------------------------------------------------------------------ // read a 4x4 matrix from an array of 16 floats Transform ReadMatrix(const Element &element); diff --git a/thirdparty/assimp_fbx/FBXTokenizer.cpp b/thirdparty/assimp_fbx/FBXTokenizer.cpp index b5187f794d09..ea18d6ddc967 100644 --- a/thirdparty/assimp_fbx/FBXTokenizer.cpp +++ b/thirdparty/assimp_fbx/FBXTokenizer.cpp @@ -55,14 +55,15 @@ namespace FBX { // ------------------------------------------------------------------------------------------------ Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) : -#ifdef DEBUG - contents(sbegin, static_cast(send - sbegin)), -#endif sbegin(p_sbegin), send(p_send), type(p_type), line(p_line), - column(p_column) { + column(p_column) +{ +#ifdef DEBUG_ENABLED + contents = std::string(sbegin, static_cast(send - sbegin)); +#endif } // ------------------------------------------------------------------------------------------------ diff --git a/thirdparty/assimp_fbx/FBXTokenizer.h b/thirdparty/assimp_fbx/FBXTokenizer.h index b12688c69ad3..ccc0c81f7863 100644 --- a/thirdparty/assimp_fbx/FBXTokenizer.h +++ b/thirdparty/assimp_fbx/FBXTokenizer.h @@ -127,21 +127,21 @@ class Token { } private: -#ifdef DEBUG +#ifdef DEBUG_ENABLED // full string copy for the sole purpose that it nicely appears // in msvc's debugger window. - const std::string contents; + std::string contents; #endif - const char *const sbegin; - const char *const send; + const char * sbegin = nullptr; + const char * send = nullptr; const TokenType type; union { size_t line; size_t offset; }; - const unsigned int column; + const unsigned int column = 0; }; // Fixed leak by using shared_ptr for tokens