diff options
| -rw-r--r-- | core/io/image.cpp | 96 | ||||
| -rw-r--r-- | core/io/image.h | 20 | ||||
| -rw-r--r-- | doc/classes/EditorFileSystem.xml | 6 | ||||
| -rw-r--r-- | doc/classes/Script.xml | 1 | ||||
| -rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.cpp | 2 | ||||
| -rw-r--r-- | drivers/gles3/storage/texture_storage.cpp | 2 | ||||
| -rw-r--r-- | editor/editor_file_system.cpp | 20 | ||||
| -rw-r--r-- | editor/editor_node.cpp | 276 | ||||
| -rw-r--r-- | editor/editor_node.h | 18 | ||||
| -rw-r--r-- | editor/project_manager/project_dialog.cpp | 19 | ||||
| -rw-r--r-- | misc/extension_api_validation/4.2-stable.expected | 8 | ||||
| -rw-r--r-- | modules/basis_universal/image_compress_basisu.cpp | 3 | ||||
| -rw-r--r-- | modules/squish/image_decompress_squish.cpp | 5 | ||||
| -rw-r--r-- | platform/windows/detect.py | 3 | ||||
| -rw-r--r-- | tests/core/io/test_image.h | 12 |
15 files changed, 323 insertions, 168 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index 4b1188ad47..0af0bf7d6a 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -300,10 +300,10 @@ int Image::get_format_block_size(Format p_format) { return 1; } -void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const { +void Image::_get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const { int w = width; int h = height; - int ofs = 0; + int64_t ofs = 0; int pixel_size = get_format_pixel_size(format); int pixel_rshift = get_format_pixel_rshift(format); @@ -315,7 +315,7 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_widt int bw = w % block != 0 ? w + (block - w % block) : w; int bh = h % block != 0 ? h + (block - h % block) : h; - int s = bw * bh; + int64_t s = bw * bh; s *= pixel_size; s >>= pixel_rshift; @@ -329,37 +329,30 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_widt r_height = h; } -int Image::get_mipmap_offset(int p_mipmap) const { +int64_t Image::get_mipmap_offset(int p_mipmap) const { ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1); - int ofs, w, h; + int64_t ofs; + int w, h; _get_mipmap_offset_and_size(p_mipmap, ofs, w, h); return ofs; } -int Image::get_mipmap_byte_size(int p_mipmap) const { - ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1); - - int ofs, w, h; - _get_mipmap_offset_and_size(p_mipmap, ofs, w, h); - int ofs2; - _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w, h); - return ofs2 - ofs; -} - -void Image::get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const { - int ofs, w, h; +void Image::get_mipmap_offset_and_size(int p_mipmap, int64_t &r_ofs, int64_t &r_size) const { + int64_t ofs; + int w, h; _get_mipmap_offset_and_size(p_mipmap, ofs, w, h); - int ofs2; + int64_t ofs2; _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w, h); r_ofs = ofs; r_size = ofs2 - ofs; } -void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const { - int ofs; +void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap, int64_t &r_ofs, int64_t &r_size, int &w, int &h) const { + int64_t ofs; _get_mipmap_offset_and_size(p_mipmap, ofs, w, h); - int ofs2, w2, h2; + int64_t ofs2; + int w2, h2; _get_mipmap_offset_and_size(p_mipmap + 1, ofs2, w2, h2); r_ofs = ofs; r_size = ofs2 - ofs; @@ -538,8 +531,8 @@ void Image::convert(Format p_new_format) { } } - int mip_offset = 0; - int mip_size = 0; + int64_t mip_offset = 0; + int64_t mip_size = 0; new_img.get_mipmap_offset_and_size(mip, mip_offset, mip_size); memcpy(new_img.data.ptrw() + mip_offset, new_mip->data.ptr(), mip_size); @@ -555,8 +548,8 @@ void Image::convert(Format p_new_format) { int conversion_type = format | p_new_format << 8; for (int mip = 0; mip < mipmap_count; mip++) { - int mip_offset = 0; - int mip_size = 0; + int64_t mip_offset = 0; + int64_t mip_size = 0; int mip_width = 0; int mip_height = 0; get_mipmap_offset_size_and_dimensions(mip, mip_offset, mip_size, mip_width, mip_height); @@ -1151,7 +1144,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { if (i == 0) { // Read from the first mipmap that will be interpolated // (if both levels are the same, we will not interpolate, but at least we'll sample from the right level) - int offs; + int64_t offs; _get_mipmap_offset_and_size(mip1, offs, src_width, src_height); src_ptr = r_ptr + offs; } else if (!interpolate_mipmaps) { @@ -1159,7 +1152,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { break; } else { // Switch to read from the second mipmap that will be interpolated - int offs; + int64_t offs; _get_mipmap_offset_and_size(mip2, offs, src_width, src_height); src_ptr = r_ptr + offs; // Switch to write to the second destination image @@ -1599,9 +1592,9 @@ void Image::flip_x() { } /// Get mipmap size and offset. -int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { +int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { // Data offset in mipmaps (including the original texture). - int size = 0; + int64_t size = 0; int w = p_width; int h = p_height; @@ -1623,7 +1616,7 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & int bw = w % block != 0 ? w + (block - w % block) : w; int bh = h % block != 0 ? h + (block - h % block) : h; - int s = bw * bh; + int64_t s = bw * bh; s *= pixsize; s >>= pixshift; @@ -1837,7 +1830,8 @@ Error Image::generate_mipmaps(bool p_renormalize) { int prev_w = width; for (int i = 1; i <= mmcount; i++) { - int ofs, w, h; + int64_t ofs; + int w, h; _get_mipmap_offset_and_size(i, ofs, w, h); switch (format) { @@ -1993,7 +1987,8 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con uint8_t *base_ptr = data.ptrw(); for (int i = 1; i <= mmcount; i++) { - int ofs, w, h; + int64_t ofs; + int w, h; _get_mipmap_offset_and_size(i, ofs, w, h); uint8_t *ptr = &base_ptr[ofs]; @@ -2102,21 +2097,6 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con _set_color_at_ofs(ptr, pixel_ofs, c); } } -#if 0 - { - int size = get_mipmap_byte_size(i); - print_line("size for mimpap " + itos(i) + ": " + itos(size)); - Vector<uint8_t> imgdata; - imgdata.resize(size); - - - uint8_t* wr = imgdata.ptrw(); - memcpy(wr.ptr(), ptr, size); - wr = uint8_t*(); - Ref<Image> im = Image::create_from_data(w, h, false, format, imgdata); - im->save_png("res://mipmap_" + itos(i) + ".png"); - } -#endif } return OK; @@ -2131,7 +2111,8 @@ void Image::clear_mipmaps() { return; } - int ofs, w, h; + int64_t ofs; + int w, h; _get_mipmap_offset_and_size(1, ofs, w, h); data.resize(ofs); @@ -2176,7 +2157,7 @@ void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Forma ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum."); int mm = 0; - int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); + int64_t size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); data.resize(size); { @@ -2202,7 +2183,7 @@ void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Forma ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum."); int mm; - int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); + int64_t size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); if (unlikely(p_data.size() != size)) { String description_mipmaps = get_format_name(p_format) + " "; @@ -2405,7 +2386,7 @@ bool Image::is_invisible() const { return false; } - int len = data.size(); + int64_t len = data.size(); if (len == 0) { return true; @@ -2445,7 +2426,7 @@ bool Image::is_invisible() const { } Image::AlphaMode Image::detect_alpha() const { - int len = data.size(); + int64_t len = data.size(); if (len == 0) { return ALPHA_NONE; @@ -2597,7 +2578,7 @@ Size2i Image::get_image_mipmap_size(int p_width, int p_height, Format p_format, return ret; } -int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) { +int64_t Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) { if (p_mipmap <= 0) { return 0; } @@ -2605,7 +2586,7 @@ int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, i return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap - 1); } -int Image::get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h) { +int64_t Image::get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h) { if (p_mipmap <= 0) { r_w = p_width; r_h = p_height; @@ -3642,9 +3623,10 @@ Ref<Image> Image::rgbe_to_srgb() { return new_image; } -Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const { - int ofs, size, w, h; - get_mipmap_offset_size_and_dimensions(p_mipamp, ofs, size, w, h); +Ref<Image> Image::get_image_from_mipmap(int p_mipmap) const { + int64_t ofs, size; + int w, h; + get_mipmap_offset_size_and_dimensions(p_mipmap, ofs, size, w, h); Vector<uint8_t> new_data; new_data.resize(size); diff --git a/core/io/image.h b/core/io/image.h index d3ae99954f..745bb140bd 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -195,9 +195,9 @@ private: data = p_image.data; } - _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data + _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data - static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr); + static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr); bool _can_modify(Format p_format) const; _FORCE_INLINE_ void _get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const; @@ -238,10 +238,12 @@ public: */ Format get_format() const; - int get_mipmap_byte_size(int p_mipmap) const; //get where the mipmap begins in data - int get_mipmap_offset(int p_mipmap) const; //get where the mipmap begins in data - void get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const; //get where the mipmap begins in data - void get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const; //get where the mipmap begins in data + /** + * Get where the mipmap begins in data. + */ + int64_t get_mipmap_offset(int p_mipmap) const; + void get_mipmap_offset_and_size(int p_mipmap, int64_t &r_ofs, int64_t &r_size) const; + void get_mipmap_offset_size_and_dimensions(int p_mipmap, int64_t &r_ofs, int64_t &r_size, int &w, int &h) const; enum Image3DValidateError { VALIDATE_3D_OK, @@ -354,8 +356,8 @@ public: static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false); static int get_image_required_mipmaps(int p_width, int p_height, Format p_format); static Size2i get_image_mipmap_size(int p_width, int p_height, Format p_format, int p_mipmap); - static int get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap); - static int get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h); + static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap); + static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h); enum CompressMode { COMPRESS_S3TC, @@ -383,7 +385,7 @@ public: void srgb_to_linear(); void normal_map_to_xy(); Ref<Image> rgbe_to_srgb(); - Ref<Image> get_image_from_mipmap(int p_mipamp) const; + Ref<Image> get_image_from_mipmap(int p_mipmap) const; void bump_map_to_normal_map(float bump_scale = 1.0); void blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest); diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index 08b40c7800..06fa4be2c8 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -84,6 +84,12 @@ Emitted if a resource is reimported. </description> </signal> + <signal name="resources_reimporting"> + <param index="0" name="resources" type="PackedStringArray" /> + <description> + Emitted before a resource is reimported. + </description> + </signal> <signal name="resources_reload"> <param index="0" name="resources" type="PackedStringArray" /> <description> diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml index fa8e4ef5f2..45f0bbb8aa 100644 --- a/doc/classes/Script.xml +++ b/doc/classes/Script.xml @@ -93,6 +93,7 @@ <return type="bool" /> <description> Returns [code]true[/code] if the script contains non-empty source code. + [b]Note:[/b] If a script does not have source code, this does not mean that it is invalid or unusable. For example, a [GDScript] that was exported with binary tokenization has no source code, but still behaves as expected and could be instantiated. This can be checked with [method can_instantiate]. </description> </method> <method name="instance_has" qualifiers="const"> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index a6796a1a6b..84b6ab4bd8 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1420,7 +1420,7 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const #else bool force_alpha = false; #endif - if (!force_alpha && (surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) { + if (!force_alpha && (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE))) { rl->add_element(surf); } if (force_alpha || (surf->flags & GeometryInstanceSurface::FLAG_PASS_ALPHA)) { diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 9138045653..3b1373c928 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1491,7 +1491,7 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image, int tsize = 0; for (int i = 0; i < mipmaps; i++) { - int size, ofs; + int64_t size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); if (compressed) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 54a28d9cb1..a163833e50 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -2603,11 +2603,15 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, HashMap } void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params) { + Vector<String> reloads; + reloads.append(p_file); + + // Emit the resource_reimporting signal for the single file before the actual importation. + emit_signal(SNAME("resources_reimporting"), reloads); + _reimport_file(p_file, p_custom_params, p_importer); // Emit the resource_reimported signal for the single file we just reimported. - Vector<String> reloads; - reloads.append(p_file); emit_signal(SNAME("resources_reimported"), reloads); } @@ -2669,6 +2673,9 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { reimport_files.sort(); + // Emit the resource_reimporting signal for the single file before the actual importation. + emit_signal(SNAME("resources_reimporting"), reloads); + #ifdef THREADS_ENABLED bool use_multiple_threads = GLOBAL_GET("editor/import/use_multiple_threads"); #else @@ -2763,11 +2770,15 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { Error EditorFileSystem::reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) { ERR_FAIL_COND_V_MSG(!importing, ERR_INVALID_PARAMETER, "Can only append files to import during a current reimport process."); + Vector<String> reloads; + reloads.append(p_file); + + // Emit the resource_reimporting signal for the single file before the actual importation. + emit_signal(SNAME("resources_reimporting"), reloads); + Error ret = _reimport_file(p_file, p_custom_options, p_custom_importer, &p_generator_parameters); // Emit the resource_reimported signal for the single file we just reimported. - Vector<String> reloads; - reloads.append(p_file); emit_signal(SNAME("resources_reimported"), reloads); return ret; } @@ -2967,6 +2978,7 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("filesystem_changed")); ADD_SIGNAL(MethodInfo("script_classes_updated")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); + ADD_SIGNAL(MethodInfo("resources_reimporting", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 941b1d00a2..cb647ffc35 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1036,24 +1036,37 @@ void EditorNode::_fs_changed() { } } +void EditorNode::_resources_reimporting(const Vector<String> &p_resources) { + // This will copy all the modified properties of the nodes into 'scenes_modification_table' + // before they are actually reimported. It's important to do this before the reimportation + // because if a mesh is present in an inherited scene, the resource will be modified in + // the inherited scene. Then, get_modified_properties_for_node will return the mesh property, + // which will trigger a recopy of the previous mesh, preventing the reload. + for (const String &res_path : p_resources) { + if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { + preload_reimporting_with_path_in_edited_scenes(res_path); + } + } +} + void EditorNode::_resources_reimported(const Vector<String> &p_resources) { List<String> scenes; int current_tab = scene_tabs->get_current_tab(); - for (int i = 0; i < p_resources.size(); i++) { - String file_type = ResourceLoader::get_resource_type(p_resources[i]); + for (const String &res_path : p_resources) { + String file_type = ResourceLoader::get_resource_type(res_path); if (file_type == "PackedScene") { - scenes.push_back(p_resources[i]); + scenes.push_back(res_path); // Reload later if needed, first go with normal resources. continue; } - if (!ResourceCache::has(p_resources[i])) { + if (!ResourceCache::has(res_path)) { // Not loaded, no need to reload. continue; } // Reload normally. - Ref<Resource> resource = ResourceCache::get_ref(p_resources[i]); + Ref<Resource> resource = ResourceCache::get_ref(res_path); if (resource.is_valid()) { resource->reload_from_file(); } @@ -4166,15 +4179,6 @@ HashMap<StringName, Variant> EditorNode::get_modified_properties_for_node(Node * return modified_property_map; } -void EditorNode::update_ownership_table_for_addition_node_ancestors(Node *p_current_node, HashMap<Node *, Node *> &p_ownership_table) { - p_ownership_table.insert(p_current_node, p_current_node->get_owner()); - - for (int i = 0; i < p_current_node->get_child_count(); i++) { - Node *child = p_current_node->get_child(i); - update_ownership_table_for_addition_node_ancestors(child, p_ownership_table); - } -} - void EditorNode::update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification) { if (p_node) { // First, attempt to restore the script property since it may affect the get_property_list method. @@ -4283,15 +4287,24 @@ void EditorNode::update_node_reference_modification_table_for_node( } } -void EditorNode::update_reimported_diff_data_for_node( - Node *p_edited_scene, - Node *p_reimported_root, - Node *p_node, - HashMap<NodePath, ModificationNodeEntry> &p_modification_table, - List<AdditiveNodeEntry> &p_addition_list) { +bool EditorNode::is_additional_node_in_scene(Node *p_edited_scene, Node *p_reimported_root, Node *p_node) { + if (p_node == p_reimported_root) { + return false; + } + bool node_part_of_subscene = p_node != p_edited_scene && p_edited_scene->get_scene_inherited_state().is_valid() && - p_edited_scene->get_scene_inherited_state()->find_node_by_path(p_edited_scene->get_path_to(p_node)) >= 0; + p_edited_scene->get_scene_inherited_state()->find_node_by_path(p_edited_scene->get_path_to(p_node)) >= 0 && + // It's important to process added nodes from the base scene in the inherited scene as + // additional nodes to ensure they do not disappear on reload. + // When p_reimported_root == p_edited_scene that means the edited scene + // is the reimported scene, in that case the node is in the root base scene, + // so it's not an addition, otherwise, the node would be added twice on reload. + (p_node->get_owner() != p_edited_scene || p_reimported_root == p_edited_scene); + + if (node_part_of_subscene) { + return false; + } // Loop through the owners until either we reach the root node or nullptr Node *valid_node_owner = p_node->get_owner(); @@ -4302,7 +4315,25 @@ void EditorNode::update_reimported_diff_data_for_node( valid_node_owner = valid_node_owner->get_owner(); } - if ((valid_node_owner == p_reimported_root && (p_reimported_root != p_edited_scene || !p_edited_scene->get_scene_file_path().is_empty())) || node_part_of_subscene || p_node == p_reimported_root) { + // When the owner is the imported scene and the owner is also the edited scene, + // that means the node was added in the current edited scene. + // We can be sure here because if the node that the node does not come from + // the base scene because we checked just over with 'get_scene_inherited_state()->find_node_by_path'. + if (valid_node_owner == p_reimported_root && p_reimported_root != p_edited_scene) { + return false; + } + + return true; +} + +void EditorNode::get_preload_scene_modification_table( + Node *p_edited_scene, + Node *p_reimported_root, + Node *p_node, HashMap<NodePath, ModificationNodeEntry> &p_modification_table) { + // Only take the nodes that are in the base imported scene. The additional nodes will be managed + // after the resources are reimported. It's not important to check which property has + // changed on nodes that will not be reimported because they are not part of the reimported scene. + if (!is_additional_node_in_scene(p_edited_scene, p_reimported_root, p_node)) { HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node, false); // Find all valid connections to other nodes. @@ -4363,14 +4394,27 @@ void EditorNode::update_reimported_diff_data_for_node( p_modification_table[p_reimported_root->get_path_to(p_node)] = modification_node_entry; } - } else { + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + get_preload_scene_modification_table(p_edited_scene, p_reimported_root, child, p_modification_table); + } +} + +void EditorNode::update_reimported_diff_data_for_additional_nodes( + Node *p_edited_scene, + Node *p_reimported_root, + Node *p_node, + HashMap<NodePath, ModificationNodeEntry> &p_modification_table, + List<AdditiveNodeEntry> &p_addition_list) { + if (is_additional_node_in_scene(p_edited_scene, p_reimported_root, p_node)) { // Only save additional nodes which have an owner since this was causing issues transient ownerless nodes // which get recreated upon scene tree entry. // For now instead, assume all ownerless nodes are transient and will have to be recreated. if (p_node->get_owner()) { HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node, true); - - if (p_node->get_parent()->get_owner() != nullptr && p_node->get_parent()->get_owner() != p_edited_scene) { + if (p_node->get_owner() == p_edited_scene) { AdditiveNodeEntry new_additive_node_entry; new_additive_node_entry.node = p_node; new_additive_node_entry.parent = p_reimported_root->get_path_to(p_node->get_parent()); @@ -4386,18 +4430,8 @@ void EditorNode::update_reimported_diff_data_for_node( new_additive_node_entry.transform_3d = node_3d->get_relative_transform(node_3d->get_parent()); } - // Gathers the ownership of all ancestor nodes for later use. - HashMap<Node *, Node *> ownership_table; - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *child = p_node->get_child(i); - update_ownership_table_for_addition_node_ancestors(child, ownership_table); - } - - new_additive_node_entry.ownership_table = ownership_table; - p_addition_list.push_back(new_additive_node_entry); } - if (!modified_properties.is_empty()) { ModificationNodeEntry modification_node_entry; modification_node_entry.property_table = modified_properties; @@ -4409,10 +4443,9 @@ void EditorNode::update_reimported_diff_data_for_node( for (int i = 0; i < p_node->get_child_count(); i++) { Node *child = p_node->get_child(i); - update_reimported_diff_data_for_node(p_edited_scene, p_reimported_root, child, p_modification_table, p_addition_list); + update_reimported_diff_data_for_additional_nodes(p_edited_scene, p_reimported_root, child, p_modification_table, p_addition_list); } } -// void EditorNode::open_request(const String &p_path) { if (!opening_prev) { @@ -5784,6 +5817,25 @@ void EditorNode::reload_scene(const String &p_path) { scene_tabs->set_current_tab(current_tab); } +void EditorNode::get_edited_scene_map(const String &p_instance_path, HashMap<int, List<Node *>> &p_edited_scene_map) { + // Walk through each opened scene to get a global list of all instances which match + // the current reimported scenes. + for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { + if (editor_data.get_scene_path(i) == p_instance_path) { + continue; + } + Node *edited_scene_root = editor_data.get_edited_scene_root(i); + + if (edited_scene_root) { + List<Node *> valid_nodes; + find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, p_instance_path, valid_nodes); + if (valid_nodes.size() > 0) { + p_edited_scene_map[i] = valid_nodes; + } + } + } +} + void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list) { String scene_file_path = p_node->get_scene_file_path(); @@ -5811,25 +5863,54 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node * } } -void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) { +void EditorNode::preload_reimporting_with_path_in_edited_scenes(const String &p_instance_path) { HashMap<int, List<Node *>> edited_scene_map; - Array replaced_nodes; + scenes_modification_table.clear(); - // Walk through each opened scene to get a global list of all instances which match - // the current reimported scenes. - for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { - if (editor_data.get_scene_path(i) != p_instance_path) { - Node *edited_scene_root = editor_data.get_edited_scene_root(i); - - if (edited_scene_root) { - List<Node *> valid_nodes; - find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, p_instance_path, valid_nodes); - if (valid_nodes.size() > 0) { - edited_scene_map[i] = valid_nodes; + get_edited_scene_map(p_instance_path, edited_scene_map); + + if (edited_scene_map.size() > 0) { + scenes_modification_table.clear(); + + int original_edited_scene_idx = editor_data.get_edited_scene(); + Node *original_edited_scene_root = editor_data.get_edited_scene_root(); + + // Prevent scene roots with the same name from being in the tree at the same time. + scene_root->remove_child(original_edited_scene_root); + + for (const KeyValue<int, List<Node *>> &edited_scene_map_elem : edited_scene_map) { + // Set the current scene. + int current_scene_idx = edited_scene_map_elem.key; + editor_data.set_edited_scene(current_scene_idx); + Node *current_edited_scene = editor_data.get_edited_scene_root(current_scene_idx); + + // Make sure the node is in the tree so that editor_selection can add node smoothly. + scene_root->add_child(current_edited_scene); + + for (Node *original_node : edited_scene_map_elem.value) { + // Fetching all the modified properties of the nodes reimported scene. + HashMap<NodePath, ModificationNodeEntry> modification_table; + get_preload_scene_modification_table(current_edited_scene, original_node, original_node, modification_table); + + if (modification_table.size() > 0) { + NodePath scene_path_to_node = current_edited_scene->get_path_to(original_node); + scenes_modification_table[current_scene_idx][scene_path_to_node] = modification_table; } } + + scene_root->remove_child(current_edited_scene); } + + editor_data.set_edited_scene(original_edited_scene_idx); + scene_root->add_child(original_edited_scene_root); } +} + +void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) { + HashMap<int, List<Node *>> edited_scene_map; + Array replaced_nodes; + + get_edited_scene_map(p_instance_path, edited_scene_map); if (edited_scene_map.size() > 0) { // Reload the new instance. @@ -5883,6 +5964,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins // Load a replacement scene for the node. Ref<PackedScene> current_packed_scene; + Ref<PackedScene> base_packed_scene; if (original_node_file_path == p_instance_path) { // If the node file name directly matches the scene we're replacing, // just load it since we already cached it. @@ -5909,6 +5991,9 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins // Ensure the inheritance chain is loaded in the correct order so that cache can // be properly updated. for (String path : required_load_paths) { + if (current_packed_scene.is_valid()) { + base_packed_scene = current_packed_scene; + } if (!local_scene_cache.find(path)) { current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err); local_scene_cache[path] = current_packed_scene; @@ -5921,15 +6006,58 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins ERR_FAIL_COND(current_packed_scene.is_null()); // Instantiate early so that caches cleared on load in SceneState can be rebuilt early. - Node *instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + Node *instantiated_node = nullptr; + + // If we are in a inherit scene, it's easier to create a new base scene and + // grab the node from there. + // When scene_path_to_node is '.' and we have scene_inherited_state, it's because + // it's a muli-level inheritance scene. We should use + NodePath scene_path_to_node = current_edited_scene->get_path_to(original_node); + Ref<SceneState> scene_state = current_edited_scene->get_scene_inherited_state(); + if (scene_path_to_node != "." && scene_state.is_valid() && scene_state->get_path() != p_instance_path && scene_state->find_node_by_path(scene_path_to_node) >= 0) { + Node *root_node = scene_state->instantiate(SceneState::GenEditState::GEN_EDIT_STATE_INSTANCE); + instantiated_node = root_node->get_node(scene_path_to_node); + + if (instantiated_node) { + if (instantiated_node->get_parent()) { + // Remove from the root so we can delete it from memory. + instantiated_node->get_parent()->remove_child(instantiated_node); + // No need of the additional children that could have been added to the node + // in the base scene. That will be managed by the 'addition_list' later. + _remove_all_not_owned_children(instantiated_node, instantiated_node); + memdelete(root_node); + } + } else { + // Should not happen because we checked with find_node_by_path before, just in case. + memdelete(root_node); + } + } + if (!instantiated_node) { + // If no base scene was found to create the node, we will use the reimported packed scene directly. + // But, when the current edited scene is the reimported scene, it's because it's a inherited scene + // of the reimported scene. In that case, we will not instantiate current_packed_scene, because + // we would reinstanciate ourself. Using the base scene is better. + if (current_edited_scene == original_node) { + if (base_packed_scene.is_valid()) { + instantiated_node = base_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + } else { + instantiated_node = instance_scene_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + } + } else { + instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + } + } ERR_FAIL_NULL(instantiated_node); // Walk the tree for the current node and extract relevant diff data, storing it in the modification table. // For additional nodes which are part of the current scene, they get added to the addition table. HashMap<NodePath, ModificationNodeEntry> modification_table; List<AdditiveNodeEntry> addition_list; - update_reimported_diff_data_for_node(current_edited_scene, original_node, original_node, modification_table, addition_list); + if (scenes_modification_table.has(current_scene_idx) && scenes_modification_table[current_scene_idx].has(scene_path_to_node)) { + modification_table = scenes_modification_table[current_scene_idx][scene_path_to_node]; + } + update_reimported_diff_data_for_additional_nodes(current_edited_scene, original_node, original_node, modification_table, addition_list); // Disconnect all relevant connections, all connections from and persistent connections to. for (const KeyValue<NodePath, ModificationNodeEntry> &modification_table_entry : modification_table) { @@ -5991,16 +6119,11 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins // Is this replacing the edited root node? if (current_edited_scene == original_node) { - instantiated_node->set_scene_instance_state(original_node->get_scene_instance_state()); - // Fix unsaved inherited scene - if (original_node_file_path.is_empty()) { - Ref<SceneState> state = current_packed_scene->get_state(); - state->set_path(current_packed_scene->get_path()); - instantiated_node->set_scene_inherited_state(state); - instantiated_node->set_scene_file_path(String()); - } + // Set the instance as un inherited scene of itself. + instantiated_node->set_scene_inherited_state(instantiated_node->get_scene_instance_state()); + instantiated_node->set_scene_instance_state(nullptr); + instantiated_node->set_scene_file_path(original_node_file_path); current_edited_scene = instantiated_node; - editor_data.set_edited_scene_root(current_edited_scene); } @@ -6052,18 +6175,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins node_3d->set_transform(additive_node_entry.transform_3d); } } - - // Restore the ownership of its ancestors - for (KeyValue<Node *, Node *> &E : additive_node_entry.ownership_table) { - Node *current_ancestor = E.key; - Node *ancestor_owner = E.value; - - if (ancestor_owner == original_node) { - ancestor_owner = instantiated_node; - } - - current_ancestor->set_owner(ancestor_owner); - } } // Restore the selection. @@ -6125,6 +6236,24 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins editor_data.restore_edited_scene_state(editor_selection, &editor_history); } + + scenes_modification_table.clear(); +} + +void EditorNode::_remove_all_not_owned_children(Node *p_node, Node *p_owner) { + Vector<Node *> nodes_to_remove; + if (p_node != p_owner && p_node->get_owner() != p_owner) { + nodes_to_remove.push_back(p_node); + } + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child_node = p_node->get_child(i); + _remove_all_not_owned_children(child_node, p_owner); + } + + for (Node *node : nodes_to_remove) { + node->get_parent()->remove_child(node); + node->queue_free(); + } } int EditorNode::plugin_init_callback_count = 0; @@ -7572,6 +7701,7 @@ EditorNode::EditorNode() { EditorFileSystem::get_singleton()->connect("sources_changed", callable_mp(this, &EditorNode::_sources_changed)); EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &EditorNode::_fs_changed)); + EditorFileSystem::get_singleton()->connect("resources_reimporting", callable_mp(this, &EditorNode::_resources_reimporting)); EditorFileSystem::get_singleton()->connect("resources_reimported", callable_mp(this, &EditorNode::_resources_reimported)); EditorFileSystem::get_singleton()->connect("resources_reload", callable_mp(this, &EditorNode::_resources_changed)); diff --git a/editor/editor_node.h b/editor/editor_node.h index a2ee61697f..4d55eaf1b2 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -556,6 +556,7 @@ private: void _plugin_over_self_own(EditorPlugin *p_plugin); void _fs_changed(); + void _resources_reimporting(const Vector<String> &p_resources); void _resources_reimported(const Vector<String> &p_resources); void _sources_changed(bool p_exist); @@ -675,6 +676,8 @@ private: void _notify_nodes_scene_reimported(Node *p_node, Array p_reimported_nodes); + void _remove_all_not_owned_children(Node *p_node, Node *p_owner); + protected: friend class FileSystemDock; @@ -803,8 +806,6 @@ public: // Used if the original parent node is lost Transform2D transform_2d; Transform3D transform_3d; - // Used to keep track of the ownership of all ancestor nodes so they can be restored later. - HashMap<Node *, Node *> ownership_table; }; struct ConnectionWithNodePath { @@ -819,7 +820,8 @@ public: List<Node::GroupInfo> groups; }; - void update_ownership_table_for_addition_node_ancestors(Node *p_current_node, HashMap<Node *, Node *> &p_ownership_table); + HashMap<int, HashMap<NodePath, HashMap<NodePath, ModificationNodeEntry>>> scenes_modification_table; + void update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification); void update_node_reference_modification_table_for_node( @@ -828,12 +830,18 @@ public: List<Node *> p_excluded_nodes, HashMap<NodePath, ModificationNodeEntry> &p_modification_table); - void update_reimported_diff_data_for_node( + void get_preload_scene_modification_table( + Node *p_edited_scene, + Node *p_reimported_root, + Node *p_node, HashMap<NodePath, ModificationNodeEntry> &p_modification_table); + + void update_reimported_diff_data_for_additional_nodes( Node *p_edited_scene, Node *p_reimported_root, Node *p_node, HashMap<NodePath, ModificationNodeEntry> &p_modification_table, List<AdditiveNodeEntry> &p_addition_list); + bool is_additional_node_in_scene(Node *p_edited_scene, Node *p_reimported_root, Node *p_node); bool is_scene_open(const String &p_path); bool is_multi_window_enabled() const; @@ -888,7 +896,9 @@ public: void reload_scene(const String &p_path); + void get_edited_scene_map(const String &p_instance_path, HashMap<int, List<Node *>> &p_edited_scene_map); void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list); + void preload_reimporting_with_path_in_edited_scenes(const String &p_path); void reload_instances_with_path_in_edited_scenes(const String &p_path); bool is_exiting() const { return exiting; } diff --git a/editor/project_manager/project_dialog.cpp b/editor/project_manager/project_dialog.cpp index be5fa8745c..52d86a1a95 100644 --- a/editor/project_manager/project_dialog.cpp +++ b/editor/project_manager/project_dialog.cpp @@ -389,6 +389,8 @@ void ProjectDialog::_browse_install_path() { } void ProjectDialog::_project_path_selected(const String &p_path) { + show_dialog(); + if (create_dir->is_pressed() && (mode == MODE_NEW || mode == MODE_INSTALL)) { // Replace parent directory, but keep target dir name. project_path->set_text(p_path.path_join(project_path->get_text().get_file())); @@ -686,8 +688,6 @@ void ProjectDialog::set_project_path(const String &p_path) { } void ProjectDialog::ask_for_path_and_show() { - // Workaround: for the file selection dialog content to be rendered we need to show its parent dialog. - show_dialog(); _browse_project_path(); } @@ -787,6 +787,14 @@ void ProjectDialog::_notification(int p_what) { project_browse->set_icon(get_editor_theme_icon(SNAME("FolderBrowse"))); install_browse->set_icon(get_editor_theme_icon(SNAME("FolderBrowse"))); } break; + case NOTIFICATION_READY: { + fdialog_project = memnew(EditorFileDialog); + fdialog_project->set_previews_enabled(false); // Crucial, otherwise the engine crashes. + fdialog_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + fdialog_project->connect("dir_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); + fdialog_project->connect("file_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); + callable_mp((Node *)this, &Node::add_sibling).call_deferred(fdialog_project, false); + } break; } } @@ -967,21 +975,14 @@ ProjectDialog::ProjectDialog() { Control *spacer = memnew(Control); spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); default_files_container->add_child(spacer); - - fdialog_project = memnew(EditorFileDialog); - fdialog_project->set_previews_enabled(false); //Crucial, otherwise the engine crashes. - fdialog_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM); fdialog_install = memnew(EditorFileDialog); fdialog_install->set_previews_enabled(false); //Crucial, otherwise the engine crashes. fdialog_install->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - add_child(fdialog_project); add_child(fdialog_install); project_name->connect(SceneStringName(text_changed), callable_mp(this, &ProjectDialog::_project_name_changed).unbind(1)); project_path->connect(SceneStringName(text_changed), callable_mp(this, &ProjectDialog::_project_path_changed).unbind(1)); install_path->connect(SceneStringName(text_changed), callable_mp(this, &ProjectDialog::_install_path_changed).unbind(1)); - fdialog_project->connect("dir_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); - fdialog_project->connect("file_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); fdialog_install->connect("dir_selected", callable_mp(this, &ProjectDialog::_install_path_selected)); fdialog_install->connect("file_selected", callable_mp(this, &ProjectDialog::_install_path_selected)); diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 50695cb0b1..ce8f24c7a9 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -372,3 +372,11 @@ GH-93982 Validate extension JSON: Error: Field 'classes/Sprite3D/properties/frame_coords': type changed value in new API, from "Vector2" to "Vector2i". The type was wrong to begin with and has been corrected. Vector2 and Vector2i are convertible, so it should be compatible. + + +GH-94243 +-------- +Validate extension JSON: Error: Field 'classes/Image/methods/get_mipmap_offset/return_value': meta changed value in new API, from "int32" to "int64". + +Type changed to int64_t to support baking large lightmaps. +No compatibility method needed, both GDExtension and C# generate it as int64_t anyway. diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp index 216fa6c9a2..fc1f01ae50 100644 --- a/modules/basis_universal/image_compress_basisu.cpp +++ b/modules/basis_universal/image_compress_basisu.cpp @@ -120,7 +120,8 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha Vector<uint32_t> mip_data_padded; for (int32_t i = 0; i <= image->get_mipmap_count(); i++) { - int ofs, size, width, height; + int64_t ofs, size; + int width, height; image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height); const uint8_t *image_mip_data = image_data.ptr() + ofs; diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp index fba76621d6..72640cd936 100644 --- a/modules/squish/image_decompress_squish.cpp +++ b/modules/squish/image_decompress_squish.cpp @@ -77,10 +77,11 @@ void image_decompress_squish(Image *p_image) { } for (int i = 0; i <= mm_count; i++) { - int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; + int64_t src_ofs = 0, mipmap_size = 0; + int mipmap_w = 0, mipmap_h = 0; p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); - int dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); + int64_t dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags); w >>= 1; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 5713ca8a2d..3b440e3f83 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -639,7 +639,8 @@ def configure_mingw(env: "SConsEnvironment"): # TODO: Re-evaluate the need for this / streamline with common config. if env["target"] == "template_release": - env.Append(CCFLAGS=["-msse2"]) + if env["arch"] != "arm64": + env.Append(CCFLAGS=["-msse2"]) elif env.dev_build: # Allow big objects. It's supposed not to have drawbacks but seems to break # GCC LTO, so enabling for debug builds only (which are not built with LTO diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h index 09b2e8cf29..0698c60f2a 100644 --- a/tests/core/io/test_image.h +++ b/tests/core/io/test_image.h @@ -355,8 +355,8 @@ TEST_CASE("[Image] Custom mipmaps") { uint8_t *data_ptr = data.ptrw(); for (int mip = 0; mip < mipmaps; mip++) { - int mip_offset = 0; - int mip_size = 0; + int64_t mip_offset = 0; + int64_t mip_size = 0; image->get_mipmap_offset_and_size(mip, mip_offset, mip_size); for (int i = 0; i < mip_size; i++) { @@ -378,8 +378,8 @@ TEST_CASE("[Image] Custom mipmaps") { const uint8_t *data_ptr = data.ptr(); for (int mip = 0; mip < mipmaps; mip++) { - int mip_offset = 0; - int mip_size = 0; + int64_t mip_offset = 0; + int64_t mip_size = 0; image_bytes->get_mipmap_offset_and_size(mip, mip_offset, mip_size); for (int i = 0; i < mip_size; i++) { @@ -402,8 +402,8 @@ TEST_CASE("[Image] Custom mipmaps") { const uint8_t *data_ptr = data.ptr(); for (int mip = 0; mip < mipmaps; mip++) { - int mip_offset = 0; - int mip_size = 0; + int64_t mip_offset = 0; + int64_t mip_size = 0; image_rgbaf->get_mipmap_offset_and_size(mip, mip_offset, mip_size); for (int i = 0; i < mip_size; i += 4) { |
