From 3437cf155e7ca73cb96882ed5372f5baf2eac78a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 30 May 2022 17:24:16 +0200 Subject: LibOverride: Add full support for camera's background images. Add support for adding (inserting) new background images into an override of a linked Camera ID. Request from the Blender studio. This ended up being more involved than expected as it uncovered some latent issues with existing background images code. Noticiably, a new `BKE_camera_background_image_copy` had to be added to handle copying of background images in a proper, generic ID-management way. --- source/blender/blenkernel/BKE_camera.h | 8 ++++ source/blender/blenkernel/intern/camera.c | 40 +++++++++++++--- source/blender/editors/space_view3d/view3d_edit.c | 11 +++++ source/blender/makesdna/DNA_camera_types.h | 3 ++ .../makesrna/intern/rna_access_compare_override.c | 7 +++ source/blender/makesrna/intern/rna_camera.c | 55 ++++++++++++++++++++++ 6 files changed, 118 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index e55b8b1a2da..b7aa1c09e04 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -164,6 +164,14 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd, /* Camera background image API */ struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam); +/** + * Duplicate a background image, in a ID management compatible way. + * + * \param copy_flag The usual ID copying flags, see `LIB_ID_CREATE_`/`LIB_ID_COPY_` enums in + * `BKE_lib_id.h`. + */ +struct CameraBGImage *BKE_camera_background_image_copy(struct CameraBGImage *bgpic_src, + const int copy_flag); void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic); void BKE_camera_background_image_clear(struct Camera *cam); diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index b59e44aae8a..6325251647b 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -66,14 +66,19 @@ static void camera_init_data(ID *id) * * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). */ -static void camera_copy_data(Main *UNUSED(bmain), - ID *id_dst, - const ID *id_src, - const int UNUSED(flag)) +static void camera_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { Camera *cam_dst = (Camera *)id_dst; const Camera *cam_src = (const Camera *)id_src; - BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images); + + /* We never handle usercount here for own data. */ + const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + + BLI_listbase_clear(&cam_dst->bg_images); + LISTBASE_FOREACH (CameraBGImage *, bgpic_src, &cam_src->bg_images) { + CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, flag_subdata); + BLI_addtail(&cam_dst->bg_images, bgpic_dst); + } } /** Free (or release) any data used by this camera (does not free the camera itself). */ @@ -125,6 +130,11 @@ static void camera_blend_read_data(BlendDataReader *reader, ID *id) LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) { bgpic->iuser.scene = NULL; + + /* If linking from a library, clear 'local' library override flag. */ + if (ID_IS_LINKED(ca)) { + bgpic->flag &= ~CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL; + } } } @@ -1119,13 +1129,31 @@ CameraBGImage *BKE_camera_background_image_new(Camera *cam) bgpic->scale = 1.0f; bgpic->alpha = 0.5f; bgpic->iuser.flag |= IMA_ANIM_ALWAYS; - bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED; + bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED | CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL; BLI_addtail(&cam->bg_images, bgpic); return bgpic; } +CameraBGImage *BKE_camera_background_image_copy(CameraBGImage *bgpic_src, const int flag) +{ + CameraBGImage *bgpic_dst = MEM_dupallocN(bgpic_src); + + bgpic_dst->next = bgpic_dst->prev = NULL; + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)bgpic_dst->ima); + id_us_plus((ID *)bgpic_dst->clip); + } + + if ((flag & LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG) == 0) { + bgpic_dst->flag |= CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL; + } + + return bgpic_dst; +} + void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic) { BLI_remlink(&cam->bg_images, bgpic); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index fb5e7e58d33..a65e9a8d506 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -631,6 +631,17 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index); if (bgpic_rem) { + if (ID_IS_OVERRIDE_LIBRARY(cam) && + (bgpic_rem->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) == 0) { + BKE_reportf(op->reports, + RPT_WARNING, + "Cannot remove background image %d from camera '%s', as it is from the linked " + "reference data", + index, + cam->id.name + 2); + return OPERATOR_CANCELLED; + } + id_us_min((ID *)bgpic_rem->ima); id_us_min((ID *)bgpic_rem->clip); diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 9b3adc4c8dd..e0aec298cd0 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -194,6 +194,9 @@ enum { /* Axis flip options */ CAM_BGIMG_FLAG_FLIP_X = (1 << 7), CAM_BGIMG_FLAG_FLIP_Y = (1 << 8), + + /* That background image has been inserted in local override (i.e. it can be fully edited!). */ + CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL = (1 << 9), }; /* CameraBGImage->source */ diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index aea4467c162..17c00923efa 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -12,6 +12,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" +#include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_key_types.h" @@ -145,6 +146,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) return true; } } + else if (RNA_struct_is_a(ptr->type, &RNA_CameraBackgroundImage)) { + CameraBGImage *bgpic = ptr->data; + if (bgpic->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) { + return true; + } + } /* If this is a RNA-defined property (real or 'virtual' IDProp), * we want to use RNA prop flag. */ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 52ec2bee128..dcf0647392e 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -125,6 +125,49 @@ static char *rna_Camera_background_image_path(const PointerRNA *ptr) return NULL; } +static bool rna_Camera_background_images_override_apply(Main *bmain, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *UNUSED(ptr_storage), + PropertyRNA *prop_dst, + PropertyRNA *UNUSED(prop_src), + PropertyRNA *UNUSED(prop_storage), + const int UNUSED(len_dst), + const int UNUSED(len_src), + const int UNUSED(len_storage), + PointerRNA *UNUSED(ptr_item_dst), + PointerRNA *UNUSED(ptr_item_src), + PointerRNA *UNUSED(ptr_item_storage), + IDOverrideLibraryPropertyOperation *opop) +{ + BLI_assert_msg(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, + "Unsupported RNA override operation on background images collection"); + + Camera *cam_dst = (Camera *)ptr_dst->owner_id; + Camera *cam_src = (Camera *)ptr_src->owner_id; + + /* Remember that insertion operations are defined and stored in correct order, which means that + * even if we insert several items in a row, we always insert first one, then second one, etc. + * So we should always find 'anchor' constraint in both _src *and* _dst. */ + CameraBGImage *bgpic_anchor = BLI_findlink(&cam_dst->bg_images, opop->subitem_reference_index); + + /* If `bgpic_anchor` is NULL, `bgpic_src` will be inserted in first position. */ + CameraBGImage *bgpic_src = BLI_findlink(&cam_src->bg_images, opop->subitem_local_index); + + if (bgpic_src == NULL) { + BLI_assert(bgpic_src != NULL); + return false; + } + + CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, 0); + + /* This handles NULL anchor as expected by adding at head of list. */ + BLI_insertlinkafter(&cam_dst->bg_images, bgpic_anchor, bgpic_dst); + + RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst); + return true; +} + static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { SEQ_relations_invalidate_scene_strips(bmain, scene); @@ -195,6 +238,16 @@ static void rna_def_camera_background_image(BlenderRNA *brna) srna, "Background Image", "Image and settings for display in the 3D View background"); RNA_def_struct_path_func(srna, "rna_Camera_background_image_path"); + prop = RNA_def_boolean(srna, + "is_override_data", + false, + "Override Background Image", + "In a local override camera, whether this background image comes from " + "the linked reference camera, or is local to the override"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_negative_sdna( + prop, NULL, "flag", CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL); + RNA_define_lib_overridable(true); prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE); @@ -751,6 +804,8 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "bg_images", NULL); RNA_def_property_struct_type(prop, "CameraBackgroundImage"); RNA_def_property_ui_text(prop, "Background Images", "List of background images"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION | PROPOVERRIDE_NO_PROP_NAME); + RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Camera_background_images_override_apply"); RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL); RNA_define_lib_overridable(false); -- cgit v1.2.3