Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h1
-rw-r--r--source/blender/blenkernel/intern/lib_override.c16
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_ID.c257
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--tests/python/bl_blendfile_library_overrides.py102
7 files changed, 326 insertions, 59 deletions
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 96695ff1be5..f44cf23fb58 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2244,6 +2244,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_switch_object_operator"}, "T80402"),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_asset_browser"}, ("project/profile/124/", "Milestone 1")),
+ ({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
),
)
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index f69580d38be..0750a3332a8 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -74,6 +74,7 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference);
+bool BKE_lib_override_library_template_create(struct ID *id);
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index c755d153100..dbb46aa5780 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -823,6 +823,22 @@ bool BKE_lib_override_library_create(
}
/**
+ * Create a library override template.
+ */
+bool BKE_lib_override_library_template_create(struct ID *id)
+{
+ if (ID_IS_LINKED(id)) {
+ return false;
+ }
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ return false;
+ }
+
+ BKE_lib_override_library_init(id, NULL);
+ return true;
+}
+
+/**
* Convert a given proxy object into a library override.
*
* \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 4595b12e9d4..334669d3433 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -646,7 +646,8 @@ typedef struct UserDef_Experimental {
char use_switch_object_operator;
char use_sculpt_tools_tilt;
char use_asset_browser;
- char _pad[6];
+ char use_override_templates;
+ char _pad[5];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 6e2005b7314..8d9e7852b4c 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -85,6 +85,47 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_enum_override_library_property_operation_items[] = {
+ {IDOVERRIDE_LIBRARY_OP_NOOP,
+ "NOOP",
+ 0,
+ "No-Op",
+ "Does nothing, prevents adding actual overrides (NOT USED)"},
+ {IDOVERRIDE_LIBRARY_OP_REPLACE,
+ "REPLACE",
+ 0,
+ "Replace",
+ "Replace value of reference by overriding one"},
+ {IDOVERRIDE_LIBRARY_OP_ADD,
+ "DIFF_ADD",
+ 0,
+ "Differential",
+ "Stores and apply difference between reference and local value (NOT USED)"},
+ {IDOVERRIDE_LIBRARY_OP_SUBTRACT,
+ "DIFF_SUB",
+ 0,
+ "Differential",
+ "Stores and apply difference between reference and local value (NOT USED)"},
+ {IDOVERRIDE_LIBRARY_OP_MULTIPLY,
+ "FACT_MULTIPLY",
+ 0,
+ "Factor",
+ "Stores and apply multiplication factor between reference and local value (NOT USED)"},
+ {IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
+ "INSERT_AFTER",
+ 0,
+ "Insert After",
+ "Insert a new item into collection after the one referenced in subitem_reference_name or "
+ "_index"},
+ {IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE,
+ "INSERT_BEFORE",
+ 0,
+ "Insert Before",
+ "Insert a new item into collection after the one referenced in subitem_reference_name or "
+ "_index (NOT USED)"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "DNA_anim_types.h"
@@ -552,6 +593,65 @@ static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
return local_id;
}
+static void rna_ID_override_template_create(ID *id, ReportList *reports)
+{
+ if (!U.experimental.use_override_templates) {
+ BKE_report(reports, RPT_WARNING, "Override template experimental feature is disabled");
+ return;
+ }
+ if (ID_IS_LINKED(id)) {
+ BKE_report(reports, RPT_ERROR, "Unable to create override template for linked data-blocks");
+ return;
+ }
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ BKE_report(
+ reports, RPT_ERROR, "Unable to create override template for overridden data-blocks");
+ return;
+ }
+ BKE_lib_override_library_template_create(id);
+}
+
+static IDOverrideLibraryProperty *rna_ID_override_library_properties_add(
+ IDOverrideLibrary *override_library, ReportList *reports, const char rna_path[])
+{
+ bool created;
+ IDOverrideLibraryProperty *result = BKE_lib_override_library_property_get(
+ override_library, rna_path, &created);
+
+ if (!created) {
+ BKE_report(reports, RPT_DEBUG, "No new override property created, property already exists");
+ }
+
+ return result;
+}
+
+static IDOverrideLibraryPropertyOperation *rna_ID_override_library_property_operations_add(
+ IDOverrideLibraryProperty *override_property,
+ ReportList *reports,
+ int operation,
+ const char *subitem_refname,
+ const char *subitem_locname,
+ int subitem_refindex,
+ int subitem_locindex)
+{
+ bool created;
+ bool strict;
+ IDOverrideLibraryPropertyOperation *result = BKE_lib_override_library_property_operation_get(
+ override_property,
+ operation,
+ subitem_refname,
+ subitem_locname,
+ subitem_refindex,
+ subitem_locindex,
+ false,
+ &strict,
+ &created);
+ if (!created) {
+ BKE_report(reports, RPT_DEBUG, "No new override operation created, operation already exists");
+ }
+ return result;
+}
+
static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag)
{
/* XXX, new function for this! */
@@ -1267,47 +1367,6 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem override_library_property_operation_items[] = {
- {IDOVERRIDE_LIBRARY_OP_NOOP,
- "NOOP",
- 0,
- "No-Op",
- "Does nothing, prevents adding actual overrides (NOT USED)"},
- {IDOVERRIDE_LIBRARY_OP_REPLACE,
- "REPLACE",
- 0,
- "Replace",
- "Replace value of reference by overriding one"},
- {IDOVERRIDE_LIBRARY_OP_ADD,
- "DIFF_ADD",
- 0,
- "Differential",
- "Stores and apply difference between reference and local value (NOT USED)"},
- {IDOVERRIDE_LIBRARY_OP_SUBTRACT,
- "DIFF_SUB",
- 0,
- "Differential",
- "Stores and apply difference between reference and local value (NOT USED)"},
- {IDOVERRIDE_LIBRARY_OP_MULTIPLY,
- "FACT_MULTIPLY",
- 0,
- "Factor",
- "Stores and apply multiplication factor between reference and local value (NOT USED)"},
- {IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
- "INSERT_AFTER",
- 0,
- "Insert After",
- "Insert a new item into collection after the one referenced in subitem_reference_name or "
- "_index"},
- {IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE,
- "INSERT_BEFORE",
- 0,
- "Insert Before",
- "Insert a new item into collection after the one referenced in subitem_reference_name or "
- "_index (NOT USED)"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem override_library_property_flag_items[] = {
{IDOVERRIDE_LIBRARY_FLAG_MANDATORY,
"MANDATORY",
@@ -1329,7 +1388,7 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
prop = RNA_def_enum(srna,
"operation",
- override_library_property_operation_items,
+ rna_enum_override_library_property_operation_items,
IDOVERRIDE_LIBRARY_OP_REPLACE,
"Operation",
"What override operation is performed");
@@ -1386,6 +1445,66 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
}
+static void rna_def_ID_override_library_property_operations(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "IDOverrideLibraryPropertyOperations");
+ srna = RNA_def_struct(brna, "IDOverrideLibraryPropertyOperations", NULL);
+ RNA_def_struct_sdna(srna, "IDOverrideLibraryProperty");
+ RNA_def_struct_ui_text(srna, "Override Operations", "Collection of override operations");
+
+ /* Add Property */
+ func = RNA_def_function(srna, "add", "rna_ID_override_library_property_operations_add");
+ RNA_def_function_ui_description(func, "Add a new operation");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_enum(func,
+ "operation",
+ rna_enum_override_library_property_operation_items,
+ IDOVERRIDE_LIBRARY_OP_REPLACE,
+ "Operation",
+ "What override operation is performed");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func,
+ "subitem_reference_name",
+ NULL,
+ INT_MAX,
+ "Subitem Reference Name",
+ "Used to handle insertions into collection");
+ parm = RNA_def_string(func,
+ "subitem_local_name",
+ NULL,
+ INT_MAX,
+ "Subitem Local Name",
+ "Used to handle insertions into collection");
+ parm = RNA_def_int(func,
+ "subitem_reference_index",
+ -1,
+ -1,
+ INT_MAX,
+ "Subitem Reference Index",
+ "Used to handle insertions into collection",
+ -1,
+ INT_MAX);
+ parm = RNA_def_int(func,
+ "subitem_local_index",
+ -1,
+ -1,
+ INT_MAX,
+ "Subitem Local Index",
+ "Used to handle insertions into collection",
+ -1,
+ INT_MAX);
+ parm = RNA_def_pointer(func,
+ "property",
+ "IDOverrideLibraryPropertyOperation",
+ "New Operation",
+ "Created operation");
+ RNA_def_function_return(func, parm);
+}
+
static void rna_def_ID_override_library_property(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1405,18 +1524,47 @@ static void rna_def_ID_override_library_property(BlenderRNA *brna)
"RNA path leading to that property, from owning ID");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
- RNA_def_collection(srna,
- "operations",
- "IDOverrideLibraryPropertyOperation",
- "Operations",
- "List of overriding operations for a property");
+ prop = RNA_def_collection(srna,
+ "operations",
+ "IDOverrideLibraryPropertyOperation",
+ "Operations",
+ "List of overriding operations for a property");
+ rna_def_ID_override_library_property_operations(brna, prop);
rna_def_ID_override_library_property_operation(brna);
}
+static void rna_def_ID_override_library_properties(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "IDOverrideLibraryProperties");
+ srna = RNA_def_struct(brna, "IDOverrideLibraryProperties", NULL);
+ RNA_def_struct_sdna(srna, "IDOverrideLibrary");
+ RNA_def_struct_ui_text(srna, "Override Properties", "Collection of override properties");
+
+ /* Add Property */
+ func = RNA_def_function(srna, "add", "rna_ID_override_library_properties_add");
+ RNA_def_function_ui_description(
+ func, "Add a property to the override library when it doesn't exist yet");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func,
+ "property",
+ "IDOverrideLibraryProperty",
+ "New Property",
+ "Newly created override property or existing one");
+ RNA_def_function_return(func, parm);
+ parm = RNA_def_string(
+ func, "rna_path", NULL, 256, "RNA Path", "RNA-Path of the property to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
static void rna_def_ID_override_library(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "IDOverrideLibrary", NULL);
RNA_def_struct_ui_text(
@@ -1425,11 +1573,12 @@ static void rna_def_ID_override_library(BlenderRNA *brna)
RNA_def_pointer(
srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override");
- RNA_def_collection(srna,
- "properties",
- "IDOverrideLibraryProperty",
- "Properties",
- "List of overridden properties");
+ prop = RNA_def_collection(srna,
+ "properties",
+ "IDOverrideLibraryProperty",
+ "Properties",
+ "List of overridden properties");
+ rna_def_ID_override_library_properties(brna, prop);
rna_def_ID_override_library_property(brna);
}
@@ -1581,6 +1730,10 @@ static void rna_def_ID(BlenderRNA *brna)
"Whether local usages of the linked ID should be remapped to the new "
"library override of it");
+ func = RNA_def_function(srna, "override_template_create", "rna_ID_override_template_create");
+ RNA_def_function_ui_description(func, "Create an override template for this ID");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+
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, "
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 6f1884f50f4..baf77aae87f 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6305,6 +6305,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
prop,
"Asset Browser",
"Enable Asset Browser editor and operators to manage data-blocks as asset");
+
+ prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
+ RNA_def_property_ui_text(
+ prop, "Override Templates", "Enable library override template in the python API");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py
index ab75a410590..ccb2fcc01c8 100644
--- a/tests/python/bl_blendfile_library_overrides.py
+++ b/tests/python/bl_blendfile_library_overrides.py
@@ -1,6 +1,6 @@
# Apache License, Version 2.0
-# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py
+# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py -- --output-dir=/tmp/
import pathlib
import bpy
import sys
@@ -16,6 +16,8 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase):
OBJECT_LIBRARY_PARENT = "LibMeshParent"
MESH_LIBRARY_CHILD = "LibMeshChild"
OBJECT_LIBRARY_CHILD = "LibMeshChild"
+ MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive"
+ OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive"
def __init__(self, args):
self.args = args
@@ -33,6 +35,14 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase):
obj_child = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_CHILD, object_data=mesh_child)
obj_child.parent = obj
bpy.context.collection.objects.link(obj_child)
+
+ mesh = bpy.data.meshes.new(TestLibraryOverrides.MESH_LIBRARY_PERMISSIVE)
+ obj = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh)
+ bpy.context.collection.objects.link(obj)
+ obj.override_template_create()
+ prop = obj.override_library.properties.add(rna_path='scale')
+ prop.operations.add(operation='NOOP')
+
bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False)
def __ensure_override_library_updated(self):
@@ -47,29 +57,108 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase):
bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PARENT)
obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PARENT]
- assert(obj.override_library is None)
+ self.assertIsNone(obj.override_library)
local_id = obj.override_create()
- assert(local_id.override_library)
- assert(local_id.data.override_library is None)
+ self.assertIsNotNone(local_id.override_library)
+ self.assertIsNone(local_id.data.override_library)
assert(len(local_id.override_library.properties) == 0)
local_id.location.y = 1.0
self.__ensure_override_library_updated()
- assert (len(local_id.override_library.properties) == 1)
assert(len(local_id.override_library.properties) == 1)
override_prop = local_id.override_library.properties[0]
assert(override_prop.rna_path == "location");
assert(len(override_prop.operations) == 1)
override_operation = override_prop.operations[0]
- assert (override_operation.operation == 'REPLACE')
+ assert(override_operation.operation == 'REPLACE')
# Setting location.y overridded all elements in the location array. -1 is a wildcard.
assert(override_operation.subitem_local_index == -1)
+ def test_link_permissive(self):
+ """
+ Linked assets with a permissive template.
+
+ - Checks if the NOOP is properly handled.
+ - Checks if the correct properties and operations are created/updated.
+ """
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+ bpy.data.orphans_purge()
+
+ link_dir = self.output_path / "Object"
+ bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE)
+
+ obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE]
+ self.assertIsNotNone(obj.override_library)
+ local_id = obj.override_create()
+ self.assertIsNotNone(local_id.override_library)
+ self.assertIsNone(local_id.data.override_library)
+ assert(len(local_id.override_library.properties) == 1)
+ override_prop = local_id.override_library.properties[0]
+ assert(override_prop.rna_path == "scale");
+ assert(len(override_prop.operations) == 1)
+ override_operation = override_prop.operations[0]
+ assert(override_operation.operation == 'NOOP')
+ assert(override_operation.subitem_local_index == -1)
+
+ local_id.location.y = 1.0
+ local_id.scale.x = 0.5
+ # XXX(jbakker): This change should not applied. But it is as the library
+ # overrides aren't updated yet. We should expect 1.0
+ assert(local_id.scale.x == 0.5)
+ assert(local_id.location.y == 1.0)
+
+ self.__ensure_override_library_updated()
+ assert(local_id.scale.x == 1.0)
+ assert(local_id.location.y == 1.0)
+
+ assert(len(local_id.override_library.properties) == 2)
+ override_prop = local_id.override_library.properties[0]
+ assert(override_prop.rna_path == "scale");
+ assert(len(override_prop.operations) == 1)
+ override_operation = override_prop.operations[0]
+ assert(override_operation.operation == 'NOOP')
+ assert(override_operation.subitem_local_index == -1)
+
+ override_prop = local_id.override_library.properties[1]
+ assert(override_prop.rna_path == "location");
+ assert(len(override_prop.operations) == 1)
+ override_operation = override_prop.operations[0]
+ assert(override_operation.operation == 'REPLACE')
+ assert (override_operation.subitem_local_index == -1)
+
+
+class TestLibraryTemplate(TestHelper, unittest.TestCase):
+ MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive"
+ OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive"
+
+ def __init__(self, args):
+ pass
+
+ def test_permissive_template(self):
+ """
+ Test setting up a permissive template.
+ """
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+ mesh = bpy.data.meshes.new(TestLibraryTemplate.MESH_LIBRARY_PERMISSIVE)
+ obj = bpy.data.objects.new(TestLibraryTemplate.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh)
+ bpy.context.collection.objects.link(obj)
+ assert(obj.override_library is None)
+ obj.override_template_create()
+ assert(obj.override_library is not None)
+ assert(len(obj.override_library.properties) == 0)
+ prop = obj.override_library.properties.add(rna_path='scale')
+ assert(len(obj.override_library.properties) == 1)
+ assert(len(prop.operations) == 0)
+ operation = prop.operations.add(operation='NOOP')
+ assert(len(prop.operations) == 1)
+ assert(operation.operation == 'NOOP')
+
TESTS = (
TestLibraryOverrides,
+ TestLibraryTemplate,
)
@@ -95,6 +184,7 @@ def main():
# Don't write thumbnails into the home directory.
bpy.context.preferences.filepaths.use_save_preview_images = False
+ bpy.context.preferences.experimental.use_override_templates = True
for Test in TESTS:
Test(args).run_all_tests()