ID Static Override, part II: RNA changes.
This is essentially a huge refactor/extension of our existing RNA compare & copy code, since static override needs more advanced handling here. Note that not all new features are implemented yet, advanced things like collections insertion/deletion are still TODO (medium priority). This completes the ground work for overrides, remaining commits will be about UI and some basic/testing activation of overrides for a limited set of data-blocks & properties. For details see https://developer.blender.org/D2417
This commit is contained in:
parent
6d003ef812
commit
638afb9bd4
Notes:
blender-bot
2023-02-14 06:12:27 +01:00
Referenced by issue #54005, Copy to selected not working for Python defined properties
|
@ -384,10 +384,10 @@ bool BKE_override_static_status_check_local(ID *local)
|
|||
RNA_id_pointer_create(local, &rnaptr_local);
|
||||
RNA_id_pointer_create(reference, &rnaptr_reference);
|
||||
|
||||
// if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
|
||||
// local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
|
||||
// return false;
|
||||
// }
|
||||
if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
|
||||
local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -428,10 +428,10 @@ bool BKE_override_static_status_check_reference(ID *local)
|
|||
RNA_id_pointer_create(local, &rnaptr_local);
|
||||
RNA_id_pointer_create(reference, &rnaptr_reference);
|
||||
|
||||
// if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
|
||||
// local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
|
||||
// return false;
|
||||
// }
|
||||
if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
|
||||
local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ bool BKE_override_static_operations_create(ID *local)
|
|||
RNA_id_pointer_create(local, &rnaptr_local);
|
||||
RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
|
||||
|
||||
// ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
|
||||
ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
|
||||
#ifndef NDEBUG
|
||||
if (ret) {
|
||||
printf("We did generate static override rules for %s\n", local->name);
|
||||
|
@ -534,7 +534,7 @@ void BKE_override_static_update(Main *bmain, ID *local)
|
|||
RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
|
||||
}
|
||||
|
||||
// RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
|
||||
RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
|
||||
|
||||
/* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
|
||||
* we'll actually free old, outdated data from local. */
|
||||
|
@ -634,10 +634,10 @@ ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_s
|
|||
RNA_id_pointer_create(local, &rnaptr_final);
|
||||
RNA_id_pointer_create(storage_id, &rnaptr_storage);
|
||||
|
||||
// if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
|
||||
// BKE_libblock_free_ex(override_storage, storage_id, true, false);
|
||||
// storage_id = NULL;
|
||||
// }
|
||||
if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
|
||||
BKE_libblock_free_ex(override_storage, storage_id, true, false);
|
||||
storage_id = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
local->override_static->storage = storage_id;
|
||||
|
|
|
@ -39,6 +39,9 @@ extern "C" {
|
|||
|
||||
struct bContext;
|
||||
struct ID;
|
||||
struct IDOverrideStatic;
|
||||
struct IDOverrideStaticProperty;
|
||||
struct IDOverrideStaticPropertyOperation;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct ReportList;
|
||||
|
@ -1042,7 +1045,7 @@ char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int
|
|||
* call RNA_struct_find_property. The names have to exist as RNA properties
|
||||
* for the type in the pointer, if they do not exist an error will be printed.
|
||||
*
|
||||
* There is no support for pointers and collections here yet, these can be
|
||||
* There is no support for pointers and collections here yet, these can be
|
||||
* added when ID properties support them. */
|
||||
|
||||
int RNA_boolean_get(PointerRNA *ptr, const char *name);
|
||||
|
@ -1234,17 +1237,51 @@ StructRNA *ID_code_to_RNA_type(short idcode);
|
|||
|
||||
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
|
||||
|
||||
/* Equals test (skips pointers and collections)
|
||||
* is_strict false assumes uninitialized properties are equal */
|
||||
/* Equals test. */
|
||||
|
||||
typedef enum eRNAEqualsMode {
|
||||
RNA_EQ_STRICT, /* set/unset ignored */
|
||||
RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
|
||||
RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */
|
||||
} eRNAEqualsMode;
|
||||
/* Note: In practice, EQ_STRICT and EQ_COMPARE have same behavior currently, and will yield same result. */
|
||||
typedef enum eRNACompareMode {
|
||||
/* Only care about equality, not full comparison. */
|
||||
RNA_EQ_STRICT, /* set/unset ignored */
|
||||
RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
|
||||
RNA_EQ_UNSET_MATCH_NONE, /* unset property never matches set property */
|
||||
/* Full comparison. */
|
||||
RNA_EQ_COMPARE,
|
||||
} eRNACompareMode;
|
||||
|
||||
bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode);
|
||||
bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode);
|
||||
bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode);
|
||||
bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode);
|
||||
|
||||
/* Override. */
|
||||
|
||||
bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference,
|
||||
struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden);
|
||||
|
||||
bool RNA_struct_override_store(
|
||||
struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override);
|
||||
|
||||
void RNA_property_override_apply(
|
||||
struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop,
|
||||
struct IDOverrideStaticProperty *op);
|
||||
void RNA_struct_override_apply(
|
||||
struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage,
|
||||
struct IDOverrideStatic *override);
|
||||
|
||||
bool RNA_struct_auto_override(
|
||||
struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path);
|
||||
|
||||
struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop);
|
||||
struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created);
|
||||
|
||||
struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict);
|
||||
struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
|
||||
const bool strict, bool *r_strict, bool *r_created);
|
||||
|
||||
void RNA_property_override_status(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const int index,
|
||||
bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -177,6 +177,8 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
|
|||
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
|
||||
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
|
||||
|
||||
void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply);
|
||||
|
||||
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
|
||||
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ typedef enum PropertySubType {
|
|||
|
||||
/* Make sure enums are updated with these */
|
||||
/* HIGHEST FLAG IN USE: 1 << 31
|
||||
* FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */
|
||||
* FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */
|
||||
typedef enum PropertyFlag {
|
||||
/* editable means the property is editable in the user
|
||||
* interface, properties are editable by default except
|
||||
|
@ -176,6 +176,9 @@ typedef enum PropertyFlag {
|
|||
* and collections */
|
||||
PROP_ANIMATABLE = (1 << 1),
|
||||
|
||||
/* Means the property can be overriden by a local 'proxy' of some linked datablock. */
|
||||
PROP_OVERRIDABLE = (1 << 2),
|
||||
|
||||
/* This flag means when the property's widget is in 'textedit' mode, it will be updated
|
||||
* after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
|
||||
* It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
|
||||
|
|
|
@ -3025,12 +3025,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
|
|||
prop->arraylength[1],
|
||||
prop->arraylength[2],
|
||||
prop->totarraylength);
|
||||
fprintf(f, "\t%s%s, %d, %s, %s,\n",
|
||||
fprintf(f, "\t%s%s, %d, %s, %s, %s, %s, %s,\n",
|
||||
(prop->flag & PROP_CONTEXT_UPDATE) ? "(UpdateFunc)" : "",
|
||||
rna_function_string(prop->update),
|
||||
prop->noteflag,
|
||||
rna_function_string(prop->editable),
|
||||
rna_function_string(prop->itemeditable));
|
||||
rna_function_string(prop->itemeditable),
|
||||
rna_function_string(prop->override_diff),
|
||||
rna_function_string(prop->override_store),
|
||||
rna_function_string(prop->override_apply));
|
||||
|
||||
if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
|
||||
else fprintf(f, "\t0, -1");
|
||||
|
|
|
@ -97,6 +97,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
|
|||
#include "BKE_idprop.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_library_query.h"
|
||||
#include "BKE_library_override.h"
|
||||
#include "BKE_library_remap.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_material.h"
|
||||
|
@ -311,6 +312,15 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static ID *rna_ID_override_create(ID *id, Main *bmain)
|
||||
{
|
||||
if (id->lib == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return BKE_override_static_create_from(bmain, id);
|
||||
}
|
||||
|
||||
static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
|
||||
{
|
||||
/* XXX, new function for this! */
|
||||
|
@ -762,6 +772,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
|
|||
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
|
||||
}
|
||||
|
||||
static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr)
|
||||
{
|
||||
ID *id = (ID *)ptr->data;
|
||||
ID *reference = (id && id->override_static) ? id->override_static->reference : NULL;
|
||||
|
||||
return reference ? rna_pointer_inherit_refine(ptr, ID_code_to_RNA_type(GS(reference->name)), reference) : PointerRNA_NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_ID_properties(BlenderRNA *brna)
|
||||
|
@ -1024,6 +1042,12 @@ static void rna_def_ID(BlenderRNA *brna)
|
|||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from");
|
||||
|
||||
prop = RNA_def_pointer(srna, "override_static_reference", "ID",
|
||||
"Override Reference", "Reference linked data-block overridden by this one");
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "override_static->reference");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_funcs(prop, "rna_ID_override_reference_get", NULL, NULL, NULL);
|
||||
|
||||
prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview",
|
||||
"Preview image and icon of this data-block (None if not supported for this type of data)");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
@ -1036,6 +1060,12 @@ static void rna_def_ID(BlenderRNA *brna)
|
|||
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
|
||||
RNA_def_function_ui_description(func, "Create an overridden local copy of this linked data-block (not supported for all data-blocks)");
|
||||
RNA_def_function_flag(func, FUNC_USE_MAIN);
|
||||
parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
|
||||
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
|
||||
"on reload the data will be removed");
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "BKE_idprop.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_library_override.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
|
@ -1817,7 +1818,8 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
|
|||
|
||||
return ((flag & PROP_EDITABLE) &&
|
||||
(flag & PROP_REGISTER) == 0 &&
|
||||
(!id || !ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)));
|
||||
(!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
|
||||
(!id->override_static || (prop->flag & PROP_OVERRIDABLE)))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1843,11 +1845,19 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
|
|||
}
|
||||
|
||||
/* property from linked data-block */
|
||||
if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
|
||||
if (!(*r_info)[0]) {
|
||||
*r_info = "Can't edit this property from a linked data-block.";
|
||||
if (id) {
|
||||
if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
|
||||
if (!(*r_info)[0]) {
|
||||
*r_info = "Can't edit this property from a linked data-block.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (id->override_static != NULL && (prop->flag & PROP_OVERRIDABLE) == 0) {
|
||||
if (!(*r_info)[0]) {
|
||||
*r_info = "Can't edit this property from an override data-block.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
|
||||
|
@ -6959,120 +6969,22 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
|
|||
}
|
||||
}
|
||||
|
||||
static bool rna_property_override_operation_apply(
|
||||
PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
|
||||
IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
|
||||
{
|
||||
int len, fromlen;
|
||||
PropertyRNA *fromprop = prop;
|
||||
|
||||
if (prop->magic != RNA_MAGIC) {
|
||||
/* In case of IDProperty, we have to find the *real* idprop of ptr,
|
||||
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
|
||||
prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
|
||||
|
||||
/* its possible the custom-prop doesn't exist on this data-block */
|
||||
if (prop == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
|
||||
if (prop == fromprop) {
|
||||
fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the length of the array to work with */
|
||||
len = RNA_property_array_length(ptr, prop);
|
||||
fromlen = RNA_property_array_length(fromptr, fromprop);
|
||||
|
||||
if (len != fromlen)
|
||||
if (!RNA_property_editable(ptr, prop)) {
|
||||
return false;
|
||||
|
||||
/* get and set the default values as appropriate for the various types */
|
||||
switch (RNA_property_type(prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
if (len) {
|
||||
if (index == -1) {
|
||||
int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean");
|
||||
|
||||
RNA_property_boolean_get_array(fromptr, fromprop, tmparray);
|
||||
RNA_property_boolean_set_array(ptr, prop, tmparray);
|
||||
|
||||
MEM_freeN(tmparray);
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_boolean_get_index(fromptr, fromprop, index);
|
||||
RNA_property_boolean_set_index(ptr, prop, index, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_boolean_get(fromptr, fromprop);
|
||||
RNA_property_boolean_set(ptr, prop, value);
|
||||
}
|
||||
return true;
|
||||
case PROP_INT:
|
||||
if (len) {
|
||||
if (index == -1) {
|
||||
int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int");
|
||||
|
||||
RNA_property_int_get_array(fromptr, fromprop, tmparray);
|
||||
RNA_property_int_set_array(ptr, prop, tmparray);
|
||||
|
||||
MEM_freeN(tmparray);
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_int_get_index(fromptr, fromprop, index);
|
||||
RNA_property_int_set_index(ptr, prop, index, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_int_get(fromptr, fromprop);
|
||||
RNA_property_int_set(ptr, prop, value);
|
||||
}
|
||||
return true;
|
||||
case PROP_FLOAT:
|
||||
if (len) {
|
||||
if (index == -1) {
|
||||
float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float");
|
||||
|
||||
RNA_property_float_get_array(fromptr, fromprop, tmparray);
|
||||
RNA_property_float_set_array(ptr, prop, tmparray);
|
||||
|
||||
MEM_freeN(tmparray);
|
||||
}
|
||||
else {
|
||||
float value = RNA_property_float_get_index(fromptr, fromprop, index);
|
||||
RNA_property_float_set_index(ptr, prop, index, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
float value = RNA_property_float_get(fromptr, fromprop);
|
||||
RNA_property_float_set(ptr, prop, value);
|
||||
}
|
||||
return true;
|
||||
case PROP_ENUM:
|
||||
{
|
||||
int value = RNA_property_enum_get(fromptr, fromprop);
|
||||
RNA_property_enum_set(ptr, prop, value);
|
||||
return true;
|
||||
}
|
||||
case PROP_POINTER:
|
||||
{
|
||||
PointerRNA value = RNA_property_pointer_get(fromptr, fromprop);
|
||||
RNA_property_pointer_set(ptr, prop, value);
|
||||
return true;
|
||||
}
|
||||
case PROP_STRING:
|
||||
{
|
||||
char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL);
|
||||
RNA_property_string_set(ptr, prop, value);
|
||||
MEM_freeN(value);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
IDOverrideStaticPropertyOperation opop = {
|
||||
.operation = IDOVERRIDESTATIC_OP_REPLACE,
|
||||
.subitem_reference_index = index,
|
||||
.subitem_local_index = index
|
||||
};
|
||||
return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop);
|
||||
}
|
||||
|
||||
/* use RNA_warning macro which includes __func__ suffix */
|
||||
|
@ -7097,149 +7009,20 @@ void _RNA_warning(const char *format, ...)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode)
|
||||
static int rna_property_override_diff(
|
||||
PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode,
|
||||
IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags);
|
||||
|
||||
bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode)
|
||||
{
|
||||
int len, fromlen;
|
||||
BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
|
||||
|
||||
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
|
||||
/* uninitialized properties are assumed to match anything */
|
||||
if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop))
|
||||
return true;
|
||||
}
|
||||
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
|
||||
/* unset properties never match set properties */
|
||||
if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* get the length of the array to work with */
|
||||
len = RNA_property_array_length(a, prop);
|
||||
fromlen = RNA_property_array_length(b, prop);
|
||||
|
||||
if (len != fromlen)
|
||||
return false;
|
||||
|
||||
/* get and set the default values as appropriate for the various types */
|
||||
switch (RNA_property_type(prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
{
|
||||
if (len) {
|
||||
int fixed_a[16], fixed_b[16];
|
||||
int *array_a, *array_b;
|
||||
bool equals;
|
||||
|
||||
array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
|
||||
array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
|
||||
|
||||
RNA_property_boolean_get_array(a, prop, array_a);
|
||||
RNA_property_boolean_get_array(b, prop, array_b);
|
||||
|
||||
equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
|
||||
|
||||
if (array_a != fixed_a) MEM_freeN(array_a);
|
||||
if (array_b != fixed_b) MEM_freeN(array_b);
|
||||
|
||||
return equals;
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_boolean_get(a, prop);
|
||||
return value == RNA_property_boolean_get(b, prop);
|
||||
}
|
||||
}
|
||||
|
||||
case PROP_INT:
|
||||
{
|
||||
if (len) {
|
||||
int fixed_a[16], fixed_b[16];
|
||||
int *array_a, *array_b;
|
||||
bool equals;
|
||||
|
||||
array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
|
||||
array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
|
||||
|
||||
RNA_property_int_get_array(a, prop, array_a);
|
||||
RNA_property_int_get_array(b, prop, array_b);
|
||||
|
||||
equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
|
||||
|
||||
if (array_a != fixed_a) MEM_freeN(array_a);
|
||||
if (array_b != fixed_b) MEM_freeN(array_b);
|
||||
|
||||
return equals;
|
||||
}
|
||||
else {
|
||||
int value = RNA_property_int_get(a, prop);
|
||||
return value == RNA_property_int_get(b, prop);
|
||||
}
|
||||
}
|
||||
|
||||
case PROP_FLOAT:
|
||||
{
|
||||
if (len) {
|
||||
float fixed_a[16], fixed_b[16];
|
||||
float *array_a, *array_b;
|
||||
bool equals;
|
||||
|
||||
array_a = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_a;
|
||||
array_b = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_b;
|
||||
|
||||
RNA_property_float_get_array(a, prop, array_a);
|
||||
RNA_property_float_get_array(b, prop, array_b);
|
||||
|
||||
equals = memcmp(array_a, array_b, sizeof(float) * len) == 0;
|
||||
|
||||
if (array_a != fixed_a) MEM_freeN(array_a);
|
||||
if (array_b != fixed_b) MEM_freeN(array_b);
|
||||
|
||||
return equals;
|
||||
}
|
||||
else {
|
||||
float value = RNA_property_float_get(a, prop);
|
||||
return value == RNA_property_float_get(b, prop);
|
||||
}
|
||||
}
|
||||
|
||||
case PROP_ENUM:
|
||||
{
|
||||
int value = RNA_property_enum_get(a, prop);
|
||||
return value == RNA_property_enum_get(b, prop);
|
||||
}
|
||||
|
||||
case PROP_STRING:
|
||||
{
|
||||
char fixed_a[128], fixed_b[128];
|
||||
int len_a, len_b;
|
||||
char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a);
|
||||
char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b);
|
||||
bool equals = STREQ(value_a, value_b);
|
||||
|
||||
if (value_a != fixed_a) MEM_freeN(value_a);
|
||||
if (value_b != fixed_b) MEM_freeN(value_b);
|
||||
|
||||
return equals;
|
||||
}
|
||||
|
||||
case PROP_POINTER:
|
||||
{
|
||||
if (!STREQ(RNA_property_identifier(prop), "rna_type")) {
|
||||
PointerRNA propptr_a = RNA_property_pointer_get(a, prop);
|
||||
PointerRNA propptr_b = RNA_property_pointer_get(b, prop);
|
||||
return RNA_struct_equals(&propptr_a, &propptr_b, mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0);
|
||||
}
|
||||
|
||||
bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
|
||||
bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode)
|
||||
{
|
||||
CollectionPropertyIterator iter;
|
||||
// CollectionPropertyRNA *citerprop; /* UNUSED */
|
||||
PropertyRNA *iterprop;
|
||||
bool equals = true;
|
||||
|
||||
|
@ -7251,7 +7034,6 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
|
|||
return false;
|
||||
|
||||
iterprop = RNA_struct_iterator_property(a->type);
|
||||
// citerprop = (CollectionPropertyRNA *)rna_ensure_property(iterprop); /* UNUSED */
|
||||
|
||||
RNA_property_collection_begin(a, iterprop, &iter);
|
||||
for (; iter.valid; RNA_property_collection_next(&iter)) {
|
||||
|
@ -7267,6 +7049,474 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
|
|||
return equals;
|
||||
}
|
||||
|
||||
/* Low-level functions, also used by non-override RNA API like copy or equality check. */
|
||||
#include "PIL_time_utildefines.h"
|
||||
static int rna_property_override_diff(
|
||||
PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode,
|
||||
IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
|
||||
{
|
||||
int len_a, len_b;
|
||||
|
||||
PropertyRNA *prop_b = prop_a;
|
||||
|
||||
if (prop_a->magic != RNA_MAGIC) {
|
||||
/* In case of IDProperty, we have to find the *real* idprop of ptr,
|
||||
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
|
||||
/* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
|
||||
prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name);
|
||||
prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name);
|
||||
|
||||
if (ELEM(NULL, prop_a, prop_b)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL);
|
||||
|
||||
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
|
||||
/* uninitialized properties are assumed to match anything */
|
||||
if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b))
|
||||
return 0;
|
||||
}
|
||||
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
|
||||
/* unset properties never match set properties */
|
||||
if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get the length of the array to work with */
|
||||
len_a = RNA_property_array_length(ptr_a, prop_a);
|
||||
len_b = RNA_property_array_length(ptr_b, prop_b);
|
||||
|
||||
if (len_a != len_b) {
|
||||
/* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
|
||||
return len_a > len_b ? 1 : -1;
|
||||
}
|
||||
|
||||
return prop_a->override_diff(
|
||||
ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed);
|
||||
}
|
||||
|
||||
/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use
|
||||
* the local data-block's data as second operand). */
|
||||
static bool rna_property_override_operation_store(
|
||||
PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
|
||||
IDOverrideStaticProperty *op)
|
||||
{
|
||||
int len_local, len_reference, len_storage = 0;
|
||||
PropertyRNA *prop_reference = prop_local;
|
||||
PropertyRNA *prop_storage = prop_local;
|
||||
bool changed = false;
|
||||
|
||||
if (!ptr_storage) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
if (prop_local->magic != RNA_MAGIC) {
|
||||
/* In case of IDProperty, we have to find the *real* idprop of ptr,
|
||||
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
|
||||
/* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */
|
||||
prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
|
||||
prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
|
||||
if (ptr_storage) {
|
||||
prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
|
||||
}
|
||||
|
||||
/* its possible the custom-prop doesn't exist on this data-block */
|
||||
if (prop_local == NULL) {
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the length of the array to work with */
|
||||
len_local = RNA_property_array_length(ptr_local, prop_local);
|
||||
len_reference = RNA_property_array_length(ptr_reference, prop_reference);
|
||||
if (prop_storage) {
|
||||
len_storage = RNA_property_array_length(ptr_storage, prop_storage);
|
||||
}
|
||||
|
||||
if (len_local != len_reference || len_local != len_storage) {
|
||||
/* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
|
||||
return changed;
|
||||
}
|
||||
|
||||
BLI_assert(prop_local->override_store == prop_reference->override_store &&
|
||||
(!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
|
||||
prop_local->override_store != NULL);
|
||||
|
||||
for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
|
||||
/* Only needed for diff operations. */
|
||||
if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop_local->override_store(
|
||||
ptr_local, ptr_reference, ptr_storage, prop_local, prop_reference, prop_storage,
|
||||
len_local, len_reference, len_storage, opop))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool rna_property_override_operation_apply(
|
||||
PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
|
||||
IDOverrideStaticPropertyOperation *opop)
|
||||
{
|
||||
int len_local, len_reference, len_storage = 0;
|
||||
PropertyRNA *prop_reference = prop_local;
|
||||
PropertyRNA *prop_storage = prop_local;
|
||||
|
||||
const short override_op = opop->operation;
|
||||
|
||||
if (override_op == IDOVERRIDESTATIC_OP_NOOP) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !ptr_storage) {
|
||||
/* We cannot apply 'diff' override operations without some refference storage.
|
||||
* This should typically only happen at read time of .blend file... */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prop_local->magic != RNA_MAGIC) {
|
||||
/* In case of IDProperty, we have to find the *real* idprop of ptr,
|
||||
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
|
||||
/* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
|
||||
prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
|
||||
prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
|
||||
if (ptr_storage) {
|
||||
prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
|
||||
}
|
||||
|
||||
/* its possible the custom-prop doesn't exist on this data-block */
|
||||
if (prop_local == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
|
||||
/* We cannot apply 'diff' override operations without some refference storage.
|
||||
* This should typically only happen at read time of .blend file... */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* get the length of the array to work with */
|
||||
len_local = RNA_property_array_length(ptr_local, prop_local);
|
||||
len_reference = RNA_property_array_length(ptr_reference, prop_reference);
|
||||
if (ptr_storage) {
|
||||
len_storage = RNA_property_array_length(ptr_storage, prop_storage);
|
||||
}
|
||||
|
||||
if (len_local != len_reference || (ptr_storage && len_local != len_storage)) {
|
||||
/* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_assert(prop_local->override_apply == prop_reference->override_apply &&
|
||||
(!ptr_storage || prop_local->override_apply == prop_storage->override_apply) &&
|
||||
prop_local->override_apply != NULL);
|
||||
|
||||
/* get and set the default values as appropriate for the various types */
|
||||
return prop_local->override_apply(
|
||||
ptr_local, ptr_reference, ptr_storage,
|
||||
prop_local, prop_reference, prop_storage,
|
||||
len_local, len_reference, len_storage,
|
||||
opop);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether reference and local overriden data match (are the same),
|
||||
* with respect to given restrictive sets of properties. */
|
||||
bool RNA_struct_override_matches(
|
||||
PointerRNA *local, PointerRNA *reference,
|
||||
IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden)
|
||||
{
|
||||
CollectionPropertyIterator iter;
|
||||
PropertyRNA *iterprop;
|
||||
bool equals = true;
|
||||
|
||||
BLI_assert(local->type == reference->type);
|
||||
|
||||
iterprop = RNA_struct_iterator_property(local->type);
|
||||
|
||||
RNA_property_collection_begin(local, iterprop, &iter);
|
||||
for (; iter.valid; RNA_property_collection_next(&iter)) {
|
||||
PropertyRNA *prop = iter.ptr.data;
|
||||
|
||||
if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignore_overridden) {
|
||||
/* XXX TODO this will have to be refined to handle collections insertions, and array items */
|
||||
char *rna_path = RNA_path_from_ID_to_property(local, prop);
|
||||
if (BKE_override_static_property_find(override, rna_path) != NULL) {
|
||||
MEM_SAFE_FREE(rna_path);
|
||||
continue;
|
||||
}
|
||||
MEM_SAFE_FREE(rna_path);
|
||||
}
|
||||
|
||||
int flag = 0;
|
||||
if (ignore_non_overridable) {
|
||||
flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE;
|
||||
}
|
||||
if (ignore_overridden) {
|
||||
flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN;
|
||||
}
|
||||
if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) {
|
||||
equals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RNA_property_collection_end(&iter);
|
||||
|
||||
return equals;
|
||||
}
|
||||
|
||||
/** Store needed second operands into \a storage data-block for differential override operations. */
|
||||
bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
TIMEIT_START_AVERAGED(RNA_struct_override_store);
|
||||
#endif
|
||||
for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
|
||||
/* Simplified for now! */
|
||||
PointerRNA src_data, dst_data;
|
||||
PropertyRNA *src_prop, *dst_prop;
|
||||
|
||||
if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) &&
|
||||
RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop))
|
||||
{
|
||||
PointerRNA storage_data;
|
||||
PropertyRNA *storage_prop = NULL;
|
||||
|
||||
/* It is totally OK if this does not success, only a subset of override operations actually need storage. */
|
||||
if (storage && (storage->id.data != NULL)) {
|
||||
RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
|
||||
}
|
||||
|
||||
if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
TIMEIT_END_AVERAGED(RNA_struct_override_store);
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/** Apply given \a op override property operations on \a dst, using \a src as source. */
|
||||
void RNA_property_override_apply(
|
||||
PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op)
|
||||
{
|
||||
for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
|
||||
if (!rna_property_override_operation_apply(dst, src, storage, prop, opop))
|
||||
{
|
||||
BLI_assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply given \a override operations on \a dst, using \a src as source. */
|
||||
void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override)
|
||||
{
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
TIMEIT_START_AVERAGED(RNA_struct_override_apply);
|
||||
#endif
|
||||
for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
|
||||
/* Simplified for now! */
|
||||
PointerRNA src_data, dst_data;
|
||||
PropertyRNA *src_prop, *dst_prop;
|
||||
|
||||
if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) &&
|
||||
RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop))
|
||||
{
|
||||
PointerRNA storage_data;
|
||||
PropertyRNA *storage_prop = NULL;
|
||||
|
||||
/* It is totally OK if this does not success, only a subset of override operations actually need storage. */
|
||||
if (storage && (storage->id.data != NULL)) {
|
||||
RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
|
||||
}
|
||||
|
||||
/* Note that src and dst props are the same, unless they are IDProperties... */
|
||||
RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
else {
|
||||
printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
|
||||
((ID *)src->id.data)->name, op->rna_path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
TIMEIT_END_AVERAGED(RNA_struct_override_apply);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Automatically define override rules by comparing \a local and \a reference RNA structs. */
|
||||
bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path)
|
||||
{
|
||||
CollectionPropertyIterator iter;
|
||||
PropertyRNA *iterprop;
|
||||
bool changed = false;
|
||||
|
||||
BLI_assert(local->type == reference->type);
|
||||
BLI_assert(local->id.data && reference->id.data);
|
||||
|
||||
if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
static float _sum_time = 0.0f;
|
||||
static float _num_time = 0.0f;
|
||||
double _timeit_time;
|
||||
if (!root_path) {
|
||||
_timeit_time = PIL_check_seconds_timer();
|
||||
}
|
||||
#endif
|
||||
|
||||
iterprop = RNA_struct_iterator_property(local->type);
|
||||
|
||||
for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
|
||||
PropertyRNA *prop = iter.ptr.data;
|
||||
|
||||
if (!(prop->flag & PROP_OVERRIDABLE)) {
|
||||
continue;
|
||||
}
|
||||
if (RNA_property_animated(local, prop)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXX TODO this will have to be refined to handle collections insertions, and array items */
|
||||
char *rna_path;
|
||||
if (root_path) {
|
||||
/* Inlined building, much much more efficient. */
|
||||
rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop));
|
||||
}
|
||||
else {
|
||||
rna_path = RNA_path_from_ID_to_property(local, prop);
|
||||
}
|
||||
if (rna_path == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed,
|
||||
RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
|
||||
|
||||
MEM_SAFE_FREE(rna_path);
|
||||
}
|
||||
RNA_property_collection_end(&iter);
|
||||
|
||||
#ifdef DEBUG_OVERRIDE_TIMEIT
|
||||
if (!root_path) {
|
||||
const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time);
|
||||
_sum_time += _delta_time;
|
||||
_num_time++;
|
||||
printf("ID: %s\n", ((ID *)local->id.data)->name);
|
||||
printf("time end (%s): %.6f\n", __func__, _delta_time);
|
||||
printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
|
||||
{
|
||||
ID *id = ptr->id.data;
|
||||
|
||||
if (!id || !id->override_static) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
|
||||
if (rna_path) {
|
||||
IDOverrideStaticProperty *op = BKE_override_static_property_find(id->override_static, rna_path);
|
||||
MEM_freeN(rna_path);
|
||||
return op;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
|
||||
{
|
||||
ID *id = ptr->id.data;
|
||||
|
||||
if (!id || !id->override_static) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
|
||||
if (rna_path) {
|
||||
IDOverrideStaticProperty *op = BKE_override_static_property_get(id->override_static, rna_path, r_created);
|
||||
MEM_freeN(rna_path);
|
||||
return op;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
|
||||
{
|
||||
IDOverrideStaticProperty *op = RNA_property_override_property_find(ptr, prop);
|
||||
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return BKE_override_static_property_operation_find(op, NULL, NULL, index, index, strict, r_strict);
|
||||
}
|
||||
|
||||
IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
|
||||
const bool strict, bool *r_strict, bool *r_created)
|
||||
{
|
||||
IDOverrideStaticProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
|
||||
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
|
||||
}
|
||||
|
||||
void RNA_property_override_status(
|
||||
PointerRNA *ptr, PropertyRNA *prop, const int index,
|
||||
bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked)
|
||||
{
|
||||
#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val)
|
||||
|
||||
SET_RET(r_overridable, false);
|
||||
SET_RET(r_overridden, false);
|
||||
SET_RET(r_mandatory, false);
|
||||
SET_RET(r_locked, false);
|
||||
|
||||
if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) {
|
||||
return;
|
||||
}
|
||||
|
||||
SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE) && (prop->flag & PROP_EDITABLE));
|
||||
|
||||
if (r_overridden || r_mandatory || r_locked) {
|
||||
IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
|
||||
SET_RET(r_overridden, opop != NULL);
|
||||
SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0);
|
||||
SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RNA_path_resolved_create(
|
||||
PointerRNA *ptr, struct PropertyRNA *prop,
|
||||
|
|
|
@ -1270,6 +1270,14 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Override handling. */
|
||||
if (DefRNA.preprocess) {
|
||||
prop->override_diff = (RNAPropOverrideDiff)"rna_property_override_diff_default";
|
||||
prop->override_store = (RNAPropOverrideStore)"rna_property_override_store_default";
|
||||
prop->override_apply = (RNAPropOverrideApply)"rna_property_override_apply_default";
|
||||
}
|
||||
/* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */
|
||||
|
||||
rna_addtail(&cont->properties, prop);
|
||||
|
||||
return prop;
|
||||
|
@ -2222,6 +2230,29 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
|
|||
if (editable) prop->itemeditable = (ItemEditableFunc)editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom callbacks for override operations handling.
|
||||
*
|
||||
* \note \a diff callback will also be used by RNA comparison/equality functions.
|
||||
*/
|
||||
void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply)
|
||||
{
|
||||
if (!DefRNA.preprocess) {
|
||||
fprintf(stderr, "%s: only during preprocessing.\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (diff) {
|
||||
prop->override_diff = (RNAPropOverrideDiff)diff;
|
||||
}
|
||||
if (store) {
|
||||
prop->override_store = (RNAPropOverrideStore)store;
|
||||
}
|
||||
if (apply) {
|
||||
prop->override_apply = (RNAPropOverrideApply)apply;
|
||||
}
|
||||
}
|
||||
|
||||
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
|
||||
{
|
||||
if (!DefRNA.preprocess) {
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
|
||||
struct FreestyleSettings;
|
||||
struct ID;
|
||||
struct IDOverrideStatic;
|
||||
struct IDOverrideStaticProperty;
|
||||
struct IDOverrideStaticPropertyOperation;
|
||||
struct IDProperty;
|
||||
struct Main;
|
||||
struct Mesh;
|
||||
|
@ -201,6 +204,12 @@ void RNA_def_mask(struct BlenderRNA *brna);
|
|||
|
||||
void rna_def_animdata_common(struct StructRNA *srna);
|
||||
|
||||
bool rna_AnimaData_override_apply(
|
||||
struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
|
||||
struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
|
||||
const int len_local, const int len_reference, const int len_storage,
|
||||
struct IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
void rna_def_animviz_common(struct StructRNA *srna);
|
||||
void rna_def_motionpath_common(struct StructRNA *srna);
|
||||
|
||||
|
@ -391,6 +400,33 @@ extern StructRNA RNA_PropertyGroup;
|
|||
|
||||
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
|
||||
|
||||
/* Override default callbacks. */
|
||||
/* Default override callbacks for all types. */
|
||||
/* TODO: Maybe at some point we'll want to write that in direct RNA-generated code instead
|
||||
* (like we do for default get/set/etc.)?
|
||||
* Not obvious though, those are fairly more complicated than basic SDNA access.
|
||||
*/
|
||||
int rna_property_override_diff_default(
|
||||
struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
|
||||
struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
|
||||
const int len_a, const int len_b,
|
||||
const int mode,
|
||||
struct IDOverrideStatic *override, const char *rna_path,
|
||||
const int flags, bool *r_override_changed);
|
||||
|
||||
bool rna_property_override_store_default(
|
||||
struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
|
||||
struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
|
||||
const int len_local, const int len_reference, const int len_storage,
|
||||
struct IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
bool rna_property_override_apply_default(
|
||||
struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
|
||||
struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
|
||||
const int len_dst, const int len_src, const int len_storage,
|
||||
struct IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
|
||||
/* Builtin Property Callbacks */
|
||||
|
||||
void rna_builtin_properties_begin(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
|
||||
|
|
|
@ -40,6 +40,9 @@ struct PointerRNA;
|
|||
struct FunctionRNA;
|
||||
struct CollectionPropertyIterator;
|
||||
struct bContext;
|
||||
struct IDOverrideStatic;
|
||||
struct IDOverrideStaticProperty;
|
||||
struct IDOverrideStaticPropertyOperation;
|
||||
struct IDProperty;
|
||||
struct GHash;
|
||||
struct Main;
|
||||
|
@ -117,6 +120,60 @@ typedef void (*PropStringSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *
|
|||
typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop);
|
||||
typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
|
||||
|
||||
/* Handling override operations, and also comparison. */
|
||||
enum {
|
||||
/* Do not compare properties that are not overridable. */
|
||||
RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
|
||||
/* Do not compare properties that are already overridden. */
|
||||
RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
|
||||
* following comparison mode given.
|
||||
* If \a override and \a rna_path are not NULL, it will add a new override operation for overridable properties
|
||||
* that differ and have not yet been overridden (and set accordingly \a r_override_changed if given).
|
||||
*
|
||||
* \note Given PropertyRNA are final (in case of IDProps...).
|
||||
* \note In non-array cases, \a len values are 0.
|
||||
* \note \a override, \a rna_path and \a r_override_changed may be NULL pointers.
|
||||
*/
|
||||
typedef int (*RNAPropOverrideDiff)(
|
||||
struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
|
||||
struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
|
||||
const int len_a, const int len_b,
|
||||
const int mode,
|
||||
struct IDOverrideStatic *override, const char *rna_path,
|
||||
const int flags, bool *r_override_changed);
|
||||
|
||||
/**
|
||||
* Only used for differential override (add, sub, etc.).
|
||||
* Store into storage the value needed to transform reference's value into local's value.
|
||||
*
|
||||
* \note Given PropertyRNA are final (in case of IDProps...).
|
||||
* \note In non-array cases, \a len values are 0.
|
||||
* \note Might change given override operation (e.g. change 'add' one into 'sub'), in case computed storage value
|
||||
* is out of range (or even change it to basic 'set' operation if nothing else works).
|
||||
*/
|
||||
typedef bool (*RNAPropOverrideStore)(
|
||||
struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
|
||||
struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
|
||||
const int len_local, const int len_reference, const int len_storage,
|
||||
struct IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
/**
|
||||
* Apply given override operation from src to dst (using value from storage as second operand
|
||||
* for differential operations).
|
||||
*
|
||||
* \note Given PropertyRNA are final (in case of IDProps...).
|
||||
* \note In non-array cases, \a len values are 0.
|
||||
*/
|
||||
typedef bool (*RNAPropOverrideApply)(
|
||||
struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
|
||||
struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
|
||||
const int len_dst, const int len_src, const int len_storage,
|
||||
struct IDOverrideStaticPropertyOperation *opop);
|
||||
|
||||
/* Container - generic abstracted container of RNA properties */
|
||||
typedef struct ContainerRNA {
|
||||
void *next, *prev;
|
||||
|
@ -194,6 +251,11 @@ struct PropertyRNA {
|
|||
/* callback for testing if array-item editable (if applicable) */
|
||||
ItemEditableFunc itemeditable;
|
||||
|
||||
/* Override handling callbacks (diff is also used for comparison). */
|
||||
RNAPropOverrideDiff override_diff;
|
||||
RNAPropOverrideStore override_store;
|
||||
RNAPropOverrideApply override_apply;
|
||||
|
||||
/* raw access */
|
||||
int rawoffset;
|
||||
RawPropertyType rawtype;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue