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:
authorJohnny Matthews <johnny.matthews@gmail.com>2022-02-02 17:43:43 +0300
committerJohnny Matthews <johnny.matthews@gmail.com>2022-02-02 17:43:43 +0300
commit6edd8bd98f6133c362af2f8b549f276634e25737 (patch)
tree6e9dd7757ef1dbc86f8072ad26dfee8d67c1c330
parenta1f044e9b9df70efedfc4b27cc41dc4e4cd76e9b (diff)
parente54fba5591a95238b7106b6e1fba6164c69dd622 (diff)
Merge branch 'master' into 2d
-rw-r--r--release/scripts/modules/rna_xml.py30
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/nodeitems_builtins.py2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h12
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c26
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c27
-rw-r--r--source/blender/blenkernel/intern/image_partial_update.cc3
-rw-r--r--source/blender/blenkernel/intern/lib_override.c75
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c23
-rw-r--r--source/blender/blenkernel/intern/modifier.c4
-rw-r--r--source/blender/blenkernel/intern/node.cc2
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh4
-rw-r--r--source/blender/blenlib/tests/BLI_vector_set_test.cc10
-rw-r--r--source/blender/blenloader/BLO_readfile.h2
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc8
-rw-r--r--source/blender/compositor/nodes/COM_CombineXYZNode.cc55
-rw-r--r--source/blender/compositor/nodes/COM_CombineXYZNode.h36
-rw-r--r--source/blender/compositor/nodes/COM_SeparateXYZNode.cc63
-rw-r--r--source/blender/compositor/nodes/COM_SeparateXYZNode.h36
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode.hh21
-rw-r--r--source/blender/draw/engines/image/image_space.hh2
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c39
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c2
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h7
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c22
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c34
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c2
-rw-r--r--source/blender/gpu/GPU_select.h2
-rw-r--r--source/blender/gpu/GPU_texture.h3
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh8
-rw-r--r--source/blender/makesdna/DNA_armature_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/RNA_access.h13
-rw-r--r--source/blender/makesrna/intern/rna_ID.c3
-rw-r--r--source/blender/makesrna/intern/rna_asset.c2
-rw-r--r--source/blender/makesrna/intern/rna_internal.h5
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c7
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc203
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc71
-rw-r--r--source/blender/render/intern/texture_margin.cc45
-rw-r--r--source/blender/sequencer/intern/strip_add.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files.c20
-rw-r--r--tests/python/bl_keymap_validate.py2
52 files changed, 715 insertions, 245 deletions
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index 7f7b273c42b..aa8841c5efe 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -298,7 +298,7 @@ def xml2rna(
del value_xml_split
tp_name = 'ARRAY'
-# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
+ # print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
try:
setattr(value, attr, value_xml_coerce)
except ValueError:
@@ -340,7 +340,6 @@ def xml2rna(
else:
# print(elems)
-
if len(elems) == 1:
# sub node named by its type
child_xml_real, = elems
@@ -376,7 +375,6 @@ def _get_context_val(context, path):
def xml_file_run(context, filepath, rna_map):
-
import xml.dom.minidom
xml_nodes = xml.dom.minidom.parse(filepath)
@@ -391,27 +389,25 @@ def xml_file_run(context, filepath, rna_map):
value = _get_context_val(context, rna_path)
if value is not Ellipsis and value is not None:
- print(" loading XML: %r -> %r" % (filepath, rna_path))
+ # print(" loading XML: %r -> %r" % (filepath, rna_path))
xml2rna(xml_node, root_rna=value)
def xml_file_write(context, filepath, rna_map, *, skip_typemap=None):
-
- file = open(filepath, "w", encoding="utf-8")
- fw = file.write
-
- fw("<bpy>\n")
-
- for rna_path, _xml_tag in rna_map:
- # xml_tag is ignored, we get this from the rna
- value = _get_context_val(context, rna_path)
- rna2xml(fw,
+ with open(filepath, "w", encoding="utf-8") as file:
+ fw = file.write
+ fw("<bpy>\n")
+
+ for rna_path, _xml_tag in rna_map:
+ # xml_tag is ignored, we get this from the rna
+ value = _get_context_val(context, rna_path)
+ rna2xml(
+ fw=fw,
root_rna=value,
method='ATTR',
root_ident=" ",
ident_val=" ",
skip_typemap=skip_typemap,
- )
+ )
- fw("</bpy>\n")
- file.close()
+ fw("</bpy>\n")
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 0548486c786..78ef68e0bab 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2316,7 +2316,6 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
context, (
({"property": "use_undo_legacy"}, "T60695"),
({"property": "override_auto_resync"}, "T83811"),
- ({"property": "proxy_to_override_auto_conversion"}, "T91671"),
({"property": "use_cycles_debug"}, None),
({"property": "use_geometry_nodes_legacy"}, "T91274"),
({"property": "show_asset_debug_info"}, None),
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index b841cb5dd13..4b48f5f0680 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -547,6 +547,8 @@ compositor_node_categories = [
NodeItem("CompositorNodeCombYUVA"),
NodeItem("CompositorNodeSepYCCA"),
NodeItem("CompositorNodeCombYCCA"),
+ NodeItem("CompositorNodeSeparateXYZ"),
+ NodeItem("CompositorNodeCombineXYZ"),
NodeItem("CompositorNodeSwitchView"),
NodeItem("CompositorNodeConvertColorSpace"),
]),
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 091f9784697..645d049fe71 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 0
+#define BLENDER_FILE_SUBVERSION 1
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 30e75259967..e8065566c97 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -100,6 +100,9 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
* main. You can add more local IDs to be remapped to use new overriding ones by setting their
* LIB_TAG_DOIT tag.
*
+ * \param owner_library: the library in which the overrides should be created. Besides versioning
+ * and resync code path, this should always be NULL (i.e. the local .blend file).
+ *
* \param reference_library: the library from which the linked data being overridden come from
* (i.e. the library of the linked reference ID).
*
@@ -109,6 +112,7 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
* \return \a true on success, \a false otherwise.
*/
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
+ struct Library *owner_library,
const struct Library *reference_library,
bool do_no_main);
/**
@@ -122,16 +126,24 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
*
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
+ *
+ * \param owner_library: the library in which the overrides should be created. Besides versioning
+ * and resync code path, this should always be NULL (i.e. the local .blend file).
+ *
* \param id_root: The root ID to create an override from.
+ *
* \param id_reference: Some reference ID used to do some post-processing after overrides have been
* created, may be NULL. Typically, the Empty object instantiating the linked collection we
* override, currently.
+ *
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
+ *
* \return true if override was successfully created.
*/
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
+ struct Library *owner_library,
struct ID *id_root,
struct ID *id_reference,
struct ID **r_id_root_override);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 16d8ba2e6dd..d583b5f0648 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1291,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_POSTERIZE 327
#define CMP_NODE_CONVERT_COLOR_SPACE 328
#define CMP_NODE_SCENE_TIME 329
+#define CMP_NODE_SEPARATE_XYZ 330
+#define CMP_NODE_COMBINE_XYZ 331
/* channel toggles */
#define CMP_CHAN_RGB 1
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6ae19c8036f..819f786a2d0 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -78,6 +78,23 @@
/** \name High Level `.blend` file read/write.
* \{ */
+static bool blendfile_or_libraries_versions_atleast(Main *bmain,
+ const short versionfile,
+ const short subversionfile)
+{
+ if (!MAIN_VERSION_ATLEAST(bmain, versionfile, subversionfile)) {
+ return false;
+ }
+
+ LISTBASE_FOREACH (Library *, library, &bmain->libraries) {
+ if (!MAIN_VERSION_ATLEAST(library, versionfile, subversionfile)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
char *path_dst,
const char *path_src)
@@ -349,10 +366,11 @@ static void setup_app_data(bContext *C,
do_versions_ipos_to_animato(bmain);
}
- /* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */
- /* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a
- * version bump and check here. */
- if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) {
+ /* NOTE: readfile's `do_version` does not allow to create new IDs, and only operates on a single
+ * library at a time. This code needs to operate on the whole Main at once. */
+ /* NOTE: Check bmain version (i.e. current blend file version), AND the versions of all the
+ * linked libraries. */
+ if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) {
BKE_lib_override_library_main_proxy_convert(bmain, reports);
}
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 9b3f4c2fae8..94d14b63437 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -993,6 +993,27 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d
/** \name Library link/append code.
* \{ */
+static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports)
+{
+ /* NOTE: Do not bother checking file versions here, if there are no proxies to convert this code
+ * is quite fast anyway. */
+
+ BlendFileReadReport bf_reports = {.reports = reports};
+ BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports);
+
+ if (bf_reports.count.proxies_to_lib_overrides_success != 0 ||
+ bf_reports.count.proxies_to_lib_overrides_failures != 0) {
+ BKE_reportf(
+ bf_reports.reports,
+ RPT_WARNING,
+ "Proxies have been removed from Blender (%d proxies were automatically converted "
+ "to library overrides, %d proxies could not be converted and were cleared). "
+ "Please consider re-saving any library .blend file with the newest Blender version.",
+ bf_reports.count.proxies_to_lib_overrides_success,
+ bf_reports.count.proxies_to_lib_overrides_failures);
+ }
+}
+
void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
{
if (lapp_context->num_items == 0) {
@@ -1259,6 +1280,8 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
}
BKE_main_id_newptr_and_tag_clear(bmain);
+
+ blendfile_link_append_proxies_convert(bmain, reports);
}
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
@@ -1361,6 +1384,10 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
.active_collection = NULL};
loose_data_instantiate(&instantiate_context);
}
+
+ if ((lapp_context->params->flag & FILE_LINK) != 0) {
+ blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports);
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc
index ddf0e18ff9b..876e5276e5a 100644
--- a/source/blender/blenkernel/intern/image_partial_update.cc
+++ b/source/blender/blenkernel/intern/image_partial_update.cc
@@ -273,7 +273,8 @@ struct TileChangeset {
const int previous_chunk_len = chunk_dirty_flags_.size();
chunk_dirty_flags_.resize(chunk_len);
- /* Fast exit. When the changeset was already empty no need to re-init the chunk_validity. */
+ /* Fast exit. When the changeset was already empty no need to
+ * re-initialize the chunk_validity. */
if (!has_dirty_chunks()) {
return;
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index d1375b1e5b5..5abe0f5e6be 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -211,6 +211,7 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo
}
static ID *lib_override_library_create_from(Main *bmain,
+ Library *owner_library,
ID *reference_id,
const int lib_id_copy_flags)
{
@@ -227,6 +228,12 @@ static ID *lib_override_library_create_from(Main *bmain,
}
id_us_min(local_id);
+ /* TODO: Handle this properly in LIB_NO_MAIN case as well (i.e. resync case). Or offload to
+ * generic ID copy code? */
+ if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) == 0) {
+ local_id->lib = owner_library;
+ }
+
BKE_lib_override_library_init(local_id, reference_id);
/* NOTE: From liboverride perspective (and RNA one), shape keys are considered as local embedded
@@ -281,7 +288,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
BLI_assert(reference_id != NULL);
BLI_assert(ID_IS_LINKED(reference_id));
- ID *local_id = lib_override_library_create_from(bmain, reference_id, 0);
+ ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0);
/* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant
* mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies.
* Ref T94650. */
@@ -320,6 +327,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
}
bool BKE_lib_override_library_create_from_tag(Main *bmain,
+ Library *owner_library,
const Library *reference_library,
const bool do_no_main)
{
@@ -351,7 +359,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* This requires extra care further down the resync process,
* see: #BKE_lib_override_library_resync. */
reference_id->newid = lib_override_library_create_from(
- bmain, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
+ bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
if (reference_id->newid == NULL) {
success = false;
break;
@@ -813,7 +821,10 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
lib_override_overrides_group_tag_recursive(data);
}
-static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_root)
+static bool lib_override_library_create_do(Main *bmain,
+ Scene *scene,
+ Library *owner_library,
+ ID *id_root)
{
BKE_main_relations_create(bmain, 0);
LibOverrideGroupTagData data = {.bmain = bmain,
@@ -832,12 +843,13 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data);
- return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
+ return BKE_lib_override_library_create_from_tag(bmain, owner_library, id_root->lib, false);
}
static void lib_override_library_create_post_process(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
+ const Library *owner_library,
ID *id_root,
ID *id_reference,
Collection *residual_storage,
@@ -859,7 +871,8 @@ static void lib_override_library_create_post_process(Main *bmain,
/* Instantiating the root collection or object should never be needed in resync case, since the
* old override would be remapped to the new one. */
- if (!is_resync && id_root != NULL && id_root->newid != NULL && !ID_IS_LINKED(id_root->newid)) {
+ if (!is_resync && id_root != NULL && id_root->newid != NULL &&
+ (!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) {
switch (GS(id_root->name)) {
case ID_GR: {
Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
@@ -904,7 +917,7 @@ static void lib_override_library_create_post_process(Main *bmain,
Collection *default_instantiating_collection = residual_storage;
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
Object *ob_new = (Object *)ob->id.newid;
- if (ob_new == NULL || ID_IS_LINKED(ob_new)) {
+ if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
continue;
}
@@ -967,6 +980,7 @@ static void lib_override_library_create_post_process(Main *bmain,
bool BKE_lib_override_library_create(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
+ Library *owner_library,
ID *id_root,
ID *id_reference,
ID **r_id_root_override)
@@ -975,7 +989,7 @@ bool BKE_lib_override_library_create(Main *bmain,
*r_id_root_override = NULL;
}
- const bool success = lib_override_library_create_do(bmain, scene, id_root);
+ const bool success = lib_override_library_create_do(bmain, scene, owner_library, id_root);
if (!success) {
return success;
@@ -986,7 +1000,7 @@ bool BKE_lib_override_library_create(Main *bmain,
}
lib_override_library_create_post_process(
- bmain, scene, view_layer, id_root, id_reference, NULL, false);
+ bmain, scene, view_layer, owner_library, id_root, id_reference, NULL, false);
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1026,7 +1040,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
/* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
* sure this is a valid state, but for now just abort the overriding process. */
- if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
+ if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root)) {
+ if (ob_proxy->proxy != NULL) {
+ ob_proxy->proxy->proxy_from = NULL;
+ }
+ id_us_min((ID *)ob_proxy->proxy);
+ ob_proxy->proxy = ob_proxy->proxy_group = NULL;
return false;
}
@@ -1044,18 +1063,19 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE);
/* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created
- * overrides.
+ * overrides. Also do that for the IDs from the same lib as the proxy in case it is linked.
* While this might not be 100% the desired behavior, it is likely to be the case most of the
* time. Ref: T91711. */
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (!ID_IS_LINKED(id_iter)) {
+ if (!ID_IS_LINKED(id_iter) || id_iter->lib == ob_proxy->id.lib) {
id_iter->tag |= LIB_TAG_DOIT;
}
}
FOREACH_MAIN_ID_END;
- return BKE_lib_override_library_create(bmain, scene, view_layer, id_root, id_reference, NULL);
+ return BKE_lib_override_library_create(
+ bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_reference, NULL);
}
static void lib_override_library_proxy_convert_do(Main *bmain,
@@ -1105,18 +1125,24 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
- if (ID_IS_LINKED(object)) {
- if (object->proxy != NULL) {
- CLOG_WARN(&LOG, "Did not try to convert linked proxy object '%s'", object->id.name);
- reports->count.linked_proxies++;
- }
- continue;
- }
-
if (object->proxy_group != NULL || object->proxy != NULL) {
- CLOG_WARN(
- &LOG, "Proxy object '%s' failed to be converted to library override", object->id.name);
+ if (ID_IS_LINKED(object)) {
+ CLOG_WARN(&LOG,
+ "Linked proxy object '%s' from '%s' failed to be converted to library override",
+ object->id.name + 2,
+ object->id.lib->filepath);
+ }
+ else {
+ CLOG_WARN(&LOG,
+ "Proxy object '%s' failed to be converted to library override",
+ object->id.name + 2);
+ }
reports->count.proxies_to_lib_overrides_failures++;
+ if (object->proxy != NULL) {
+ object->proxy->proxy_from = NULL;
+ }
+ id_us_min((ID *)object->proxy);
+ object->proxy = object->proxy_group = NULL;
}
}
}
@@ -1288,7 +1314,7 @@ static bool lib_override_library_resync(Main *bmain,
* override IDs (including within the old overrides themselves, since those are tagged too
* above). */
const bool success = BKE_lib_override_library_create_from_tag(
- bmain, id_root_reference->lib, true);
+ bmain, NULL, id_root_reference->lib, true);
if (!success) {
return success;
@@ -1502,6 +1528,7 @@ static bool lib_override_library_resync(Main *bmain,
lib_override_library_create_post_process(bmain,
scene,
view_layer,
+ NULL,
id_root_reference,
id_root,
override_resync_residual_storage,
@@ -1926,7 +1953,7 @@ void BKE_lib_override_library_main_resync(Main *bmain,
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
lib_override_library_create_post_process(
- bmain, scene, view_layer, NULL, NULL, override_resync_residual_storage, true);
+ bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true);
if (BKE_collection_is_empty(override_resync_residual_storage)) {
BKE_collection_delete(bmain, override_resync_residual_storage, true);
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index ff2ac8ecee9..3f2d81b6dc2 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,19 +34,29 @@
#include "MEM_guardedalloc.h"
+/* General note on iterating vers/loops/edges/polys and end mode.
+ *
+ * The edit mesh pointer is set for both final and cage meshes in both cases when there are
+ * modifiers applied and not. This helps consistency of checks in the draw manager, where the
+ * existence of the edit mesh pointer does not depend on object configuration.
+ *
+ * For the iterating, however, we need to follow the `CD_ORIGINDEX` code paths when there are
+ * modifiers applied on the cage. In the code terms it means that the check for the edit mode code
+ * path needs to consist of both edit mesh and edit data checks. */
+
void BKE_mesh_foreach_mapped_vert(
Mesh *mesh,
void (*func)(void *userData, int index, const float co[3], const float no[3]),
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMVert *eve;
int i;
- if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
@@ -100,13 +110,13 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMEdge *eed;
int i;
- if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
@@ -158,14 +168,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
/* We can't use dm->getLoopDataLayout(dm) here,
* we want to always access dm->loopData, EditDerivedBMesh would
* return loop data from bmesh itself. */
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMFace *efa;
- const float(*vertexCos)[3] = mesh->runtime.edit_data ? mesh->runtime.edit_data->vertexCos :
- NULL;
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index e1fd8ff45d1..bdf2568287b 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -1182,8 +1182,8 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
#if 0
CollisionModifierData *collmd = (CollisionModifierData *)md;
- // TODO: CollisionModifier should use pointcache
- // + have proper reset events before enabling this
+ /* TODO: CollisionModifier should use pointcache
+ * + have proper reset events before enabling this. */
writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 4de07a20bdf..7276e5205f0 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4533,6 +4533,8 @@ static void registerCompositNodes()
register_node_type_cmp_sepycca();
register_node_type_cmp_combycca();
register_node_type_cmp_premulkey();
+ register_node_type_cmp_separate_xyz();
+ register_node_type_cmp_combine_xyz();
register_node_type_cmp_diff_matte();
register_node_type_cmp_distance_matte();
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 0aac96f93bc..ed744d09314 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -570,6 +570,10 @@ class VectorSet {
if (this->size() == 0) {
try {
slots_.reinitialize(total_slots);
+ if (keys_ != nullptr) {
+ this->deallocate_keys_array(keys_);
+ keys_ = nullptr;
+ }
keys_ = this->allocate_keys_array(usable_slots);
}
catch (...) {
diff --git a/source/blender/blenlib/tests/BLI_vector_set_test.cc b/source/blender/blenlib/tests/BLI_vector_set_test.cc
index c4016ca75e1..fe3130a846f 100644
--- a/source/blender/blenlib/tests/BLI_vector_set_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_set_test.cc
@@ -271,4 +271,14 @@ TEST(vector_set, LookupKey)
EXPECT_EQ(set.lookup_key_ptr("a"), set.lookup_key_ptr_as("a"));
}
+TEST(vector_set, GrowWhenEmpty)
+{
+ /* Tests that the internal keys array is freed correctly when growing an empty set. */
+ VectorSet<int> set;
+ set.add(4);
+ set.remove(4);
+ EXPECT_TRUE(set.is_empty());
+ set.reserve(100);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c4c3b42cb63..066b180dcc9 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -117,8 +117,6 @@ typedef struct BlendFileReadReport {
/* Number of root override IDs that were resynced. */
int resynced_lib_overrides;
- /* Number of (non-converted) linked proxies. */
- int linked_proxies;
/* Number of proxies converted to library overrides. */
int proxies_to_lib_overrides_success;
/* Number of proxies that failed to convert to library overrides. */
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 025e114cb52..2f473ef2945 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -274,10 +274,14 @@ set(SRC
# converter nodes
nodes/COM_CombineColorNode.cc
nodes/COM_CombineColorNode.h
+ nodes/COM_CombineXYZNode.cc
+ nodes/COM_CombineXYZNode.h
nodes/COM_IDMaskNode.cc
nodes/COM_IDMaskNode.h
nodes/COM_SeparateColorNode.cc
nodes/COM_SeparateColorNode.h
+ nodes/COM_SeparateXYZNode.cc
+ nodes/COM_SeparateXYZNode.h
nodes/COM_MapRangeNode.cc
nodes/COM_MapRangeNode.h
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 6cf6c698a2f..d0b3ae74446 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -44,6 +44,7 @@
#include "COM_ColorSpillNode.h"
#include "COM_ColorToBWNode.h"
#include "COM_CombineColorNode.h"
+#include "COM_CombineXYZNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
#include "COM_ConvertColorSpaceNode.h"
@@ -96,6 +97,7 @@
#include "COM_ScaleOperation.h"
#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
+#include "COM_SeparateXYZNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
#include "COM_SplitViewerNode.h"
@@ -434,6 +436,12 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_CONVERT_COLOR_SPACE:
node = new ConvertColorSpaceNode(b_node);
break;
+ case CMP_NODE_SEPARATE_XYZ:
+ node = new SeparateXYZNode(b_node);
+ break;
+ case CMP_NODE_COMBINE_XYZ:
+ node = new CombineXYZNode(b_node);
+ break;
}
return node;
}
diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.cc b/source/blender/compositor/nodes/COM_CombineXYZNode.cc
new file mode 100644
index 00000000000..2b71b94e192
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineXYZNode.cc
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_CombineXYZNode.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+CombineXYZNode::CombineXYZNode(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void CombineXYZNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &UNUSED(context)) const
+{
+ NodeInput *input_x_socket = this->get_input_socket(0);
+ NodeInput *input_y_socket = this->get_input_socket(1);
+ NodeInput *input_z_socket = this->get_input_socket(2);
+ NodeOutput *output_socket = this->get_output_socket(0);
+
+ CombineChannelsOperation *operation = new CombineChannelsOperation();
+ if (input_x_socket->is_linked()) {
+ operation->set_canvas_input_index(0);
+ }
+ else if (input_y_socket->is_linked()) {
+ operation->set_canvas_input_index(1);
+ }
+ else {
+ operation->set_canvas_input_index(2);
+ }
+ converter.add_operation(operation);
+
+ converter.map_input_socket(input_x_socket, operation->get_input_socket(0));
+ converter.map_input_socket(input_y_socket, operation->get_input_socket(1));
+ converter.map_input_socket(input_z_socket, operation->get_input_socket(2));
+ converter.map_output_socket(output_socket, operation->get_output_socket());
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineXYZNode.h b/source/blender/compositor/nodes/COM_CombineXYZNode.h
new file mode 100644
index 00000000000..c3bb69b03ed
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineXYZNode.h
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+/**
+ * \brief SeparateXYZNode
+ * \ingroup Node
+ */
+class CombineXYZNode : public Node {
+ public:
+ CombineXYZNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.cc b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc
new file mode 100644
index 00000000000..749116d6217
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.cc
@@ -0,0 +1,63 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_SeparateXYZNode.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+SeparateXYZNode::SeparateXYZNode(bNode *editor_node) : Node(editor_node)
+{
+ /* pass */
+}
+
+void SeparateXYZNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &UNUSED(context)) const
+{
+ NodeInput *vector_socket = this->get_input_socket(0);
+ NodeOutput *output_x_socket = this->get_output_socket(0);
+ NodeOutput *output_y_socket = this->get_output_socket(1);
+ NodeOutput *output_z_socket = this->get_output_socket(2);
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(0);
+ converter.add_operation(operation);
+ converter.map_input_socket(vector_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_x_socket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(1);
+ converter.add_operation(operation);
+ converter.map_input_socket(vector_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_y_socket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(2);
+ converter.add_operation(operation);
+ converter.map_input_socket(vector_socket, operation->get_input_socket(0));
+ converter.map_output_socket(output_z_socket, operation->get_output_socket(0));
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateXYZNode.h b/source/blender/compositor/nodes/COM_SeparateXYZNode.h
new file mode 100644
index 00000000000..1efa017d9e3
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateXYZNode.h
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+/**
+ * \brief SeparateXYZNode
+ * \ingroup Node
+ */
+class SeparateXYZNode : public Node {
+ public:
+ SeparateXYZNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh
index dfff93b9429..3be34ef6acb 100644
--- a/source/blender/draw/engines/image/image_drawing_mode.hh
+++ b/source/blender/draw/engines/image/image_drawing_mode.hh
@@ -227,8 +227,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
GPUTexture *texture = info.texture;
const float texture_width = GPU_texture_width(texture);
const float texture_height = GPU_texture_height(texture);
- // TODO
- // early bound check.
+ /* TODO: early bound check. */
ImageTileWrapper tile_accessor(iterator.tile_data.tile);
float tile_offset_x = static_cast<float>(tile_accessor.get_tile_x_offset());
float tile_offset_y = static_cast<float>(tile_accessor.get_tile_y_offset());
@@ -253,9 +252,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
if (!region_overlap) {
continue;
}
- // convert the overlapping region to texel space and to ss_pixel space...
- // TODO: first convert to ss_pixel space as integer based. and from there go back to texel
- // space. But perhaps this isn't needed and we could use an extraction offset somehow.
+ /* Convert the overlapping region to texel space and to ss_pixel space...
+ * TODO: first convert to ss_pixel space as integer based. and from there go back to texel
+ * space. But perhaps this isn't needed and we could use an extraction offset somehow. */
rcti gpu_texture_region_to_update;
BLI_rcti_init(&gpu_texture_region_to_update,
floor((changed_overlapping_region_in_uv_space.xmin - info.uv_bounds.xmin) *
@@ -275,8 +274,8 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
ceil((changed_overlapping_region_in_uv_space.ymin - tile_offset_y) * tile_height),
ceil((changed_overlapping_region_in_uv_space.ymax - tile_offset_y) * tile_height));
- // Create an image buffer with a size
- // extract and scale into an imbuf
+ /* Create an image buffer with a size.
+ * Extract and scale into an imbuf. */
const int texture_region_width = BLI_rcti_size_x(&gpu_texture_region_to_update);
const int texture_region_height = BLI_rcti_size_y(&gpu_texture_region_to_update);
@@ -437,17 +436,17 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
instance_data->partial_update.ensure_image(image);
instance_data->clear_dirty_flag();
- // Step: Find out which screen space textures are needed to draw on the screen. Remove the
- // screen space textures that aren't needed.
+ /* Step: Find out which screen space textures are needed to draw on the screen. Remove the
+ * screen space textures that aren't needed. */
const ARegion *region = draw_ctx->region;
method.update_screen_space_bounds(region);
method.update_uv_bounds(region);
- // Step: Update the GPU textures based on the changes in the image.
+ /* Step: Update the GPU textures based on the changes in the image. */
instance_data->update_gpu_texture_allocations();
update_textures(*instance_data, image, iuser);
- // Step: Add the GPU textures to the shgroup.
+ /* Step: Add the GPU textures to the shgroup. */
instance_data->update_batches();
add_depth_shgroups(*instance_data, image, iuser);
add_shgroups(instance_data);
diff --git a/source/blender/draw/engines/image/image_space.hh b/source/blender/draw/engines/image/image_space.hh
index 29d9cd4340b..fbb92ce24aa 100644
--- a/source/blender/draw/engines/image/image_space.hh
+++ b/source/blender/draw/engines/image/image_space.hh
@@ -22,7 +22,7 @@
#pragma once
-class ShaderParameters;
+struct ShaderParameters;
/**
* Space accessor.
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 4029f1237e8..2b80ccc57d5 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -2084,7 +2084,9 @@ static void draw_armature_edit(ArmatureDrawContext *ctx)
boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
- draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
+ if (!is_select) {
+ draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
+ }
if (arm->drawtype == ARM_ENVELOPE) {
draw_bone_update_disp_matrix_default(eBone, NULL);
@@ -2107,12 +2109,14 @@ static void draw_armature_edit(ArmatureDrawContext *ctx)
draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
}
- if (show_text && (arm->flag & ARM_DRAWNAMES)) {
- draw_bone_name(ctx, eBone, NULL, arm, boneflag);
- }
+ if (!is_select) {
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, eBone, NULL, arm, boneflag);
+ }
- if (arm->flag & ARM_DRAWAXES) {
- draw_axes(ctx, eBone, NULL, arm);
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, eBone, NULL, arm);
+ }
}
}
}
@@ -2221,7 +2225,9 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
}
- draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
+ if (!is_pose_select) {
+ draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
+ }
if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
draw_bone_update_disp_matrix_custom(pchan);
@@ -2248,16 +2254,19 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
}
- if (draw_dofs) {
- draw_bone_degrees_of_freedom(ctx, pchan);
- }
+ /* These aren't included in the selection. */
+ if (!is_pose_select) {
+ if (draw_dofs) {
+ draw_bone_degrees_of_freedom(ctx, pchan);
+ }
- if (show_text && (arm->flag & ARM_DRAWNAMES)) {
- draw_bone_name(ctx, NULL, pchan, arm, boneflag);
- }
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, NULL, pchan, arm, boneflag);
+ }
- if (arm->flag & ARM_DRAWAXES) {
- draw_axes(ctx, NULL, pchan, arm);
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, NULL, pchan, arm);
+ }
}
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index a24a3a5a3a7..4a8670a9ee2 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -999,7 +999,7 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
- // Build patch coordinates for all the face dots
+ /* Build patch coordinates for all the face dots. */
cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
mesh_eval->totpoly);
CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
@@ -1760,7 +1760,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start"));
int *subdiv_polygon_offset = cache->subdiv_polygon_offset;
- // TODO: parallel_reduce?
+ /* TODO: parallel_reduce? */
for (int i = 0; i < mesh_eval->totpoly; i++) {
const MPoly *mpoly = &mesh_eval->mpoly[i];
const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index afb786da8c6..c910162415d 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -4635,7 +4635,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
}
}
- /* Separate the entrie stroke. */
+ /* Separate the entire stroke. */
if (all_points_selected) {
/* deselect old stroke */
gps->flag &= ~GP_STROKE_SELECT;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index a6eb35d49b9..ee594398f4a 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2334,7 +2334,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
const bool success = BKE_lib_override_library_create(
- bmain, scene, view_layer, id_root, &obact->id, NULL);
+ bmain, scene, view_layer, NULL, id_root, &obact->id, NULL);
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 03fc4c20fe5..02e8ab2f128 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -875,7 +875,7 @@ static void id_override_library_create_fn(bContext *C,
}
success = BKE_lib_override_library_create(
- bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr);
+ bmain, CTX_data_scene(C), CTX_data_view_layer(C), NULL, id_root, id_reference, nullptr);
}
else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6a1a09df316..1ef737bc84b 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -40,13 +40,6 @@ struct wmKeyConfig;
struct wmOperatorType;
struct wmWindowManager;
-/* drawing flags: */
-enum {
- DRAW_PICKING = (1 << 0),
- DRAW_CONSTCOLOR = (1 << 1),
- DRAW_SCENESET = (1 << 2),
-};
-
/* view3d_header.c */
void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 9a2cc76c44e..d6b928c6fa7 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -981,6 +981,15 @@ int view3d_opengl_select_ex(ViewContext *vc,
}
}
+ /* Re-use cache (rect must be smaller than the cached)
+ * other context is assumed to be unchanged */
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ goto finally;
+ }
+
/* Important to use 'vc->obact', not 'OBACT(vc->view_layer)' below,
* so it will be NULL when hidden. */
struct {
@@ -1040,15 +1049,6 @@ int view3d_opengl_select_ex(ViewContext *vc,
UI_Theme_Store(&theme_state);
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
- /* Re-use cache (rect must be smaller than the cached)
- * other context is assumed to be unchanged */
- if (GPU_select_is_cached()) {
- GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0);
- GPU_select_cache_load_id();
- hits = GPU_select_end();
- goto finally;
- }
-
/* All of the queries need to be perform on the drawing context. */
DRW_opengl_context_enable();
@@ -1132,14 +1132,14 @@ int view3d_opengl_select_ex(ViewContext *vc,
DRW_opengl_context_disable();
+ UI_Theme_Restore(&theme_state);
+
finally:
if (hits < 0) {
printf("Too many objects in select buffer\n"); /* XXX make error message */
}
- UI_Theme_Restore(&theme_state);
-
return hits;
}
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 2a696dd0593..04a8d462924 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -751,28 +751,30 @@ void createTransPose(TransInfo *t)
tc->data_len++;
- if (has_translate_rotate[0] && has_translate_rotate[1]) {
- continue;
- }
+ if (has_translate_rotate != NULL) {
+ if (has_translate_rotate[0] && has_translate_rotate[1]) {
+ continue;
+ }
- if (has_targetless_ik(pchan) == NULL) {
- if (pchan->parent && (bone->flag & BONE_CONNECTED)) {
- if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
- has_translate_rotate[0] = true;
+ if (has_targetless_ik(pchan) == NULL) {
+ if (pchan->parent && (bone->flag & BONE_CONNECTED)) {
+ if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ has_translate_rotate[0] = true;
+ }
}
- }
- else {
- if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
- has_translate_rotate[0] = true;
+ else {
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
+ has_translate_rotate[1] = true;
}
}
- if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
- has_translate_rotate[1] = true;
+ else {
+ has_translate_rotate[0] = true;
}
}
- else {
- has_translate_rotate[0] = true;
- }
}
if (tc->data_len == 0) {
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index c1f36951f64..c0572478481 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -954,8 +954,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob_iter = objects[ob_index];
const bool use_mat_local = params->use_local_axis && (ob_iter != ob);
- bPoseChannel *pchan;
-
/* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */
const int mode = TFM_ROTATION;
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 90bbde4976c..3076058c075 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -51,7 +51,7 @@ typedef struct GPUSelectResult {
/**
* The nearest depth.
* - Only supported by picking modes (#GPU_SELECT_PICK_ALL and #GPU_SELECT_PICK_NEAREST)
- * since occlusion quiries don't provide a convenient way of accessing the depth-buffer.
+ * since occlusion quires don't provide a convenient way of accessing the depth-buffer.
* - OpenGL's `GL_SELECT` supported both near and far depths,
* this has not been included as Blender doesn't need this however support could be added.
*/
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 6fae4a13918..7812c7a7257 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -272,7 +272,8 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
* Fills the whole texture with the same data for all pixels.
* \warning Only work for 2D texture for now.
* \warning Only clears the mip 0 of the texture.
- * \param data_format: data format of the pixel data. \note The format is float for unorm textures.
+ * \param data_format: data format of the pixel data.
+ * \note The format is float for unorm textures.
* \param data: 1 pixel worth of data to fill the texture with.
*/
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f1a8178bf0a..692eb7f5db5 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -125,10 +125,10 @@ constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>);
template<typename... T>
constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>);
-// gcc (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on,
-// results in "obj_export_io.hh:205:18: warning: ā€˜%sā€™ directive output truncated writing 34 bytes
-// into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered
-// as an edge case by tests on purpose.
+/* GCC (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on,
+ * results in "obj_export_io.hh:205:18: warning: ā€˜%sā€™ directive output truncated writing 34 bytes
+ * into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered
+ * as an edge case by tests on purpose. */
#if defined __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-truncation"
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 566ffd19669..1005b5186aa 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -77,7 +77,7 @@ typedef struct Bone {
/** dist, weight: for non-deformgroup deforms. */
float dist, weight;
/**
- * The width for block bones.
+ * The width for block bones. The final X/Z bone widths are double these values.
*
* \note keep in this order for transform code which stores a pointer to `xwidth`,
* accessing length and `zwidth` as offsets.
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 15bb1ef920d..637dd216935 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -651,7 +651,6 @@ typedef struct UserDef_Experimental {
/* Debug options, always available. */
char use_undo_legacy;
char no_override_auto_resync;
- char no_proxy_to_override_conversion;
char use_cycles_debug;
char use_geometry_nodes_legacy;
char show_asset_debug_info;
@@ -666,7 +665,7 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
- char _pad[1];
+ char _pad[2];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 1ade964854d..130402a31db 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -143,6 +143,7 @@ extern StructRNA RNA_CompositorNodeCombHSVA;
extern StructRNA RNA_CompositorNodeCombRGBA;
extern StructRNA RNA_CompositorNodeCombYCCA;
extern StructRNA RNA_CompositorNodeCombYUVA;
+extern StructRNA RNA_CompositorNodeCombineXYZ;
extern StructRNA RNA_CompositorNodeComposite;
extern StructRNA RNA_CompositorNodeCornerPin;
extern StructRNA RNA_CompositorNodeCrop;
@@ -187,6 +188,7 @@ extern StructRNA RNA_CompositorNodeRLayers;
extern StructRNA RNA_CompositorNodeRotate;
extern StructRNA RNA_CompositorNodeScale;
extern StructRNA RNA_CompositorNodeSceneTime;
+extern StructRNA RNA_CompositorNodeSeparateXYZ;
extern StructRNA RNA_CompositorNodeSepHSVA;
extern StructRNA RNA_CompositorNodeSepRGBA;
extern StructRNA RNA_CompositorNodeSepYCCA;
@@ -1512,10 +1514,21 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name);
/**
* Check if the #IDproperty exists, for operators.
+ *
+ * \param use_ghost: Internally an #IDProperty may exist,
+ * without the RNA considering it to be "set", see #IDP_FLAG_GHOST.
+ * This is used for operators, where executing an operator that has run previously
+ * will re-use the last value (unless #PROP_SKIP_SAVE property is set).
+ * In this case, the presence of the an existing value shouldn't prevent it being initialized
+ * from the context. Even though the this value will be returned if it's requested,
+ * it's not considered to be set (as it would if the menu item or key-map defined it's value).
+ * Set `use_ghost` to true for default behavior, otherwise false to check if there is a value
+ * exists internally and would be returned on request.
*/
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost);
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop);
+/** See #RNA_property_is_set_ex documentation. */
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost);
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier);
bool RNA_property_is_idprop(const PropertyRNA *prop);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 1ae036a254e..1f3dd34a0a7 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -719,7 +719,8 @@ static ID *rna_ID_override_hierarchy_create(
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
ID *id_root_override = NULL;
- BKE_lib_override_library_create(bmain, scene, view_layer, id, id_reference, &id_root_override);
+ BKE_lib_override_library_create(
+ bmain, scene, view_layer, NULL, id, id_reference, &id_root_override);
WM_main_add_notifier(NC_ID | NA_ADDED, NULL);
WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index e79cbc838d4..e80c8559020 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -237,7 +237,7 @@ static void rna_AssetMetaData_catalog_id_set(PointerRNA *ptr, const char *value)
}
if (!BLI_uuid_parse_string(&new_uuid, value)) {
- // TODO(Sybren): raise ValueError exception once that's possible from an RNA setter.
+ /* TODO(@sybren): raise ValueError exception once that's possible from an RNA setter. */
printf("UUID %s not formatted correctly, ignoring new value\n", value);
return;
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index d4de20b5328..0e0391197ea 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -369,9 +369,10 @@ void rna_ViewLayer_active_aov_index_range(
PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax);
int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr);
void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value);
-/** Set `r_rna_path` with the base viewlayer path.
+/**
+ * Set `r_rna_path` with the base view-layer path.
* `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`.
- * \return actual length of the generayted RNA path.
+ * \return actual length of the generated RNA path.
*/
size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer,
char *r_rna_path,
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 4379b4ebe1d..aef219c4236 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6386,13 +6386,6 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"Enable library overrides automatic resync detection and process on file load. Disable when "
"dealing with older .blend files that need manual Resync (Enforce) handling");
- prop = RNA_def_property(srna, "proxy_to_override_auto_conversion", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "no_proxy_to_override_conversion", 1);
- RNA_def_property_ui_text(
- prop,
- "Proxy to Override Auto Conversion",
- "Enable automatic conversion of proxies to library overrides on file load");
-
prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1);
RNA_def_property_ui_text(
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 0d5a9a9e609..8415b592503 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -110,6 +110,8 @@ using blender::float3;
using blender::FunctionRef;
using blender::IndexRange;
using blender::Map;
+using blender::MultiValueMap;
+using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::StringRef;
@@ -120,7 +122,9 @@ using blender::fn::Field;
using blender::fn::GField;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
+using blender::fn::GVArray;
using blender::fn::ValueOrField;
+using blender::fn::ValueOrFieldCPPType;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::GeoNodeExecParams;
using blender::nodes::InputSocketFieldType;
@@ -955,80 +959,145 @@ static void clear_runtime_data(NodesModifierData *nmd)
}
}
-static void store_field_on_geometry_component(GeometryComponent &component,
- const StringRef attribute_name,
- AttributeDomain domain,
- const GField &field)
+struct OutputAttributeInfo {
+ GField field;
+ StringRefNull name;
+};
+
+struct OutputAttributeToStore {
+ GeometryComponentType component_type;
+ AttributeDomain domain;
+ StringRefNull name;
+ GMutableSpan data;
+};
+
+/**
+ * The output attributes are organized based on their domain, because attributes on the same domain
+ * can be evaluated together.
+ */
+static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attributes_to_store(
+ const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values)
{
- /* If the attribute name corresponds to a built-in attribute, use the domain of the built-in
- * attribute instead. */
- if (component.attribute_is_builtin(attribute_name)) {
- component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
- std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(attribute_name);
- if (meta_data.has_value()) {
- domain = meta_data->domain;
+ MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain;
+ for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
+ if (!socket_type_has_attribute_toggle(*socket->bsocket())) {
+ continue;
}
- else {
- return;
+
+ const std::string prop_name = socket->identifier() + attribute_name_suffix;
+ const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
+ if (prop == nullptr) {
+ continue;
}
+ const StringRefNull attribute_name = IDP_String(prop);
+ if (attribute_name.is_empty()) {
+ continue;
+ }
+
+ const int index = socket->index();
+ const GPointer value = output_values[index];
+ const ValueOrFieldCPPType *cpp_type = dynamic_cast<const ValueOrFieldCPPType *>(value.type());
+ BLI_assert(cpp_type != nullptr);
+ const GField field = cpp_type->as_field(value.get());
+
+ const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
+ &nmd.node_group->outputs, socket->index());
+ const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
+ OutputAttributeInfo output_info;
+ output_info.field = std::move(field);
+ output_info.name = attribute_name;
+ outputs_by_domain.add(domain, std::move(output_info));
}
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(field.cpp_type());
- OutputAttribute attribute = component.attribute_try_get_for_output_only(
- attribute_name, domain, data_type);
- if (attribute) {
- /* In the future we could also evaluate all output fields at once. */
- const int domain_size = component.attribute_domain_size(domain);
- blender::bke::GeometryComponentFieldContext field_context{component, domain};
- blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
- field_evaluator.add_with_destination(field, attribute.varray());
- field_evaluator.evaluate();
- attribute.save();
- }
+ return outputs_by_domain;
}
-static void store_output_value_in_geometry(GeometrySet &geometry_set,
- NodesModifierData *nmd,
- const InputSocketRef &socket,
- const GPointer value)
+/**
+ * The computed values are stored in newly allocated arrays. They still have to be moved to the
+ * actual geometry.
+ */
+static Vector<OutputAttributeToStore> compute_attributes_to_store(
+ const GeometrySet &geometry,
+ const MultiValueMap<AttributeDomain, OutputAttributeInfo> &outputs_by_domain)
{
- if (!socket_type_has_attribute_toggle(*socket.bsocket())) {
- return;
- }
- const std::string prop_name = socket.identifier() + attribute_name_suffix;
- const IDProperty *prop = IDP_GetPropertyFromGroup(nmd->settings.properties, prop_name.c_str());
- if (prop == nullptr) {
- return;
- }
- const StringRefNull attribute_name = IDP_String(prop);
- if (attribute_name.is_empty()) {
- return;
+ Vector<OutputAttributeToStore> attributes_to_store;
+ for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES}) {
+ if (!geometry.has(component_type)) {
+ continue;
+ }
+ const GeometryComponent &component = *geometry.get_component_for_read(component_type);
+ for (const auto item : outputs_by_domain.items()) {
+ const AttributeDomain domain = item.key;
+ const Span<OutputAttributeInfo> outputs_info = item.value;
+ if (!component.attribute_domain_supported(domain)) {
+ continue;
+ }
+ const int domain_size = component.attribute_domain_size(domain);
+ blender::bke::GeometryComponentFieldContext field_context{component, domain};
+ blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
+ for (const OutputAttributeInfo &output_info : outputs_info) {
+ const CPPType &type = output_info.field.cpp_type();
+ OutputAttributeToStore store{
+ component_type,
+ domain,
+ output_info.name,
+ GMutableSpan{
+ type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
+ field_evaluator.add_with_destination(output_info.field, store.data);
+ attributes_to_store.append(store);
+ }
+ field_evaluator.evaluate();
+ }
}
- const blender::fn::ValueOrFieldCPPType *cpp_type =
- dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type());
- BLI_assert(cpp_type != nullptr);
+ return attributes_to_store;
+}
- const GField field = cpp_type->as_field(value.get());
- const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs,
- socket.index());
- const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
- if (geometry_set.has_mesh()) {
- MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
- store_field_on_geometry_component(component, attribute_name, domain, field);
- }
- if (geometry_set.has_pointcloud()) {
- PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>();
- store_field_on_geometry_component(component, attribute_name, domain, field);
- }
- if (geometry_set.has_curve()) {
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- store_field_on_geometry_component(component, attribute_name, domain, field);
- }
- if (geometry_set.has_instances()) {
- InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
- store_field_on_geometry_component(component, attribute_name, domain, field);
+static void store_computed_output_attributes(
+ GeometrySet &geometry, const Span<OutputAttributeToStore> attributes_to_store)
+{
+ for (const OutputAttributeToStore &store : attributes_to_store) {
+ GeometryComponent &component = geometry.get_component_for_write(store.component_type);
+ /* Try deleting an existing attribute, so that we can just use `attribute_try_create` to pass
+ * in the data directly. */
+ component.attribute_try_delete(store.name);
+ if (component.attribute_exists(store.name)) {
+ /* Copy the data into an existing attribute. */
+ blender::bke::WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(
+ store.name);
+ if (write_attribute) {
+ write_attribute.varray.set_all(store.data.data());
+ store.data.type().destruct_n(store.data.data(), store.data.size());
+ MEM_freeN(store.data.data());
+ if (write_attribute.tag_modified_fn) {
+ write_attribute.tag_modified_fn();
+ }
+ }
+ }
+ else {
+ component.attribute_try_create(store.name,
+ store.domain,
+ blender::bke::cpp_type_to_custom_data_type(store.data.type()),
+ AttributeInitMove(store.data.data()));
+ }
}
}
+static void store_output_attributes(GeometrySet &geometry,
+ const NodesModifierData &nmd,
+ const NodeRef &output_node,
+ Span<GMutablePointer> output_values)
+{
+ /* All new attribute values have to be computed before the geometry is actually changed. This is
+ * necessary because some fields might depend on attributes that are overwritten. */
+ MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain =
+ find_output_attributes_to_store(nmd, output_node, output_values);
+ Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
+ geometry, outputs_by_domain);
+ store_computed_output_attributes(geometry, attributes_to_store);
+}
+
/**
* Evaluate a node group to compute the output geometry.
*/
@@ -1103,7 +1172,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params);
- GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
+ GeometrySet output_geometry_set = std::move(*eval_params.r_output_values[0].get<GeometrySet>());
if (geo_logger.has_value()) {
geo_logger->log_output_geometry(output_geometry_set);
@@ -1112,10 +1181,10 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
}
- for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
- GMutablePointer socket_value = eval_params.r_output_values[socket->index()];
- store_output_value_in_geometry(output_geometry_set, nmd, *socket, socket_value);
- socket_value.destruct();
+ store_output_attributes(output_geometry_set, *nmd, output_node, eval_params.r_output_values);
+
+ for (GMutablePointer value : eval_params.r_output_values) {
+ value.destruct();
}
return output_geometry_set;
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 82faccc2c2d..71acc738472 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -140,6 +140,8 @@ void register_node_type_cmp_pixelate(void);
void register_node_type_cmp_trackpos(void);
void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
+void register_node_type_cmp_separate_xyz(void);
+void register_node_type_cmp_combine_xyz(void);
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
void node_cmp_rlayers_register_pass(struct bNodeTree *ntree,
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 8cbde6adcad..8fd71a978e3 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -230,6 +230,8 @@ DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIAL
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
+DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" )
+DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index dddc3f33dca..8581ab7f82f 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -110,6 +110,7 @@ set(SRC
nodes/node_composite_sepcomb_rgba.cc
nodes/node_composite_sepcomb_ycca.cc
nodes/node_composite_sepcomb_yuva.cc
+ nodes/node_composite_sepcomb_xyz.cc
nodes/node_composite_setalpha.cc
nodes/node_composite_split_viewer.cc
nodes/node_composite_stabilize2d.cc
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc
new file mode 100644
index 00000000000..5dfcf5dca1e
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_xyz.cc
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+/* **************** SEPARATE XYZ ******************** */
+namespace blender::nodes {
+
+static void cmp_node_separate_xyz_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>("X");
+ b.add_output<decl::Float>("Y");
+ b.add_output<decl::Float>("Z");
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_separate_xyz()
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_XYZ, "Separate XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::cmp_node_separate_xyz_declare;
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE XYZ ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_combine_xyz_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("X").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>("Y").min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>("Z").min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Vector>("Vector");
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_combine_xyz()
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBINE_XYZ, "Combine XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::cmp_node_combine_xyz_declare;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
index 5a9d9db5367..b864aa64709 100644
--- a/source/blender/render/intern/texture_margin.cc
+++ b/source/blender/render/intern/texture_margin.cc
@@ -48,16 +48,17 @@
namespace blender::render::texturemargin {
-/* The map class contains both a pixel map which maps out polygon indices for all UV-polygons and
+/**
+ * The map class contains both a pixel map which maps out polygon indices for all UV-polygons and
* adjacency tables.
*/
class TextureMarginMap {
static const int directions[8][2];
static const int distances[8];
- /* Maps UV-edges to their corresponding UV-edge. */
+ /** Maps UV-edges to their corresponding UV-edge. */
Vector<int> loop_adjacency_map_;
- /* Maps UV-edges to their corresponding polygon. */
+ /** Maps UV-edges to their corresponding polygon. */
Vector<int> loop_to_poly_map_;
int w_, h_;
@@ -132,9 +133,7 @@ class TextureMarginMap {
static void zscan_store_pixel(
void *map, int x, int y, [[maybe_unused]] float u, [[maybe_unused]] float v)
{
- /* NOTE: Not thread safe, see comment above.
- *
- */
+ /* NOTE: Not thread safe, see comment above. */
TextureMarginMap *m = static_cast<TextureMarginMap *>(map);
m->set_pixel(x, y, m->value_to_store_);
if (m->mask_) {
@@ -153,7 +152,8 @@ class TextureMarginMap {
#define IsDijkstraPixel(dp) ((dp)&0x80000000)
#define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF)
- /* Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map.
+ /**
+ * Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map.
* For each pixel mark which direction is the shortest way to a polygon.
*/
void grow_dijkstra(int margin)
@@ -188,8 +188,10 @@ class TextureMarginMap {
}
}
- // std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
- // Not strictly needed because at this point it already is a heap.
+ /* Not strictly needed because at this point it already is a heap. */
+#if 0
+ std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+#endif
while (active_pixels.size()) {
std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
@@ -215,7 +217,8 @@ class TextureMarginMap {
}
}
- /* Walk over the map and for margin pixels follow the direction stored in the bottom 3
+ /**
+ * Walk over the map and for margin pixels follow the direction stored in the bottom 3
* bits back to the polygon.
* Then look up the pixel from the next polygon.
*/
@@ -324,10 +327,12 @@ class TextureMarginMap {
}
}
- /* Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well.
- * Because the Dijkstra is not vey exact in determining which polygon is the closest, the
+ /**
+ * Call lookup_pixel for the start_poly. If that fails, try the adjacent polygons as well.
+ * Because the Dijkstra is not very exact in determining which polygon is the closest, the
* polygon we need can be the one next to the one the Dijkstra map provides. To prevent missing
- * pixels also check the neighbouring polygons. */
+ * pixels also check the neighboring polygons.
+ */
bool lookup_pixel_polygon_neighbourhood(
float x, float y, uint32_t *r_start_poly, float *r_destx, float *r_desty, int *r_other_poly)
{
@@ -344,8 +349,8 @@ class TextureMarginMap {
float mindist = -1.f;
- /* Loop over all adjacent polyons and determine which edge is closest.
- * This could be optimized by only inspecting neigbours which are on the edge of an island.
+ /* Loop over all adjacent polygons and determine which edge is closest.
+ * This could be optimized by only inspecting neighbors which are on the edge of an island.
* But it seems fast enough for now and that would add a lot of complexity. */
for (int i = 0; i < totloop; i++) {
int otherloop = loop_adjacency_map_[i + loopstart];
@@ -370,10 +375,12 @@ class TextureMarginMap {
return mindist >= 0.f;
}
- /* Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon.
+ /**
+ * Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon.
* Then return the location of the equivalent pixel in the other polygon.
* Returns true if a new pixel location was found, false if it wasn't, which can happen if the
- * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. */
+ * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon.
+ */
bool lookup_pixel(float x,
float y,
int src_poly,
@@ -568,7 +575,9 @@ static void generate_margin(ImBuf *ibuf,
vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f);
}
- BLI_assert(lt->poly < 0x80000000); // NOTE: we need the top bit for the dijkstra distance map
+ /* NOTE: we need the top bit for the dijkstra distance map. */
+ BLI_assert(lt->poly < 0x80000000);
+
map.rasterize_tri(vec[0], vec[1], vec[2], lt->poly, draw_new_mask ? mask : nullptr);
}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index be29dcfcd0c..dd8966acfd8 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -297,7 +297,7 @@ static void seq_add_sound_av_sync(Main *bmain, Scene *scene, Sequence *seq, SeqL
const double av_stream_offset = sound_stream.start - load_data->r_video_stream_start;
const int frame_offset = av_stream_offset * FPS;
- /* Set subframe offset. */
+ /* Set sub-frame offset. */
seq->sound->offset_time = ((double)frame_offset / FPS) - av_stream_offset;
SEQ_transform_translate_sequence(scene, seq, frame_offset);
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 1478712c3cd..723c572c4da 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -874,18 +874,16 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
duration_lib_override_recursive_resync_seconds);
}
- if (bf_reports->count.linked_proxies != 0 ||
- bf_reports->count.proxies_to_lib_overrides_success != 0 ||
+ if (bf_reports->count.proxies_to_lib_overrides_success != 0 ||
bf_reports->count.proxies_to_lib_overrides_failures != 0) {
- BKE_reportf(bf_reports->reports,
- RPT_WARNING,
- "Proxies are deprecated (%d proxies were automatically converted to library "
- "overrides, %d proxies could not be converted and %d linked proxies were kept "
- "untouched). If you need to keep proxies for the time being, please disable the "
- "`Proxy to Override Auto Conversion` in Experimental user preferences",
- bf_reports->count.proxies_to_lib_overrides_success,
- bf_reports->count.proxies_to_lib_overrides_failures,
- bf_reports->count.linked_proxies);
+ BKE_reportf(
+ bf_reports->reports,
+ RPT_WARNING,
+ "Proxies have been removed from Blender (%d proxies were automatically converted "
+ "to library overrides, %d proxies could not be converted and were cleared). "
+ "Please also consider re-saving any library .blend file with the newest Blender version.",
+ bf_reports->count.proxies_to_lib_overrides_success,
+ bf_reports->count.proxies_to_lib_overrides_failures);
}
if (bf_reports->count.sequence_strips_skipped != 0) {
diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py
index ebc35c1178c..705a026e441 100644
--- a/tests/python/bl_keymap_validate.py
+++ b/tests/python/bl_keymap_validate.py
@@ -162,7 +162,7 @@ def keymap_data_clean(keyconfig_data: typing.List, *, relaxed: bool) -> None:
item_prop.pop("properties")
# Needed so: `{"properties": ()}` matches `None` as there is no meaningful difference.
- # Wruting `None` makes the most sense when explicitly written, however generated properties
+ # Writing `None` makes the most sense when explicitly written, however generated properties
# might be empty and it's not worth adding checks in the generation logic to use `None`
# just to satisfy this check.
if not item_prop: