diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 1fc2da08bc6..e7bcfa8226d 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1210,7 +1210,7 @@ class CYCLES_CAMERA_PT_lens_custom_parameters(CyclesButtonsPanel, Panel): col = layout.column() for key in ccam.keys(): - col.prop(ccam, f'["{key}"]') + col.prop(ccam, f'["{key}"]', text=bpy.path.display_name(key)) class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/kernel/util/ies.h b/intern/cycles/kernel/util/ies.h index ee09e526162..8642082c0a3 100644 --- a/intern/cycles/kernel/util/ies.h +++ b/intern/cycles/kernel/util/ies.h @@ -27,22 +27,29 @@ ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg, * we can just take the corresponding value at the current horizontal coordinate. */ #define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v)) - float a = 0.0f; + + /* Look up the inner two points directly. */ + const float c = IES_LOOKUP(v + 1); + const float b = IES_LOOKUP(v); + + /* Look up first point, or fall back to second point if not available. */ + float a = b; if (v > 0) { a = IES_LOOKUP(v - 1); } else if (wrap_vlow) { a = IES_LOOKUP(1); } - const float b = IES_LOOKUP(v); - const float c = IES_LOOKUP(v + 1); - float d = 0.0f; + + /* Look up last point, or fall back to third point if not available. */ + float d = c; if (v + 2 < v_num) { d = IES_LOOKUP(v + 2); } else if (wrap_vhigh) { d = IES_LOOKUP(v_num - 2); } + #undef IES_LOOKUP return cubic_interp(a, b, c, d, v_frac); @@ -105,7 +112,14 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, /* Skip forward to the actual intensity data. */ ofs += h_num + v_num; - float a = 0.0f; + /* Interpolate the inner two points directly. */ + const float b = interpolate_ies_vertical( + kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i); + const float c = interpolate_ies_vertical( + kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1); + + /* Interpolate first point, or fall back to second point if not available. */ + float a = b; if (h_i > 0) { a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i - 1); } @@ -113,11 +127,9 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, /* The last entry (360°) equals the first one, so we need to wrap around to the one before. */ a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_num - 2); } - const float b = interpolate_ies_vertical( - kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i); - const float c = interpolate_ies_vertical( - kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1); - float d = 0.0f; + + /* Interpolate last point, or fall back to second point if not available. */ + float d = b; if (h_i + 2 < h_num) { d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 2); } diff --git a/scripts/templates_osl/advanced_camera.osl b/scripts/templates_osl/advanced_camera.osl index 1997886177b..124f4d1f82b 100644 --- a/scripts/templates_osl/advanced_camera.osl +++ b/scripts/templates_osl/advanced_camera.osl @@ -37,7 +37,7 @@ shader camera(float focal_length = 50.0 [[ float min = 0.0, float distortion_k3 = 0.0, float swirl_scale = 100.0, float swirl_amplitude = 0.01, - float swirl_W = 0.0 [[ float sensitivity = 1]], + float swirl_w = 0.0 [[ float sensitivity = 1]], output point position = 0.0, output vector direction = 0.0, output color throughput = 1.0) @@ -61,7 +61,7 @@ shader camera(float focal_length = 50.0 [[ float min = 0.0, Pcam = Pcam * sensor_size / focal_length; if (do_swirl) { - Pcam += swirl_amplitude * noise("perlin", Pcam * swirl_scale, swirl_W); + Pcam += swirl_amplitude * noise("perlin", Pcam * swirl_scale, swirl_w); } direction = normalize(vector(Pcam.x, Pcam.y, 1.0)); diff --git a/source/blender/asset_system/AS_asset_catalog.hh b/source/blender/asset_system/AS_asset_catalog.hh index a82b86351d0..364bebfc3f6 100644 --- a/source/blender/asset_system/AS_asset_catalog.hh +++ b/source/blender/asset_system/AS_asset_catalog.hh @@ -71,7 +71,7 @@ class AssetCatalogService { * * This "dirty" state is tracked per catalog, so that it's possible to gracefully load changes * from disk. Any catalog with unsaved changes will not be overwritten by on-disk changes. */ - void tag_has_unsaved_changes(AssetCatalog *edited_catalog); + void tag_has_unsaved_changes(AssetCatalog *edited_catalog = nullptr); bool has_unsaved_changes() const; /** @@ -159,8 +159,15 @@ class AssetCatalogService { */ AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const; - /** Create a catalog with some sensible auto-generated catalog ID. - * The catalog will be saved to the default catalog file. */ + /** + * Create a catalog with some sensible auto-generated catalog ID. + * The catalog will be saved to the default catalog file. + * + * NOTE: this does NOT mark the catalog service itself as 'has changes'. The caller is + * responsible for that. + * + * \see #tag_has_unsaved_changes() + */ AssetCatalog *create_catalog(const AssetCatalogPath &catalog_path); /** @@ -228,6 +235,11 @@ class AssetCatalogService { * will be removed from a CDF when saved to disk. * * This is a lower-level function than #prune_catalogs_by_path. + * + * NOTE: this does NOT mark the catalog service itself as 'has changes'. The caller is + * responsible for that. + * + * \see #tag_has_unsaved_changes() */ void delete_catalog_by_id_soft(CatalogID catalog_id); diff --git a/source/blender/asset_system/intern/asset_catalog.cc b/source/blender/asset_system/intern/asset_catalog.cc index 21efd40f20a..02ce2d581db 100644 --- a/source/blender/asset_system/intern/asset_catalog.cc +++ b/source/blender/asset_system/intern/asset_catalog.cc @@ -482,9 +482,19 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat { /* TODO(Sybren): expand to support multiple CDFs. */ - /* - Already loaded a CDF from disk? -> Always write to that file. */ + /* - Already loaded a CDF from disk? -> Only write to that file when there were actual changes. + * This prevents touching the file, which can cause issues when multiple Blender instances are + * accessing the same file (like on shared storage, Syncthing, etc.). See #111576. + */ if (catalog_collection_->catalog_definition_file_) { + /* Always sync with what's on disk. */ this->reload_catalogs(); + + if (!this->has_unsaved_changes() && + catalog_collection_->catalog_definition_file_->exists_on_disk()) + { + return true; + } return catalog_collection_->catalog_definition_file_->write_to_disk(); } diff --git a/source/blender/asset_system/intern/asset_catalog_definition_file.cc b/source/blender/asset_system/intern/asset_catalog_definition_file.cc index 4364b85a75a..5cf9aff7790 100644 --- a/source/blender/asset_system/intern/asset_catalog_definition_file.cc +++ b/source/blender/asset_system/intern/asset_catalog_definition_file.cc @@ -185,6 +185,11 @@ bool AssetCatalogDefinitionFile::write_to_disk(const CatalogFilePath &dest_file_ return true; } +bool AssetCatalogDefinitionFile::exists_on_disk() const +{ + return BLI_exists(this->file_path.c_str()); +} + bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &dest_file_path) const { char directory[PATH_MAX]; diff --git a/source/blender/asset_system/intern/asset_catalog_definition_file.hh b/source/blender/asset_system/intern/asset_catalog_definition_file.hh index c7d99c9677a..870a20b64ba 100644 --- a/source/blender/asset_system/intern/asset_catalog_definition_file.hh +++ b/source/blender/asset_system/intern/asset_catalog_definition_file.hh @@ -55,6 +55,11 @@ class AssetCatalogDefinitionFile { */ bool write_to_disk(const CatalogFilePath &dest_file_path) const; + /** + * Returns whether this file exists on disk. + */ + bool exists_on_disk() const; + bool contains(CatalogID catalog_id) const; /** Add a catalog, overwriting the one with the same catalog ID. */ void add_overwrite(AssetCatalog *catalog); diff --git a/source/blender/asset_system/tests/asset_catalog_test.cc b/source/blender/asset_system/tests/asset_catalog_test.cc index 0334a203318..cbb4fb8c328 100644 --- a/source/blender/asset_system/tests/asset_catalog_test.cc +++ b/source/blender/asset_system/tests/asset_catalog_test.cc @@ -341,6 +341,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf) TestableAssetCatalogService service(cdf_filename); service.load_from_disk(); const AssetCatalog *cat = service.create_catalog("some/catalog/path"); + service.tag_has_unsaved_changes(); const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend"; ASSERT_TRUE(service.write_to_disk(blendfilename)); @@ -458,6 +459,10 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch) /* Creating a new catalog should not save anything to disk yet. */ EXPECT_FALSE(BLI_exists(temp_lib_root.c_str())); + /* Creating a new catalog should not mark the asset service as 'dirty'; that's + * the caller's responsibility. */ + EXPECT_FALSE(service.has_unsaved_changes()); + /* Writing to disk should create the directory + the default file. */ service.write_to_disk(temp_lib_root + "phony.blend"); EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str())); @@ -498,6 +503,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file) /* This should create a new catalog but not write to disk. */ const AssetCatalog *new_catalog = service.create_catalog("new/catalog"); const bUUID new_catalog_id = new_catalog->catalog_id; + service.tag_has_unsaved_changes(); /* Reload the on-disk catalog file. */ TestableAssetCatalogService loaded_service(temp_lib_root); @@ -887,6 +893,7 @@ TEST_F(AssetCatalogTest, backups) TestableAssetCatalogService service(cdf_dir); service.load_from_disk(); service.delete_catalog_by_id_soft(UUID_POSES_ELLIE); + service.tag_has_unsaved_changes(); service.write_to_disk(cdf_dir + "phony.blend"); const CatalogFilePath backup_path = writable_cdf_file + "~"; diff --git a/source/blender/blenlib/intern/BLI_mmap.cc b/source/blender/blenlib/intern/BLI_mmap.cc index d69c4637468..9fc4c747a36 100644 --- a/source/blender/blenlib/intern/BLI_mmap.cc +++ b/source/blender/blenlib/intern/BLI_mmap.cc @@ -275,7 +275,9 @@ static void print_error(const char *message) { char buffer[256]; size_t length = BLI_string_join(buffer, sizeof(buffer), "BLI_mmap: ", message, "\n"); - write(STDERR_FILENO, buffer, length); + if (write(STDERR_FILENO, buffer, length) < 0) { + /* If writing to stderr fails, there is nowhere to write an error about that. */ + } } static bool try_map_zeros(BLI_mmap_file *file)