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:
authorHans Goudey <h.goudey@me.com>2021-04-10 06:01:57 +0300
committerHans Goudey <h.goudey@me.com>2021-04-10 06:02:04 +0300
commitda3004a0f998033dd3d192b0beba97cf9bd7a19b (patch)
tree9b0448b5de214d4cb201bd2cbe76034661e2e45e
parentec090a215beb56e4cfb48e76456a8de2d86f1da2 (diff)
parent0515ff70ec09694d11e36e90212119574c65ada9 (diff)
Merge branch 'master' into geometry-nodes-curve-support
-rw-r--r--build_files/cmake/Modules/FindOSL.cmake2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm5
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h35
-rw-r--r--readme.rst2
m---------release/scripts/addons0
-rw-r--r--release/scripts/startup/bl_operators/node.py5
-rw-r--r--release/scripts/startup/bl_ui/space_node.py3
-rw-r--r--source/blender/blenkernel/BKE_curve.h5
-rw-r--r--source/blender/blenkernel/intern/anim_data.c6
-rw-r--r--source/blender/blenkernel/intern/anim_path.c39
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c20
-rw-r--r--source/blender/blenkernel/intern/collection.c11
-rw-r--r--source/blender/blenkernel/intern/displist.cc2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c17
-rw-r--r--source/blender/blenkernel/intern/gpencil.c3
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c6
-rw-r--r--source/blender/blenkernel/intern/lib_override.c14
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc9
-rw-r--r--source/blender/blenkernel/intern/nla.c12
-rw-r--r--source/blender/blenkernel/intern/node.cc10
-rw-r--r--source/blender/blenkernel/intern/object.c21
-rw-r--r--source/blender/blenkernel/intern/screen.c13
-rw-r--r--source/blender/blenkernel/intern/text.c3
-rw-r--r--source/blender/blenlib/BLI_iterator.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc3
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc2
-rw-r--r--source/blender/draw/intern/shaders/common_pointcloud_lib.glsl2
-rw-r--r--source/blender/editors/animation/keyframing.c3
-rw-r--r--source/blender/editors/space_nla/nla_draw.c6
-rw-r--r--source/blender/editors/space_node/node_add.c3
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt14
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc133
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh51
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc73
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.hh48
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh115
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh84
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.cc (renamed from source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh)16
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh65
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc447
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh94
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc453
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc (renamed from source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc)55
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh42
-rw-r--r--source/blender/editors/transform/transform_generics.c69
-rw-r--r--source/blender/editors/undo/ed_undo.c24
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc4
-rw-r--r--source/blender/gpu/tests/gpu_testing.cc2
-rw-r--r--source/blender/makesdna/DNA_space_types.h23
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c36
-rw-r--r--source/blender/makesrna/intern/rna_scene.c1
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc4
-rw-r--r--source/blender/nodes/NOD_geometry.h3
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc183
58 files changed, 1532 insertions, 803 deletions
diff --git a/build_files/cmake/Modules/FindOSL.cmake b/build_files/cmake/Modules/FindOSL.cmake
index d184215ac9f..b21c7ad50a3 100644
--- a/build_files/cmake/Modules/FindOSL.cmake
+++ b/build_files/cmake/Modules/FindOSL.cmake
@@ -75,7 +75,7 @@ FIND_PATH(OSL_SHADER_DIR
/usr/share/OSL/
/usr/include/OSL/
PATH_SUFFIXES
- shaders
+ share/OSL/shaders
)
# handle the QUIETLY and REQUIRED arguments and set OSL_FOUND to TRUE if
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 6a5a088d163..1776b0d5ce0 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -1131,7 +1131,8 @@ GHOST_TSuccess GHOST_WindowCocoa::hasCursorShape(GHOST_TStandardCursor shape)
return success;
}
-/** Reverse the bits in a GHOST_TUns8
+/* Reverse the bits in a GHOST_TUns8 */
+#if 0
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
{
ch= ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
@@ -1139,7 +1140,7 @@ static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
ch= ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
return ch;
}
-*/
+#endif
/** Reverse the bits in a GHOST_TUns16 */
static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 3d51c04f929..89cb68010fb 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -57,9 +57,11 @@
extern "C" {
#endif
-/** Returns the length of the allocated memory segment pointed at
+/**
+ * Returns the length of the allocated memory segment pointed at
* by vmemh. If the pointer was not previously allocated by this
- * module, the result is undefined.*/
+ * module, the result is undefined.
+ */
extern size_t (*MEM_allocN_len)(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
/**
@@ -103,7 +105,8 @@ extern void *(*MEM_recallocN_id)(void *vmemh,
/**
* Allocate a block of memory of size len, with tag name str. The
* memory is cleared. The name must be static, because only a
- * pointer to it is stored ! */
+ * pointer to it is stored!
+ */
extern void *(*MEM_callocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2);
@@ -143,12 +146,15 @@ extern void *(*MEM_mallocN_aligned)(size_t len,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
-/** Print a list of the names and sizes of all allocated memory
- * blocks. as a python dict for easy investigation */
+/**
+ * Print a list of the names and sizes of all allocated memory
+ * blocks. as a python dict for easy investigation.
+ */
extern void (*MEM_printmemlist_pydict)(void);
-/** Print a list of the names and sizes of all allocated memory
- * blocks. */
+/**
+ * Print a list of the names and sizes of all allocated memory blocks.
+ */
extern void (*MEM_printmemlist)(void);
/** calls the function on all allocated memory blocks. */
@@ -163,7 +169,8 @@ extern void (*MEM_set_error_callback)(void (*func)(const char *));
/**
* Are the start/end block markers still correct ?
*
- * \retval true for correct memory, false for corrupted memory. */
+ * \retval true for correct memory, false for corrupted memory.
+ */
extern bool (*MEM_consistency_check)(void);
/** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */
@@ -209,8 +216,10 @@ extern size_t (*MEM_get_peak_memory)(void) ATTR_WARN_UNUSED_RESULT;
extern const char *(*MEM_name_ptr)(void *vmemh);
#endif
-/** This should be called as early as possible in the program. When it has been called, information
- * about memory leaks will be printed on exit. */
+/**
+ * This should be called as early as possible in the program. When it has been called, information
+ * about memory leaks will be printed on exit.
+ */
void MEM_init_memleak_detection(void);
/**
@@ -219,9 +228,11 @@ void MEM_init_memleak_detection(void);
*/
void MEM_use_memleak_detection(bool enabled);
-/** When this has been called and memory leaks have been detected, the process will have an exit
+/**
+ * When this has been called and memory leaks have been detected, the process will have an exit
* code that indicates failure. This can be used for when checking for memory leaks with automated
- * tests. */
+ * tests.
+ */
void MEM_enable_fail_on_memleak(void);
/* Switch allocator to fast mode, with less tracking.
diff --git a/readme.rst b/readme.rst
index aadc766b22f..6d03d004be4 100644
--- a/readme.rst
+++ b/readme.rst
@@ -35,7 +35,7 @@ Development
License
-------
-Blender as a whole is licensed under the GNU Public License, Version 3.
+Blender as a whole is licensed under the GNU General Public License, Version 3.
Individual files may have a different, but compatible license.
See `blender.org/about/license <https://www.blender.org/about/license>`__ for details.
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject ebe76f3a7ba96b3881567def29b7e2527e018e9
+Subproject bcd08a9506d33bdd7358201031b04d041ef22d9
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 7884a7287b7..63da9c6af55 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -20,7 +20,6 @@
from __future__ import annotations
import bpy
-import nodeitems_utils
from bpy.types import (
Operator,
PropertyGroup,
@@ -195,6 +194,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
# Create an enum list from node items
def node_enum_items(self, context):
+ import nodeitems_utils
+
enum_items = NODE_OT_add_search._enum_item_hack
enum_items.clear()
@@ -210,6 +211,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
# Look up the item based on index
def find_node_item(self, context):
+ import nodeitems_utils
+
node_item = int(self.node_item)
for index, item in enumerate(nodeitems_utils.node_items_iter(context)):
if index == node_item:
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index d8cfa9dcc82..89ce742b81e 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -18,7 +18,6 @@
# <pep8 compliant>
import bpy
-import nodeitems_utils
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
@@ -225,6 +224,8 @@ class NODE_MT_add(bpy.types.Menu):
bl_translation_context = i18n_contexts.operator_default
def draw(self, context):
+ import nodeitems_utils
+
layout = self.layout
layout.operator_context = 'INVOKE_DEFAULT'
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 26c9bef7d6c..59922bf934c 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -55,9 +55,8 @@ typedef struct CurveCache {
* The first entry is the length between point 0 and 1 while the last is the
* total length of the curve.
*
- * Used by 'BKE_where_on_path'.
- */
- float *anim_path_accum_length;
+ * Used by #BKE_where_on_path. */
+ const float *anim_path_accum_length;
} CurveCache;
/* Definitions needed for shape keys */
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 633d6202222..447ed8fbe14 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -287,8 +287,10 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
!BLI_listbase_is_empty(&adt->overrides);
}
-/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure). */
+/**
+ * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure).
+ */
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
{
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c
index 58ab5609fce..78884ed907e 100644
--- a/source/blender/blenkernel/intern/anim_path.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -65,11 +65,11 @@ int BKE_anim_path_get_array_size(const CurveCache *curve_cache)
float BKE_anim_path_get_length(const CurveCache *curve_cache)
{
- int seg_size = BKE_anim_path_get_array_size(curve_cache);
+ const int seg_size = BKE_anim_path_get_array_size(curve_cache);
return curve_cache->anim_path_accum_length[seg_size - 1];
}
-void BKE_anim_path_calc_data(struct Object *ob)
+void BKE_anim_path_calc_data(Object *ob)
{
if (ob == NULL || ob->type != OB_CURVE) {
return;
@@ -87,7 +87,7 @@ void BKE_anim_path_calc_data(struct Object *ob)
/* Free old data. */
if (ob->runtime.curve_cache->anim_path_accum_length) {
- MEM_freeN(ob->runtime.curve_cache->anim_path_accum_length);
+ MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
/* We assume that we have at least two points.
@@ -96,11 +96,10 @@ void BKE_anim_path_calc_data(struct Object *ob)
*/
BLI_assert(bl->nr > 1);
- int seg_size = get_bevlist_seg_array_size(bl);
+ const int seg_size = get_bevlist_seg_array_size(bl);
+ float *len_data = (float *)MEM_mallocN(sizeof(float) * seg_size, "calcpathdist");
+ ob->runtime.curve_cache->anim_path_accum_length = len_data;
- ob->runtime.curve_cache->anim_path_accum_length = (float *)MEM_mallocN(sizeof(float) * seg_size,
- "calcpathdist");
- float *len_data = ob->runtime.curve_cache->anim_path_accum_length;
BevPoint *bp_arr = bl->bevpoints;
float prev_len = 0.0f;
for (int i = 0; i < bl->nr - 1; i++) {
@@ -115,20 +114,20 @@ void BKE_anim_path_calc_data(struct Object *ob)
}
static void get_curve_points_from_idx(const int idx,
- BevList *bl,
- bool is_cyclic,
- BevPoint **r_p0,
- BevPoint **r_p1,
- BevPoint **r_p2,
- BevPoint **r_p3)
+ const BevList *bl,
+ const bool is_cyclic,
+ BevPoint const **r_p0,
+ BevPoint const **r_p1,
+ BevPoint const **r_p2,
+ BevPoint const **r_p3)
{
BLI_assert(idx >= 0);
BLI_assert(idx < bl->nr - 1 || (is_cyclic && idx < bl->nr));
BLI_assert(bl->nr > 1);
- BevPoint *bp_arr = bl->bevpoints;
+ const BevPoint *bp_arr = bl->bevpoints;
- /* First segement. */
+ /* First segment. */
if (idx == 0) {
*r_p1 = &bp_arr[0];
if (is_cyclic) {
@@ -273,11 +272,11 @@ bool BKE_where_on_path(const Object *ob,
}
/* The curve points for this ctime value. */
- BevPoint *p0, *p1, *p2, *p3;
+ const BevPoint *p0, *p1, *p2, *p3;
float frac;
const int seg_size = get_bevlist_seg_array_size(bl);
- float *accum_len_arr = ob->runtime.curve_cache->anim_path_accum_length;
+ const float *accum_len_arr = ob->runtime.curve_cache->anim_path_accum_length;
const float goal_len = ctime * accum_len_arr[seg_size - 1];
/* Are we simply trying to get the start/end point? */
@@ -296,7 +295,7 @@ bool BKE_where_on_path(const Object *ob,
else {
/* Do binary search to get the correct segment. */
int idx;
- bool found_idx = binary_search_anim_path(accum_len_arr, seg_size, goal_len, &idx, &frac);
+ const bool found_idx = binary_search_anim_path(accum_len_arr, seg_size, goal_len, &idx, &frac);
if (UNLIKELY(!found_idx)) {
return false;
@@ -349,8 +348,8 @@ bool BKE_where_on_path(const Object *ob,
/* Clamp weights to 0-1 as we don't want to extrapolate other values than position. */
clamp_v4(w, 0.0f, 1.0f);
- r_vec[3] = /* Tilt, should not be needed since we have quat still used */
- w[0] * p0->tilt + w[1] * p1->tilt + w[2] * p2->tilt + w[3] * p3->tilt;
+ /* Tilt, should not be needed since we have quat still used. */
+ r_vec[3] = w[0] * p0->tilt + w[1] * p1->tilt + w[2] * p2->tilt + w[3] * p3->tilt;
if (r_quat) {
float totfac, q1[4], q2[4];
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 9a890fd02be..6f4af6f655d 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1605,8 +1605,9 @@ static bool nla_combine_get_inverted_strip_value(const int mix_mode,
}
}
-/** Accumulate quaternion channels for Combine mode according to influence.
- * \returns blended_value = lower_values @ strip_values^infl
+/**
+ * Accumulate quaternion channels for Combine mode according to influence.
+ * \returns `blended_value = lower_values @ strip_values^infl`
*/
static void nla_combine_quaternion(const float lower_values[4],
const float strip_values[4],
@@ -2094,8 +2095,10 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
/* ---------------------- */
-/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
- * and includes a workaround for when user is not editing in place. */
+/**
+ * Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
+ * and includes a workaround for when user is not editing in place.
+ */
static void animsys_create_tweak_strip(const AnimData *adt,
const bool keyframing_to_strip,
NlaStrip *r_tweak_strip)
@@ -2210,8 +2213,10 @@ static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
return true;
}
-/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no
- * strips evaluated) nor NLA interference (ensure NLA not soloing). */
+/**
+ * Check for special case of non-pushed action being evaluated with no NLA influence (off and no
+ * strips evaluated) nor NLA interference (ensure NLA not soloing).
+ */
static bool is_action_track_evaluated_without_nla(const AnimData *adt,
const bool any_strip_evaluated)
{
@@ -2491,7 +2496,8 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
}
}
-/** Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
+/**
+ * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
* to the given \a upper_blendmode and \a upper_influence.
*
* For \a upper_snapshot, blending limited to values in the \a blend_domain. For Replace blendmode,
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 8e4633cbe15..89bb7b36406 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -2033,8 +2033,9 @@ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
data->scene = scene;
+
+ BLI_ITERATOR_INIT(iter);
iter->data = data;
- iter->valid = true;
scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
BLI_assert(data->tot != 0);
@@ -2079,6 +2080,8 @@ typedef struct SceneObjectsIteratorData {
static void scene_objects_iterator_begin(BLI_Iterator *iter, Scene *scene, GSet *visited_objects)
{
SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
+
+ BLI_ITERATOR_INIT(iter);
iter->data = data;
/* Lookup list to make sure that each object is only processed once. */
@@ -2165,11 +2168,13 @@ void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
}
}
-/** Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
+/**
+ * Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
* all collections of given `scene`.
*
* \note: This will include objects without a base currently (because they would belong to excluded
- * collections only e.g.). */
+ * collections only e.g.).
+ */
GSet *BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
{
BLI_Iterator iter;
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index b0ae727cf54..3f3ffee19be 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -1548,7 +1548,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
*/
if (!for_orco) {
if (ob->runtime.curve_cache->anim_path_accum_length) {
- MEM_freeN(ob->runtime.curve_cache->anim_path_accum_length);
+ MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
ob->runtime.curve_cache->anim_path_accum_length = NULL;
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 010ab09bb31..30d5a54b479 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -181,8 +181,10 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src)
}
}
-/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure). */
+/**
+ * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure).
+ */
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
{
ChannelDriver *driver = fcu->driver;
@@ -1508,7 +1510,8 @@ bool test_time_fcurve(FCurve *fcu)
/** \name F-Curve Calculations
* \{ */
-/* The length of each handle is not allowed to be more
+/**
+ * The length of each handle is not allowed to be more
* than the horizontal distance between (v1-v4).
* This is to prevent curve loops.
*
@@ -1555,9 +1558,13 @@ void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], con
}
}
-/** Find roots of cubic equation (c0 x³ + c1 x² + c2 x + c3)
+/**
+ .
+ * Find roots of cubic equation (c0 x³ + c1 x² + c2 x + c3)
* \return number of roots in `o`.
- * NOTE: it is up to the caller to allocate enough memory for `o`. */
+ *
+ * \note it is up to the caller to allocate enough memory for `o`.
+ */
static int solve_cubic(double c0, double c1, double c2, double c3, float *o)
{
double a, b, c, p, q, d, t, phi;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 47b9a92d4bd..9c84d155330 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -1293,7 +1293,8 @@ bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
return NULL;
}
-/** Get the appropriate gp-frame from a given layer
+/**
+ * Get the appropriate gp-frame from a given layer
* - this sets the layer's actframe var (if allowed to)
* - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
*
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 6f1896f055a..1f13f008464 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -616,7 +616,8 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
return remap_cfra;
}
-/** Get the current frame re-timed with time modifiers.
+/**
+ * Get the current frame re-timed with time modifiers.
* \param depsgraph: Current depsgraph.
* \param scene: Current scene
* \param ob: Grease pencil object
@@ -746,7 +747,8 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_gpencil_update_orig_pointers(ob_orig, ob);
}
-/** Calculate gpencil modifiers.
+/**
+ * Calculate gpencil modifiers.
* \param depsgraph: Current depsgraph
* \param scene: Current scene
* \param ob: Grease pencil object
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 150b9ee8868..e42fab70af4 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -218,10 +218,12 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
return local_id;
}
-/** Check if given ID has some override rules that actually indicate the user edited it.
+/**
+ * Check if given ID has some override rules that actually indicate the user edited it.
*
- * TODO: This could be simplified by storing a flag in IDOverrideLibrary during the diffing
- * process? */
+ * TODO: This could be simplified by storing a flag in #IDOverrideLibrary during the diffing
+ * process?
+ */
bool BKE_lib_override_library_is_user_edited(struct ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
@@ -2407,8 +2409,10 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
return storage_id;
}
-/** Restore given ID modified by \a BKE_lib_override_library_operations_store_start, to its
- * original state. */
+/**
+ * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
+ * original state.
+ */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index ecf70c779e5..cfb1c192afe 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -231,7 +231,8 @@ const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
return medge;
}
-/** Convert all of the meshes in `meshes` to an `IMesh` and return that.
+/**
+ * Convert all of the meshes in `meshes` to an `IMesh` and return that.
* All of the coordinates are transformed into the local space of the
* first Mesh. To do this transformation, we also need the transformation
* obmats corresponding to the Meshes, so they are in the `obmats` argument.
@@ -638,7 +639,8 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
}
}
-/** Make sure that there are custom data layers in the target mesh
+/**
+ * Make sure that there are custom data layers in the target mesh
* corresponding to all target layers in all of the operands after the first.
* (The target should already have layers for those in the first operand mesh).
* Edges done separately -- will have to be done later, after edges are made.
@@ -673,7 +675,8 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
}
}
-/** Convert the output IMesh im to a Blender Mesh,
+/**
+ * Convert the output IMesh im to a Blender Mesh,
* using the information in mim to get all the attributes right.
*/
static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 63b14c30b3c..97aa6b07ab0 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -434,8 +434,10 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
-/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure). */
+/**
+ * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure).
+ */
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
{
BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
@@ -1380,8 +1382,10 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
}
}
-/** Recalculate the start and end frames for the strip to match the bounds of its action such that
- * the overall NLA animation result is unchanged. */
+/**
+ * Recalculate the start and end frames for the strip to match the bounds of its action such that
+ * the overall NLA animation result is unchanged.
+ */
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
{
float prev_actstart;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index a33c9dbefd9..3a589ce614b 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -1314,8 +1314,8 @@ void nodeUnregisterType(bNodeType *nt)
bool nodeTypeUndefined(bNode *node)
{
return (node->typeinfo == &NodeTypeUndefined) ||
- (node->type == NODE_GROUP && node->id && ID_IS_LINKED(node->id) &&
- (node->id->tag & LIB_TAG_MISSING));
+ ((node->type == NODE_GROUP || node->type == NODE_CUSTOM_GROUP) && node->id &&
+ ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING));
}
GHashIterator *nodeTypeGetIterator(void)
@@ -3096,10 +3096,12 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-/** Get address of potential nodetree pointer of given ID.
+/**
+ * Get address of potential node-tree pointer of given ID.
*
* \warning Using this function directly is potentially dangerous, if you don't know or are not
- * sure, please use `ntreeFromID()` instead. */
+ * sure, please use `ntreeFromID()` instead.
+ */
bNodeTree **BKE_ntree_ptr_from_id(ID *id)
{
switch (GS(id->name)) {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 002071fac30..d96942e47e7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -312,7 +312,7 @@ static void object_free_data(ID *id)
if (ob->runtime.curve_cache) {
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
if (ob->runtime.curve_cache->anim_path_accum_length) {
- MEM_freeN(ob->runtime.curve_cache->anim_path_accum_length);
+ MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
MEM_freeN(ob->runtime.curve_cache);
ob->runtime.curve_cache = NULL;
@@ -1189,7 +1189,7 @@ void BKE_object_free_curve_cache(Object *ob)
BKE_displist_free(&ob->runtime.curve_cache->disp);
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
if (ob->runtime.curve_cache->anim_path_accum_length) {
- MEM_freeN(ob->runtime.curve_cache->anim_path_accum_length);
+ MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
}
BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
MEM_freeN(ob->runtime.curve_cache);
@@ -1359,8 +1359,9 @@ static bool object_modifier_type_copy_check(ModifierType md_type)
return !ELEM(md_type, eModifierType_Hook, eModifierType_Collision);
}
-/** Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings
- * ID), or add one, and return valid `psys` from `ob_dst`.
+/**
+ * Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings ID),
+ * or add one, and return valid `psys` from `ob_dst`.
*
* \note Order handling is fairly weak here. This code assumes that it is called **before** the
* modifier using the psys is actually copied, and that this copied modifier will be added at the
@@ -1392,7 +1393,8 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
return psys_dst;
}
-/** Copy a single modifier.
+/**
+ * Copy a single modifier.
*
* \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
* `BKE_object_modifier_stack_copy` instead.
@@ -1400,7 +1402,8 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
* \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
* systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
* which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
- * more than once, this function should preferably be called in stack order. */
+ * more than once, this function should preferably be called in stack order.
+ */
bool BKE_object_copy_modifier(
Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
{
@@ -1500,10 +1503,12 @@ bool BKE_object_copy_modifier(
return true;
}
-/** Copy a single GPencil modifier.
+/**
+ * Copy a single GPencil modifier.
*
* \note **Do not** use this function to copy a whole modifier stack. Use
- * `BKE_object_modifier_stack_copy` instead. */
+ * `BKE_object_modifier_stack_copy` instead.
+ */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
{
BLI_assert(ob_dst->type == OB_GPENCIL);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 9617ef68a7d..d5540a3cfd3 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1350,6 +1350,13 @@ static void write_area(BlendWriter *writer, ScrArea *area)
}
else if (sl->spacetype == SPACE_SPREADSHEET) {
BLO_write_struct(writer, SpaceSpreadsheet, sl);
+
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
+ BLO_write_struct(writer, SpreadsheetColumn, column);
+ BLO_write_struct(writer, SpreadsheetColumnID, column->id);
+ BLO_write_string(writer, column->id->name);
+ }
}
}
}
@@ -1702,6 +1709,12 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
sspreadsheet->runtime = NULL;
+
+ BLO_read_list(reader, &sspreadsheet->columns);
+ LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
+ BLO_read_data_address(reader, &column->id);
+ BLO_read_data_address(reader, &column->id->name);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 43d587861a5..944e01321ce 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -523,7 +523,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
return ta;
}
-/** Load a text file.
+/**
+ * Load a text file.
*
* \note Text data-blocks have no user by default, only the 'real user' flag.
*/
diff --git a/source/blender/blenlib/BLI_iterator.h b/source/blender/blenlib/BLI_iterator.h
index c1cd1c21dac..198e42f340d 100644
--- a/source/blender/blenlib/BLI_iterator.h
+++ b/source/blender/blenlib/BLI_iterator.h
@@ -34,13 +34,19 @@ typedef struct BLI_Iterator {
typedef void (*IteratorCb)(BLI_Iterator *iter);
typedef void (*IteratorBeginCb)(BLI_Iterator *iter, void *data_in);
+#define BLI_ITERATOR_INIT(iter) \
+ { \
+ (iter)->skip = false; \
+ (iter)->valid = true; \
+ } \
+ ((void)0)
+
#define ITER_BEGIN(callback_begin, callback_next, callback_end, _data_in, _type, _instance) \
{ \
_type _instance; \
IteratorCb callback_end_func = callback_end; \
BLI_Iterator iter_macro; \
- iter_macro.skip = false; \
- iter_macro.valid = true; \
+ BLI_ITERATOR_INIT(&iter_macro); \
for (callback_begin(&iter_macro, (_data_in)); iter_macro.valid; callback_next(&iter_macro)) { \
if (iter_macro.skip) { \
iter_macro.skip = false; \
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index fec33a04e6f..487ef6427af 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -38,7 +38,8 @@ namespace blender::meshintersect {
#ifdef WITH_GMP
-/** Make a #blender::meshintersect::Mesh from #BMesh bm.
+/**
+ * Make a #blender::meshintersect::Mesh from #BMesh bm.
* We are given a triangulation of it from the caller via #looptris,
* which are looptris_tot triples of loops that together tessellate
* the faces of bm.
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 872eb66e789..3f58f52670e 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -608,4 +608,8 @@ endif()
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ target_compile_options(bf_compositor PRIVATE "-Wsuggest-override")
+endif()
+
add_dependencies(bf_compositor smaa_areatex_header)
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 56bc2dc947f..648ef7519d1 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -451,6 +451,8 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
m_file_index++;
+ std::cout << "Writing compositor debug to: " << filename << "\n";
+
FILE *fp = BLI_fopen(filename, "wb");
fputs(str, fp);
fclose(fp);
diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
index f007a8c2322..74b989441a2 100644
--- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
@@ -12,7 +12,7 @@ in vec3 nor;
mat3 pointcloud_get_facing_matrix(vec3 p)
{
mat3 facing_mat;
- facing_mat[2] = normalize(ViewMatrixInverse[3].xyz - p);
+ facing_mat[2] = cameraVec(p);
facing_mat[1] = normalize(cross(ViewMatrixInverse[0].xyz, facing_mat[2]));
facing_mat[0] = cross(facing_mat[1], facing_mat[2]);
return facing_mat;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 9cbb799082c..f229d48b4eb 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -483,7 +483,8 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
return i;
}
-/** Update the FCurve to allow insertion of `bezt` without modifying the curve shape.
+/**
+ * Update the FCurve to allow insertion of `bezt` without modifying the curve shape.
*
* Checks whether it is necessary to apply Bezier subdivision due to involvement of non-auto
* handles. If necessary, changes `bezt` handles from Auto to Aligned.
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index eea81e425c2..8bf6f2698e0 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -408,8 +408,10 @@ static uint nla_draw_use_dashed_outlines(const float color[4], bool muted)
return shdr_pos;
}
-/** This check only accounts for the track's disabled flag and whether the strip is being tweaked.
- * It does not account for muting or soloing. */
+/**
+ * This check only accounts for the track's disabled flag and whether the strip is being tweaked.
+ * It does not account for muting or soloing.
+ */
static bool is_nlastrip_enabled(AnimData *adt, NlaTrack *nlt, NlaStrip *strip)
{
/** This shouldn't happen. If passed NULL, then just treat strip as enabled. */
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index c4fe9e9e531..82a315366dc 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -41,6 +41,8 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
@@ -473,6 +475,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
snode_dag_update(C, snode);
ED_node_tag_update_nodetree(bmain, ntree, object_node);
+ DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 1343ab8d851..5aa708b10c0 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -33,15 +33,21 @@ set(INC
set(SRC
space_spreadsheet.cc
- spreadsheet_column_layout.cc
+ spreadsheet_column.cc
+ spreadsheet_data_source.cc
+ spreadsheet_data_source_geometry.cc
spreadsheet_draw.cc
- spreadsheet_from_geometry.cc
+ spreadsheet_layout.cc
spreadsheet_ops.cc
- spreadsheet_column_layout.hh
+ spreadsheet_cell_value.hh
+ spreadsheet_column.hh
+ spreadsheet_data_source.hh
+ spreadsheet_data_source_geometry.hh
+ spreadsheet_column_values.hh
spreadsheet_draw.hh
- spreadsheet_from_geometry.hh
spreadsheet_intern.hh
+ spreadsheet_layout.hh
)
set(LIB
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 403e6cd6206..d34b625293c 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -17,7 +17,6 @@
#include <cstring>
#include "BLI_listbase.h"
-#include "BLI_resource_scope.hh"
#include "BKE_screen.h"
@@ -41,12 +40,15 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "BLF_api.h"
+
#include "spreadsheet_intern.hh"
-#include "spreadsheet_column_layout.hh"
-#include "spreadsheet_from_geometry.hh"
+#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
+#include "spreadsheet_layout.hh"
+using namespace blender;
using namespace blender::ed::spreadsheet;
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -85,6 +87,10 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
MEM_SAFE_FREE(sspreadsheet->runtime);
+
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
+ spreadsheet_column_free(column);
+ }
}
static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
@@ -94,6 +100,10 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
sizeof(SpaceSpreadsheet_Runtime), __func__);
}
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
+ spreadsheet_column_free(column);
+ }
+ BLI_listbase_clear(&sspreadsheet->columns);
}
static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
@@ -102,6 +112,12 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime);
+ BLI_listbase_clear(&sspreadsheet_new->columns);
+ LISTBASE_FOREACH (SpreadsheetColumn *, src_column, &sspreadsheet_old->columns) {
+ SpreadsheetColumn *new_column = spreadsheet_column_copy(src_column);
+ BLI_addtail(&sspreadsheet_new->columns, new_column);
+ }
+
return (SpaceLink *)sspreadsheet_new;
}
@@ -133,47 +149,122 @@ static ID *get_used_id(const bContext *C)
return (ID *)active_object;
}
-class FallbackSpreadsheetDrawer : public SpreadsheetDrawer {
-};
-
-static void gather_spreadsheet_columns(const bContext *C,
- SpreadsheetColumnLayout &column_layout,
- blender::ResourceScope &scope)
+static std::unique_ptr<DataSource> get_data_source(const bContext *C)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ID *used_id = get_used_id(C);
if (used_id == nullptr) {
- return;
+ return {};
}
const ID_Type id_type = GS(used_id->name);
if (id_type != ID_OB) {
- return;
+ return {};
}
Object *object_orig = (Object *)used_id;
if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) {
- return;
+ return {};
}
Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig);
if (object_eval == nullptr) {
- return;
+ return {};
}
- return spreadsheet_columns_from_geometry(C, object_eval, column_layout, scope);
+ return data_source_from_geometry(C, object_eval);
+}
+
+static float get_column_width(const ColumnValues &values)
+{
+ if (values.default_width > 0) {
+ return values.default_width * UI_UNIT_X;
+ }
+ const int fontid = UI_style_get()->widget.uifont_id;
+ const int widget_points = UI_style_get_dpi()->widget.points;
+ BLF_size(fontid, widget_points * U.pixelsize, U.dpi);
+ const StringRefNull name = values.name();
+ const float name_width = BLF_width(fontid, name.data(), name.size());
+ return std::max<float>(name_width + UI_UNIT_X, 3 * UI_UNIT_X);
+}
+
+static int get_index_column_width(const int tot_rows)
+{
+ const int fontid = UI_style_get()->widget.uifont_id;
+ BLF_size(fontid, UI_style_get_dpi()->widget.points * U.pixelsize, U.dpi);
+ return std::to_string(std::max(0, tot_rows - 1)).size() * BLF_width(fontid, "0", 1) +
+ UI_UNIT_X * 0.75;
+}
+
+static void update_visible_columns(ListBase &columns, DataSource &data_source)
+{
+ Set<SpreadsheetColumnID> used_ids;
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &columns) {
+ std::unique_ptr<ColumnValues> values = data_source.get_column_values(*column->id);
+ /* Remove columns that don't exist anymore. */
+ if (!values) {
+ BLI_remlink(&columns, column);
+ spreadsheet_column_free(column);
+ continue;
+ }
+
+ used_ids.add(*column->id);
+ }
+
+ data_source.foreach_default_column_ids([&](const SpreadsheetColumnID &column_id) {
+ std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
+ if (values) {
+ if (used_ids.add(column_id)) {
+ SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id);
+ SpreadsheetColumn *new_column = spreadsheet_column_new(new_id);
+ BLI_addtail(&columns, new_column);
+ }
+ }
+ });
}
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- blender::ResourceScope scope;
- SpreadsheetColumnLayout column_layout;
- gather_spreadsheet_columns(C, column_layout, scope);
+ std::unique_ptr<DataSource> data_source = get_data_source(C);
+ if (!data_source) {
+ data_source = std::make_unique<DataSource>();
+ }
+
+ update_visible_columns(sspreadsheet->columns, *data_source);
+
+ SpreadsheetLayout spreadsheet_layout;
+ ResourceScope scope;
+
+ LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
+ std::unique_ptr<ColumnValues> values_ptr = data_source->get_column_values(*column->id);
+ /* Should have been removed before if it does not exist anymore. */
+ BLI_assert(values_ptr);
+ const ColumnValues *values = scope.add(std::move(values_ptr), __func__);
+ const int width = get_column_width(*values);
+ spreadsheet_layout.columns.append({values, width});
+ }
+
+ const int tot_rows = data_source->tot_rows();
+ spreadsheet_layout.index_column_width = get_index_column_width(tot_rows);
+ spreadsheet_layout.row_indices = IndexRange(tot_rows).as_span();
+
+ if (const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ data_source.get())) {
+ Object *object_eval = geometry_data_source->object_eval();
+ Object *object_orig = DEG_get_original_object(object_eval);
+ if (object_orig->type == OB_MESH) {
+ if (object_orig->mode == OB_MODE_EDIT) {
+ if (sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY) {
+ spreadsheet_layout.row_indices = geometry_data_source->get_selected_element_indices();
+ }
+ }
+ }
+ }
- sspreadsheet->runtime->visible_rows = column_layout.row_indices.size();
- sspreadsheet->runtime->tot_columns = column_layout.columns.size();
- sspreadsheet->runtime->tot_rows = column_layout.tot_rows;
+ sspreadsheet->runtime->tot_columns = spreadsheet_layout.columns.size();
+ sspreadsheet->runtime->tot_rows = tot_rows;
+ sspreadsheet->runtime->visible_rows = spreadsheet_layout.row_indices.size();
- std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_column_layout(column_layout);
+ std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_layout(spreadsheet_layout);
draw_spreadsheet_in_region(C, region, *drawer);
/* Tag footer for redraw, because the main region updates data for the footer. */
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
new file mode 100644
index 00000000000..0627cff7abc
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+struct Object;
+struct Collection;
+
+namespace blender::ed::spreadsheet {
+
+struct ObjectCellValue {
+ const Object *object;
+};
+
+struct CollectionCellValue {
+ const Collection *collection;
+};
+
+/**
+ * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
+ * decouple the drawing of individual cells from the code that generates the data to be displayed.
+ */
+class CellValue {
+ public:
+ /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
+ * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
+ * but it does not really matter too much currently. */
+
+ std::optional<int> value_int;
+ std::optional<float> value_float;
+ std::optional<bool> value_bool;
+ std::optional<ObjectCellValue> value_object;
+ std::optional<CollectionCellValue> value_collection;
+};
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
new file mode 100644
index 00000000000..6c573ce7238
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_hash.hh"
+#include "BLI_string.h"
+#include "BLI_string_ref.hh"
+
+#include "spreadsheet_column.hh"
+
+namespace blender::ed::spreadsheet {
+
+SpreadsheetColumnID *spreadsheet_column_id_new()
+{
+ SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
+ __func__);
+ return column_id;
+}
+
+SpreadsheetColumnID *spreadsheet_column_id_copy(const SpreadsheetColumnID *src_column_id)
+{
+ SpreadsheetColumnID *new_column_id = spreadsheet_column_id_new();
+ new_column_id->name = BLI_strdup(src_column_id->name);
+ new_column_id->index = src_column_id->index;
+ return new_column_id;
+}
+
+void spreadsheet_column_id_free(SpreadsheetColumnID *column_id)
+{
+ if (column_id->name != nullptr) {
+ MEM_freeN(column_id->name);
+ }
+ MEM_freeN(column_id);
+}
+
+SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
+{
+ SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn),
+ __func__);
+ column->id = column_id;
+ return column;
+}
+
+SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column)
+{
+ SpreadsheetColumnID *new_column_id = spreadsheet_column_id_copy(src_column->id);
+ SpreadsheetColumn *new_column = spreadsheet_column_new(new_column_id);
+ return new_column;
+}
+
+void spreadsheet_column_free(SpreadsheetColumn *column)
+{
+ spreadsheet_column_id_free(column->id);
+ MEM_freeN(column);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
new file mode 100644
index 00000000000..0f74ee0141a
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "DNA_space_types.h"
+
+#include "BLI_hash.hh"
+
+namespace blender {
+template<> struct DefaultHash<SpreadsheetColumnID> {
+ uint64_t operator()(const SpreadsheetColumnID &column_id) const
+ {
+ return get_default_hash_2(StringRef(column_id.name), column_id.index);
+ }
+};
+} // namespace blender
+
+inline bool operator==(const SpreadsheetColumnID &a, const SpreadsheetColumnID &b)
+{
+ using blender::StringRef;
+ return StringRef(a.name) == StringRef(b.name) && a.index == b.index;
+}
+
+namespace blender::ed::spreadsheet {
+
+SpreadsheetColumnID *spreadsheet_column_id_new();
+SpreadsheetColumnID *spreadsheet_column_id_copy(const SpreadsheetColumnID *src_column_id);
+void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
+
+SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
+SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
+void spreadsheet_column_free(SpreadsheetColumn *column);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh
deleted file mode 100644
index 611337df007..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.hh
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <optional>
-
-#include "spreadsheet_draw.hh"
-
-struct Object;
-struct Collection;
-
-namespace blender::ed::spreadsheet {
-
-struct ObjectCellValue {
- const Object *object;
-};
-
-struct CollectionCellValue {
- const Collection *collection;
-};
-
-/**
- * This is a small type that can hold the value of a cell in a spreadsheet. This type allows us to
- * decouple the drawing of individual cells from the code that generates the data to be displayed.
- */
-class CellValue {
- public:
- /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
- * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
- * but it does not really matter too much currently. */
-
- std::optional<int> value_int;
- std::optional<float> value_float;
- std::optional<bool> value_bool;
- std::optional<ObjectCellValue> value_object;
- std::optional<CollectionCellValue> value_collection;
-};
-
-/**
- * This represents a column in a spreadsheet. It has a name and provides a value for all the cells
- * in the column.
- */
-class SpreadsheetColumn {
- protected:
- std::string name_;
-
- public:
- SpreadsheetColumn(std::string name) : name_(std::move(name))
- {
- }
-
- virtual ~SpreadsheetColumn() = default;
-
- virtual void get_value(int index, CellValue &r_cell_value) const = 0;
-
- StringRefNull name() const
- {
- return name_;
- }
-
- /* The default width of newly created columns, in UI units. */
- float default_width = 0.0f;
-};
-
-/* Utility class for the function below. */
-template<typename GetValueF> class LambdaSpreadsheetColumn : public SpreadsheetColumn {
- private:
- GetValueF get_value_;
-
- public:
- LambdaSpreadsheetColumn(std::string name, GetValueF get_value)
- : SpreadsheetColumn(std::move(name)), get_value_(std::move(get_value))
- {
- }
-
- void get_value(int index, CellValue &r_cell_value) const final
- {
- get_value_(index, r_cell_value);
- }
-};
-
-/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
-template<typename GetValueF>
-std::unique_ptr<SpreadsheetColumn> spreadsheet_column_from_function(std::string name,
- GetValueF get_value)
-{
- return std::make_unique<LambdaSpreadsheetColumn<GetValueF>>(std::move(name),
- std::move(get_value));
-}
-
-/* This contains information required to create a spreadsheet drawer from columns. */
-struct SpreadsheetColumnLayout {
- Vector<const SpreadsheetColumn *> columns;
- Span<int64_t> row_indices;
- int tot_rows = 0;
-};
-
-std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_column_layout(
- const SpreadsheetColumnLayout &column_layout);
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
new file mode 100644
index 00000000000..58a2776e0fc
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+
+#include "spreadsheet_cell_value.hh"
+
+namespace blender::ed::spreadsheet {
+
+/**
+ * This represents a column in a spreadsheet. It has a name and provides a value for all the cells
+ * in the column.
+ */
+class ColumnValues {
+ protected:
+ std::string name_;
+ int size_;
+
+ public:
+ ColumnValues(std::string name, const int size) : name_(std::move(name)), size_(size)
+ {
+ }
+
+ virtual ~ColumnValues() = default;
+
+ virtual void get_value(int index, CellValue &r_cell_value) const = 0;
+
+ StringRefNull name() const
+ {
+ return name_;
+ }
+
+ int size() const
+ {
+ return size_;
+ }
+
+ /* The default width of newly created columns, in UI units. */
+ float default_width = 0.0f;
+};
+
+/* Utility class for the function below. */
+template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
+ private:
+ GetValueF get_value_;
+
+ public:
+ LambdaColumnValues(std::string name, int size, GetValueF get_value)
+ : ColumnValues(std::move(name), size), get_value_(std::move(get_value))
+ {
+ }
+
+ void get_value(int index, CellValue &r_cell_value) const final
+ {
+ get_value_(index, r_cell_value);
+ }
+};
+
+/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
+template<typename GetValueF>
+std::unique_ptr<ColumnValues> column_values_from_function(std::string name,
+ int size,
+ GetValueF get_value)
+{
+ return std::make_unique<LambdaColumnValues<GetValueF>>(
+ std::move(name), size, std::move(get_value));
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.cc
index ff45b8517d1..09b8c6b1b54 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.cc
@@ -14,21 +14,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#pragma once
-
-#include "BKE_geometry_set.hh"
-
-#include "BLI_resource_scope.hh"
-
-#include "spreadsheet_column_layout.hh"
-
-struct bContext;
+#include "spreadsheet_data_source.hh"
namespace blender::ed::spreadsheet {
-void spreadsheet_columns_from_geometry(const bContext *C,
- Object *object_eval,
- SpreadsheetColumnLayout &column_layout,
- ResourceScope &scope);
+/* Provide a "key function" for the linker. */
+DataSource::~DataSource() = default;
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
new file mode 100644
index 00000000000..e012fae0edf
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+
+#include "spreadsheet_column.hh"
+#include "spreadsheet_column_values.hh"
+
+namespace blender::ed::spreadsheet {
+
+/**
+ * This class is subclassed to implement different data sources for the spreadsheet. A data source
+ * provides the information that should be displayed. It is not concerned with how data is layed
+ * out in the spreadsheet editor exactly.
+ */
+class DataSource {
+ public:
+ virtual ~DataSource();
+
+ /**
+ * Calls the callback with all the column ids that should be displayed as long as the user does
+ * not manually add or remove columns. The column id can be stack allocated. Therefore, the
+ * callback should not keep a reference to it (and copy it instead).
+ */
+ virtual void foreach_default_column_ids(FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+ {
+ UNUSED_VARS(fn);
+ }
+
+ /**
+ * Returns the column values the given column id. If no data exists for this id, null is
+ * returned.
+ */
+ virtual std::unique_ptr<ColumnValues> get_column_values(
+ const SpreadsheetColumnID &column_id) const
+ {
+ UNUSED_VARS(column_id);
+ return {};
+ }
+
+ /**
+ * Returns the number of rows in columns returned by #get_column_values.
+ */
+ virtual int tot_rows() const
+ {
+ return 0;
+ }
+};
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
new file mode 100644
index 00000000000..6716faaf552
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -0,0 +1,447 @@
+/*
+ * 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.
+ */
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+
+#include "DNA_ID.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "bmesh.h"
+
+#include "spreadsheet_data_source_geometry.hh"
+#include "spreadsheet_intern.hh"
+
+namespace blender::ed::spreadsheet {
+
+void GeometryDataSource::foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+{
+ component_->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != domain_) {
+ return true;
+ }
+ SpreadsheetColumnID column_id;
+ column_id.name = (char *)name.c_str();
+ if (meta_data.data_type == CD_PROP_FLOAT3) {
+ for (const int i : {0, 1, 2}) {
+ column_id.index = i;
+ fn(column_id);
+ }
+ }
+ else if (meta_data.data_type == CD_PROP_FLOAT2) {
+ for (const int i : {0, 1}) {
+ column_id.index = i;
+ fn(column_id);
+ }
+ }
+ else if (meta_data.data_type == CD_PROP_COLOR) {
+ for (const int i : {0, 1, 2, 3}) {
+ column_id.index = i;
+ fn(column_id);
+ }
+ }
+ else {
+ column_id.index = -1;
+ fn(column_id);
+ }
+ return true;
+ });
+}
+
+std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
+ const SpreadsheetColumnID &column_id) const
+{
+ std::lock_guard lock{mutex_};
+
+ bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name);
+ if (!attribute_ptr) {
+ return {};
+ }
+ const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__);
+ if (attribute->domain() != domain_) {
+ return {};
+ }
+ int domain_size = attribute->size();
+ switch (attribute->custom_data_type()) {
+ case CD_PROP_FLOAT:
+ return column_values_from_function(
+ column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ float value;
+ attribute->get(index, &value);
+ r_cell_value.value_float = value;
+ });
+ case CD_PROP_INT32:
+ return column_values_from_function(
+ column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ int value;
+ attribute->get(index, &value);
+ r_cell_value.value_int = value;
+ });
+ case CD_PROP_BOOL:
+ return column_values_from_function(
+ column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ bool value;
+ attribute->get(index, &value);
+ r_cell_value.value_bool = value;
+ });
+ case CD_PROP_FLOAT2: {
+ if (column_id.index < 0 || column_id.index > 1) {
+ return {};
+ }
+ const std::array<const char *, 2> suffixes = {" X", " Y"};
+ const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
+ return column_values_from_function(
+ name,
+ domain_size,
+ [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ float2 value;
+ attribute->get(index, &value);
+ r_cell_value.value_float = value[axis];
+ });
+ }
+ case CD_PROP_FLOAT3: {
+ if (column_id.index < 0 || column_id.index > 2) {
+ return {};
+ }
+ const std::array<const char *, 3> suffixes = {" X", " Y", " Z"};
+ const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
+ return column_values_from_function(
+ name,
+ domain_size,
+ [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ float3 value;
+ attribute->get(index, &value);
+ r_cell_value.value_float = value[axis];
+ });
+ }
+ case CD_PROP_COLOR: {
+ if (column_id.index < 0 || column_id.index > 3) {
+ return {};
+ }
+ const std::array<const char *, 4> suffixes = {" R", " G", " B", " A"};
+ const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
+ return column_values_from_function(
+ name,
+ domain_size,
+ [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ Color4f value;
+ attribute->get(index, &value);
+ r_cell_value.value_float = value[axis];
+ });
+ }
+ default:
+ break;
+ }
+ return {};
+}
+
+int GeometryDataSource::tot_rows() const
+{
+ return component_->attribute_domain_size(domain_);
+}
+
+using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
+
+static void get_selected_vertex_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_vertex_indices)
+{
+ for (const int i : IndexRange(mesh.totvert)) {
+ if (is_vertex_selected_fn(i)) {
+ r_vertex_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_corner_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_corner_indices)
+{
+ for (const int i : IndexRange(mesh.totloop)) {
+ const MLoop &loop = mesh.mloop[i];
+ if (is_vertex_selected_fn(loop.v)) {
+ r_corner_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_face_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_face_indices)
+{
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ bool is_selected = true;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!is_vertex_selected_fn(loop.v)) {
+ is_selected = false;
+ break;
+ }
+ }
+ if (is_selected) {
+ r_face_indices.append(poly_index);
+ }
+ }
+}
+
+static void get_selected_edge_indices(const Mesh &mesh,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_edge_indices)
+{
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+ if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) {
+ r_edge_indices.append(i);
+ }
+ }
+}
+
+static void get_selected_indices_on_domain(const Mesh &mesh,
+ const AttributeDomain domain,
+ const IsVertexSelectedFn is_vertex_selected_fn,
+ Vector<int64_t> &r_indices)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_FACE:
+ return get_selected_face_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_CORNER:
+ return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices);
+ case ATTR_DOMAIN_EDGE:
+ return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices);
+ default:
+ return;
+ }
+}
+
+Span<int64_t> GeometryDataSource::get_selected_element_indices() const
+{
+ std::lock_guard lock{mutex_};
+
+ BLI_assert(object_eval_->mode == OB_MODE_EDIT);
+ BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
+ Object *object_orig = DEG_get_original_object(object_eval_);
+ Vector<int64_t> &indices = scope_.construct<Vector<int64_t>>(__func__);
+ const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
+ const Mesh *mesh_eval = mesh_component->get_for_read();
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ BMesh *bm = mesh_orig->edit_mesh->bm;
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
+ if (orig_indices != nullptr) {
+ /* Use CD_ORIGINDEX layer if it exists. */
+ auto is_vertex_selected = [&](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ };
+ get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
+ }
+ else if (mesh_eval->totvert == bm->totvert) {
+ /* Use a simple heuristic to match original vertices to evaluated ones. */
+ auto is_vertex_selected = [&](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ };
+ get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
+ }
+
+ return indices;
+}
+
+void InstancesDataSource::foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &)> fn) const
+{
+ SpreadsheetColumnID column_id;
+ column_id.index = -1;
+ column_id.name = (char *)"Name";
+ fn(column_id);
+ for (const char *name : {"Position", "Rotation", "Scale"}) {
+ for (const int i : {0, 1, 2}) {
+ column_id.name = (char *)name;
+ column_id.index = i;
+ fn(column_id);
+ }
+ }
+}
+
+std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
+ const SpreadsheetColumnID &column_id) const
+{
+ const std::array<const char *, 3> suffixes = {" X", " Y", " Z"};
+ const int size = this->tot_rows();
+ if (STREQ(column_id.name, "Name")) {
+ Span<InstancedData> instance_data = component_->instanced_data();
+ std::unique_ptr<ColumnValues> values = column_values_from_function(
+ "Name", size, [instance_data](int index, CellValue &r_cell_value) {
+ const InstancedData &data = instance_data[index];
+ if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
+ if (data.data.object != nullptr) {
+ r_cell_value.value_object = ObjectCellValue{data.data.object};
+ }
+ }
+ else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
+ if (data.data.collection != nullptr) {
+ r_cell_value.value_collection = CollectionCellValue{data.data.collection};
+ }
+ }
+ });
+ values->default_width = 8.0f;
+ return values;
+ }
+ if (column_id.index < 0 || column_id.index > 2) {
+ return {};
+ }
+ Span<float4x4> transforms = component_->transforms();
+ if (STREQ(column_id.name, "Position")) {
+ std::string name = StringRef("Position") + suffixes[column_id.index];
+ return column_values_from_function(
+ name, size, [transforms, axis = column_id.index](int index, CellValue &r_cell_value) {
+ r_cell_value.value_float = transforms[index].translation()[axis];
+ });
+ }
+ if (STREQ(column_id.name, "Rotation")) {
+ std::string name = StringRef("Rotation") + suffixes[column_id.index];
+ return column_values_from_function(
+ name, size, [transforms, axis = column_id.index](int index, CellValue &r_cell_value) {
+ r_cell_value.value_float = transforms[index].to_euler()[axis];
+ });
+ }
+ if (STREQ(column_id.name, "Scale")) {
+ std::string name = StringRef("Scale") + suffixes[column_id.index];
+ return column_values_from_function(
+ name, size, [transforms, axis = column_id.index](int index, CellValue &r_cell_value) {
+ r_cell_value.value_float = transforms[index].scale()[axis];
+ });
+ }
+ return {};
+}
+
+int InstancesDataSource::tot_rows() const
+{
+ return component_->instances_amount();
+}
+
+static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
+ Object *object_eval,
+ const GeometryComponentType used_component_type)
+{
+ GeometrySet geometry_set;
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
+ Object *object_orig = DEG_get_original_object(object_eval);
+ if (ELEM(object_orig->type, OB_MESH, OB_CURVE, OB_POINTCLOUD)) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ if (object_orig->mode == OB_MODE_EDIT) {
+ Mesh *mesh = (Mesh *)object_orig->data;
+ BMEditMesh *em = mesh->edit_mesh;
+ if (em != nullptr) {
+ Mesh *new_mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
+ /* This is a potentially heavy operation to do on every redraw. The best solution here is
+ * to display the data directly from the bmesh without a conversion, which can be
+ * implemented a bit later. */
+ BM_mesh_bm_to_me_for_eval(em->bm, new_mesh, nullptr);
+ mesh_component.replace(new_mesh, GeometryOwnershipType::Owned);
+ }
+ }
+ else {
+ Mesh *mesh = (Mesh *)object_orig->data;
+ mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ }
+ mesh_component.copy_vertex_group_names_from_object(*object_orig);
+ }
+ else if (object_orig->type == OB_POINTCLOUD) {
+ PointCloud *pointcloud = (PointCloud *)object_orig->data;
+ PointCloudComponent &pointcloud_component =
+ geometry_set.get_component_for_write<PointCloudComponent>();
+ pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
+ }
+ }
+ else {
+ if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
+ if (mesh == nullptr) {
+ return geometry_set;
+ }
+ BKE_mesh_wrapper_ensure_mdata(mesh);
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ mesh_component.copy_vertex_group_names_from_object(*object_eval);
+ }
+ else {
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
+ if (object_eval->runtime.geometry_set_preview != nullptr) {
+ geometry_set = *object_eval->runtime.geometry_set_preview;
+ }
+ }
+ else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
+ if (object_eval->runtime.geometry_set_eval != nullptr) {
+ geometry_set = *object_eval->runtime.geometry_set_eval;
+ }
+ }
+ }
+ }
+ return geometry_set;
+}
+
+static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
+ return (GeometryComponentType)sspreadsheet->geometry_component_type;
+ }
+ if (object_eval->type == OB_POINTCLOUD) {
+ return GEO_COMPONENT_TYPE_POINT_CLOUD;
+ }
+ return GEO_COMPONENT_TYPE_MESH;
+}
+
+std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
+ const GeometryComponentType component_type = get_display_component_type(C, object_eval);
+ GeometrySet geometry_set = get_display_geometry_set(sspreadsheet, object_eval, component_type);
+
+ if (!geometry_set.has(component_type)) {
+ return {};
+ }
+
+ if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
+ return std::make_unique<InstancesDataSource>(geometry_set);
+ }
+ return std::make_unique<GeometryDataSource>(object_eval, geometry_set, component_type, domain);
+}
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
new file mode 100644
index 00000000000..273d39f27bf
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include "BLI_resource_scope.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "spreadsheet_data_source.hh"
+
+struct bContext;
+
+namespace blender::ed::spreadsheet {
+
+class GeometryDataSource : public DataSource {
+ private:
+ Object *object_eval_;
+ const GeometrySet geometry_set_;
+ const GeometryComponent *component_;
+ AttributeDomain domain_;
+
+ /* Some data is computed on the fly only when it is requested. Computing it does not change the
+ * logical state of this data source. Therefore, the corresponding methods are const and need to
+ * be protected with a mutex. */
+ mutable std::mutex mutex_;
+ mutable ResourceScope scope_;
+
+ public:
+ GeometryDataSource(Object *object_eval,
+ GeometrySet geometry_set,
+ const GeometryComponentType component_type,
+ const AttributeDomain domain)
+ : object_eval_(object_eval),
+ geometry_set_(std::move(geometry_set)),
+ component_(geometry_set_.get_component_for_read(component_type)),
+ domain_(domain)
+ {
+ }
+
+ Object *object_eval() const
+ {
+ return object_eval_;
+ }
+
+ Span<int64_t> get_selected_element_indices() const;
+
+ void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+
+ std::unique_ptr<ColumnValues> get_column_values(
+ const SpreadsheetColumnID &column_id) const override;
+
+ int tot_rows() const override;
+};
+
+class InstancesDataSource : public DataSource {
+ const GeometrySet geometry_set_;
+ const InstancesComponent *component_;
+
+ public:
+ InstancesDataSource(GeometrySet geometry_set)
+ : geometry_set_(std::move(geometry_set)),
+ component_(geometry_set_.get_component_for_read<InstancesComponent>())
+ {
+ }
+
+ void foreach_default_column_ids(
+ FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;
+
+ std::unique_ptr<ColumnValues> get_column_values(
+ const SpreadsheetColumnID &column_id) const override;
+
+ int tot_rows() const override;
+};
+
+std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc
deleted file mode 100644
index f16e9365b80..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * 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.
- */
-
-#include "BKE_context.h"
-#include "BKE_editmesh.h"
-#include "BKE_lib_id.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_wrapper.h"
-#include "BKE_modifier.h"
-
-#include "DNA_ID.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_space_types.h"
-#include "DNA_userdef_types.h"
-
-#include "DEG_depsgraph_query.h"
-
-#include "bmesh.h"
-
-#include "spreadsheet_from_geometry.hh"
-#include "spreadsheet_intern.hh"
-
-namespace blender::ed::spreadsheet {
-
-using blender::bke::ReadAttribute;
-using blender::bke::ReadAttributePtr;
-
-static void add_columns_for_instances(const InstancesComponent &instances_component,
- SpreadsheetColumnLayout &column_layout,
- ResourceScope &scope)
-{
- Span<InstancedData> instance_data = instances_component.instanced_data();
- Span<float4x4> transforms = instances_component.transforms();
-
- Vector<std::unique_ptr<SpreadsheetColumn>> &columns =
- scope.construct<Vector<std::unique_ptr<SpreadsheetColumn>>>("columns");
-
- columns.append(spreadsheet_column_from_function(
- "Name", [instance_data](int index, CellValue &r_cell_value) {
- const InstancedData &data = instance_data[index];
- if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
- if (data.data.object != nullptr) {
- r_cell_value.value_object = ObjectCellValue{data.data.object};
- }
- }
- else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
- if (data.data.collection != nullptr) {
- r_cell_value.value_collection = CollectionCellValue{data.data.collection};
- }
- }
- }));
-
- columns.last()->default_width = 8.0f;
-
- static std::array<char, 3> axis_char = {'X', 'Y', 'Z'};
- for (const int i : {0, 1, 2}) {
- std::string name = std::string("Position ") + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [transforms, i](int index, CellValue &r_cell_value) {
- r_cell_value.value_float = transforms[index].translation()[i];
- }));
- }
-
- for (const int i : {0, 1, 2}) {
- std::string name = std::string("Rotation ") + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [transforms, i](int index, CellValue &r_cell_value) {
- r_cell_value.value_float = transforms[index].to_euler()[i];
- }));
- }
-
- for (const int i : {0, 1, 2}) {
- std::string name = std::string("Scale ") + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [transforms, i](int index, CellValue &r_cell_value) {
- r_cell_value.value_float = transforms[index].scale()[i];
- }));
- }
-
- for (std::unique_ptr<SpreadsheetColumn> &column : columns) {
- column_layout.columns.append(column.get());
- }
-
- column_layout.row_indices = instance_data.index_range().as_span();
- column_layout.tot_rows = instances_component.instances_amount();
-}
-
-static Vector<std::string> get_sorted_attribute_names_to_display(
- const GeometryComponent &component, const AttributeDomain domain)
-{
- Vector<std::string> attribute_names;
- component.attribute_foreach(
- [&](const StringRef attribute_name, const AttributeMetaData &meta_data) {
- if (meta_data.domain == domain) {
- attribute_names.append(attribute_name);
- }
- return true;
- });
- std::sort(attribute_names.begin(),
- attribute_names.end(),
- [](const std::string &a, const std::string &b) {
- return BLI_strcasecmp_natural(a.c_str(), b.c_str()) < 0;
- });
- return attribute_names;
-}
-
-static void add_columns_for_attribute(const ReadAttribute *attribute,
- const StringRefNull attribute_name,
- Vector<std::unique_ptr<SpreadsheetColumn>> &columns)
-{
- const CustomDataType data_type = attribute->custom_data_type();
- switch (data_type) {
- case CD_PROP_FLOAT: {
- columns.append(spreadsheet_column_from_function(
- attribute_name, [attribute](int index, CellValue &r_cell_value) {
- float value;
- attribute->get(index, &value);
- r_cell_value.value_float = value;
- }));
- break;
- }
- case CD_PROP_FLOAT2: {
- static std::array<char, 2> axis_char = {'X', 'Y'};
- for (const int i : {0, 1}) {
- std::string name = attribute_name + " " + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [attribute, i](int index, CellValue &r_cell_value) {
- float2 value;
- attribute->get(index, &value);
- r_cell_value.value_float = value[i];
- }));
- }
- break;
- }
- case CD_PROP_FLOAT3: {
- static std::array<char, 3> axis_char = {'X', 'Y', 'Z'};
- for (const int i : {0, 1, 2}) {
- std::string name = attribute_name + " " + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [attribute, i](int index, CellValue &r_cell_value) {
- float3 value;
- attribute->get(index, &value);
- r_cell_value.value_float = value[i];
- }));
- }
- break;
- }
- case CD_PROP_COLOR: {
- static std::array<char, 4> axis_char = {'R', 'G', 'B', 'A'};
- for (const int i : {0, 1, 2, 3}) {
- std::string name = attribute_name + " " + axis_char[i];
- columns.append(spreadsheet_column_from_function(
- name, [attribute, i](int index, CellValue &r_cell_value) {
- Color4f value;
- attribute->get(index, &value);
- r_cell_value.value_float = value[i];
- }));
- }
- break;
- }
- case CD_PROP_INT32: {
- columns.append(spreadsheet_column_from_function(
- attribute_name, [attribute](int index, CellValue &r_cell_value) {
- int value;
- attribute->get(index, &value);
- r_cell_value.value_int = value;
- }));
- break;
- }
- case CD_PROP_BOOL: {
- columns.append(spreadsheet_column_from_function(
- attribute_name, [attribute](int index, CellValue &r_cell_value) {
- bool value;
- attribute->get(index, &value);
- r_cell_value.value_bool = value;
- }));
- break;
- }
- default:
- break;
- }
-}
-
-static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type)
-{
- GeometrySet geometry_set;
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
- Object *object_orig = DEG_get_original_object(object_eval);
- if (ELEM(object_orig->type, OB_MESH, OB_CURVE, OB_POINTCLOUD)) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- if (object_orig->mode == OB_MODE_EDIT) {
- Mesh *mesh = (Mesh *)object_orig->data;
- BMEditMesh *em = mesh->edit_mesh;
- if (em != nullptr) {
- Mesh *new_mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
- /* This is a potentially heavy operation to do on every redraw. The best solution here is
- * to display the data directly from the bmesh without a conversion, which can be
- * implemented a bit later. */
- BM_mesh_bm_to_me_for_eval(em->bm, new_mesh, nullptr);
- mesh_component.replace(new_mesh, GeometryOwnershipType::Owned);
- }
- }
- else {
- Mesh *mesh = (Mesh *)object_orig->data;
- mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
- }
- mesh_component.copy_vertex_group_names_from_object(*object_orig);
- }
- else if (object_orig->type == OB_POINTCLOUD) {
- PointCloud *pointcloud = (PointCloud *)object_orig->data;
- PointCloudComponent &pointcloud_component =
- geometry_set.get_component_for_write<PointCloudComponent>();
- pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
- }
- }
- else {
- if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
- Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
- if (mesh == nullptr) {
- return geometry_set;
- }
- BKE_mesh_wrapper_ensure_mdata(mesh);
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
- mesh_component.copy_vertex_group_names_from_object(*object_eval);
- }
- else {
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
- if (object_eval->runtime.geometry_set_preview != nullptr) {
- geometry_set = *object_eval->runtime.geometry_set_preview;
- }
- }
- else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
- if (object_eval->runtime.geometry_set_eval != nullptr) {
- geometry_set = *object_eval->runtime.geometry_set_eval;
- }
- }
- }
- }
- return geometry_set;
-}
-
-using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
-
-static void get_selected_vertex_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_vertex_indices)
-{
- for (const int i : IndexRange(mesh.totvert)) {
- if (is_vertex_selected_fn(i)) {
- r_vertex_indices.append(i);
- }
- }
-}
-
-static void get_selected_corner_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_corner_indices)
-{
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &loop = mesh.mloop[i];
- if (is_vertex_selected_fn(loop.v)) {
- r_corner_indices.append(i);
- }
- }
-}
-
-static void get_selected_face_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_face_indices)
-{
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- bool is_selected = true;
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (!is_vertex_selected_fn(loop.v)) {
- is_selected = false;
- break;
- }
- }
- if (is_selected) {
- r_face_indices.append(poly_index);
- }
- }
-}
-
-static void get_selected_edge_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_edge_indices)
-{
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[i];
- if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) {
- r_edge_indices.append(i);
- }
- }
-}
-
-static void get_selected_indices_on_domain(const Mesh &mesh,
- const AttributeDomain domain,
- const IsVertexSelectedFn is_vertex_selected_fn,
- Vector<int64_t> &r_indices)
-{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
- case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, r_indices);
- case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices);
- case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices);
- default:
- return;
- }
-}
-
-static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C,
- Object *object_eval,
- const MeshComponent *component,
- const AttributeDomain domain,
- ResourceScope &scope)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- const bool show_only_selected = sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY;
- if (object_eval->mode == OB_MODE_EDIT && show_only_selected) {
- Object *object_orig = DEG_get_original_object(object_eval);
- Vector<int64_t> &visible_rows = scope.construct<Vector<int64_t>>("visible rows");
- const Mesh *mesh_eval = component->get_for_read();
- Mesh *mesh_orig = (Mesh *)object_orig->data;
- BMesh *bm = mesh_orig->edit_mesh->bm;
- BM_mesh_elem_table_ensure(bm, BM_VERT);
-
- int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
- if (orig_indices != nullptr) {
- /* Use CD_ORIGINDEX layer if it exists. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows);
- }
- else if (mesh_eval->totvert == bm->totvert) {
- /* Use a simple heuristic to match original vertices to evaluated ones. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows);
- }
- /* This is safe, because the vector lives in the resource collector. */
- return visible_rows.as_span();
- }
- /* No filter is used. */
- const int domain_size = component->attribute_domain_size(domain);
- return IndexRange(domain_size).as_span();
-}
-
-static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
- return (GeometryComponentType)sspreadsheet->geometry_component_type;
- }
- if (object_eval->type == OB_POINTCLOUD) {
- return GEO_COMPONENT_TYPE_POINT_CLOUD;
- }
- return GEO_COMPONENT_TYPE_MESH;
-}
-
-void spreadsheet_columns_from_geometry(const bContext *C,
- Object *object_eval,
- SpreadsheetColumnLayout &column_layout,
- ResourceScope &scope)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
- const GeometryComponentType component_type = get_display_component_type(C, object_eval);
-
- /* Create a resource collector that owns stuff that needs to live until drawing is done. */
- GeometrySet &geometry_set = scope.add_value(
- get_display_geometry_set(sspreadsheet, object_eval, component_type), "geometry set");
-
- const GeometryComponent *component = geometry_set.get_component_for_read(component_type);
- if (component == nullptr) {
- return;
- }
- if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
- add_columns_for_instances(
- *static_cast<const InstancesComponent *>(component), column_layout, scope);
- return;
- }
-
- if (!component->attribute_domain_supported(domain)) {
- return;
- }
-
- Vector<std::string> attribute_names = get_sorted_attribute_names_to_display(*component, domain);
-
- Vector<std::unique_ptr<SpreadsheetColumn>> &columns =
- scope.construct<Vector<std::unique_ptr<SpreadsheetColumn>>>("columns");
-
- for (StringRefNull attribute_name : attribute_names) {
- ReadAttributePtr attribute_ptr = component->attribute_try_get_for_read(attribute_name);
- ReadAttribute &attribute = *attribute_ptr;
- scope.add(std::move(attribute_ptr), "attribute");
- add_columns_for_attribute(&attribute, attribute_name, columns);
- }
-
- for (std::unique_ptr<SpreadsheetColumn> &column : columns) {
- column_layout.columns.append(column.get());
- }
-
- /* The filter below only works for mesh vertices currently. */
- Span<int64_t> visible_rows;
- if (component_type == GEO_COMPONENT_TYPE_MESH) {
- visible_rows = filter_mesh_elements_by_selection(
- C, object_eval, static_cast<const MeshComponent *>(component), domain, scope);
- }
- else {
- visible_rows = IndexRange(component->attribute_domain_size(domain)).as_span();
- }
-
- const int domain_size = component->attribute_domain_size(domain);
- column_layout.row_indices = visible_rows;
- column_layout.tot_rows = domain_size;
-}
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 77c56c02d93..bca80cff773 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,7 +17,7 @@
#include <iomanip>
#include <sstream>
-#include "spreadsheet_column_layout.hh"
+#include "spreadsheet_layout.hh"
#include "DNA_userdef_types.h"
@@ -28,45 +28,22 @@
namespace blender::ed::spreadsheet {
-class ColumnLayoutDrawer : public SpreadsheetDrawer {
+class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
private:
- const SpreadsheetColumnLayout &column_layout_;
- Vector<int> column_widths_;
+ const SpreadsheetLayout &spreadsheet_layout_;
public:
- ColumnLayoutDrawer(const SpreadsheetColumnLayout &column_layout) : column_layout_(column_layout)
+ SpreadsheetLayoutDrawer(const SpreadsheetLayout &spreadsheet_layout)
+ : spreadsheet_layout_(spreadsheet_layout)
{
- tot_columns = column_layout.columns.size();
- tot_rows = column_layout.row_indices.size();
-
- const int fontid = UI_style_get()->widget.uifont_id;
- /* Use a consistent font size for the width calculation. */
- BLF_size(fontid, UI_style_get_dpi()->widget.points * U.pixelsize, U.dpi);
-
- /* The width of the index column depends on the maximum row index. */
- left_column_width = std::to_string(std::max(0, column_layout_.tot_rows - 1)).size() *
- BLF_width(fontid, "0", 1) +
- UI_UNIT_X * 0.75;
-
- /* The column widths depend on the column name widths. */
- const int minimum_column_width = 3 * UI_UNIT_X;
- const int header_name_padding = UI_UNIT_X;
- for (const SpreadsheetColumn *column : column_layout_.columns) {
- if (column->default_width == 0.0f) {
- StringRefNull name = column->name();
- const int name_width = BLF_width(fontid, name.data(), name.size());
- const int width = std::max(name_width + header_name_padding, minimum_column_width);
- column_widths_.append(width);
- }
- else {
- column_widths_.append(column->default_width * UI_UNIT_X);
- }
- }
+ tot_columns = spreadsheet_layout.columns.size();
+ tot_rows = spreadsheet_layout.row_indices.size();
+ left_column_width = spreadsheet_layout.index_column_width;
}
void draw_top_row_cell(int column_index, const CellDrawParams &params) const final
{
- const StringRefNull name = column_layout_.columns[column_index]->name();
+ const StringRefNull name = spreadsheet_layout_.columns[column_index].values->name();
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
@@ -89,7 +66,7 @@ class ColumnLayoutDrawer : public SpreadsheetDrawer {
void draw_left_column_cell(int row_index, const CellDrawParams &params) const final
{
- const int real_index = column_layout_.row_indices[row_index];
+ const int real_index = spreadsheet_layout_.row_indices[row_index];
std::string index_str = std::to_string(real_index);
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -113,8 +90,8 @@ class ColumnLayoutDrawer : public SpreadsheetDrawer {
void draw_content_cell(int row_index, int column_index, const CellDrawParams &params) const final
{
- const int real_index = column_layout_.row_indices[row_index];
- const SpreadsheetColumn &column = *column_layout_.columns[column_index];
+ const int real_index = spreadsheet_layout_.row_indices[row_index];
+ const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
CellValue cell_value;
column.get_value(real_index, cell_value);
@@ -224,14 +201,14 @@ class ColumnLayoutDrawer : public SpreadsheetDrawer {
int column_width(int column_index) const final
{
- return column_widths_[column_index];
+ return spreadsheet_layout_.columns[column_index].width;
}
};
-std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_column_layout(
- const SpreadsheetColumnLayout &column_layout)
+std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_layout(
+ const SpreadsheetLayout &spreadsheet_layout)
{
- return std::make_unique<ColumnLayoutDrawer>(column_layout);
+ return std::make_unique<SpreadsheetLayoutDrawer>(spreadsheet_layout);
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
new file mode 100644
index 00000000000..1768af6ae09
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "spreadsheet_column_values.hh"
+#include "spreadsheet_draw.hh"
+
+namespace blender::ed::spreadsheet {
+
+/* Layout information for a single column. */
+struct ColumnLayout {
+ const ColumnValues *values;
+ int width;
+};
+
+/* Layout information for the entire spreadsheet. */
+struct SpreadsheetLayout {
+ Vector<ColumnLayout> columns;
+ Span<int64_t> row_indices;
+ int index_column_width = 100;
+};
+
+std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_layout(
+ const SpreadsheetLayout &spreadsheet_layout);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index e43a3ff3635..c0c4b22da98 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -409,9 +409,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
short orient_types[3];
float custom_matrix[3][3];
- short orient_type_scene = V3D_ORIENT_GLOBAL;
- short orient_type_set = V3D_ORIENT_GLOBAL;
- short orient_type_matrix_set = -1;
+ int orient_type_scene = V3D_ORIENT_GLOBAL;
+ int orient_type_default = -1;
+ int orient_type_set = -1;
+ int orient_type_matrix_set = -1;
bool use_orient_axis = false;
@@ -424,7 +425,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
- short orient_type_default = orient_type_scene;
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ orient_type_set = RNA_property_enum_get(op->ptr, prop);
+ if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+ orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+ }
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
t->orient_axis = RNA_property_enum_get(op->ptr, prop);
@@ -435,52 +442,54 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
}
- if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
RNA_property_is_set(op->ptr, prop))) {
- orient_type_set = RNA_property_enum_get(op->ptr, prop);
- if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orient_type_set = V3D_ORIENT_GLOBAL;
+ RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
+
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
+ }
+ else if (orient_type_set == -1) {
+ orient_type_set = V3D_ORIENT_CUSTOM_MATRIX;
}
+ }
- /* Change the default orientation to be used when redoing. */
+ if (orient_type_set != -1) {
orient_type_default = orient_type_set;
}
+ else if (orient_type_matrix_set != -1) {
+ orient_type_default = orient_type_set = orient_type_matrix_set;
+ }
else if (t->con.mode & CON_APPLY) {
- orient_type_set = orient_type_scene;
+ orient_type_default = orient_type_set = orient_type_scene;
}
else {
- if (orient_type_set == orient_type_scene) {
- BLI_assert(orient_type_set == V3D_ORIENT_GLOBAL);
+ if (orient_type_scene == V3D_ORIENT_GLOBAL) {
orient_type_set = V3D_ORIENT_LOCAL;
}
+ else {
+ orient_type_set = V3D_ORIENT_GLOBAL;
+ }
if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) &&
(t->mode != TFM_ALIGN)) {
orient_type_default = V3D_ORIENT_VIEW;
}
- }
-
- if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
- RNA_property_is_set(op->ptr, prop))) {
- RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
-
- if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
- RNA_property_is_set(op->ptr, prop)) {
- orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
- }
else {
- orient_type_matrix_set = orient_type_set;
+ orient_type_default = orient_type_scene;
}
+ }
- if (orient_type_matrix_set == orient_type_set) {
- /* Constraints are forced to use the custom matrix when redoing. */
- orient_type_set = V3D_ORIENT_CUSTOM_MATRIX;
- }
+ BLI_assert(!ELEM(-1, orient_type_default, orient_type_set));
+ if (orient_type_matrix_set == orient_type_set) {
+ /* Constraints are forced to use the custom matrix when redoing. */
+ orient_type_set = V3D_ORIENT_CUSTOM_MATRIX;
}
- orient_types[0] = orient_type_default;
- orient_types[1] = orient_type_scene;
- orient_types[2] = orient_type_set;
+ orient_types[0] = (short)orient_type_default;
+ orient_types[1] = (short)orient_type_scene;
+ orient_types[2] = (short)orient_type_set;
for (int i = 0; i < 3; i++) {
/* For efficiency, avoid calculating the same orientation twice. */
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index b69f62a2875..7811509ab40 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -273,9 +273,11 @@ static void ed_undo_step_post(bContext *C,
}
}
-/** Undo or redo one step from current active one.
- * May undo or redo several steps at once only if the target step is a 'skipped' one.
- * The target step will be the one immediately before or after the active one. */
+/**
+ * Undo or redo one step from current active one.
+ * May undo or redo several steps at once only if the target step is a 'skipped' one.
+ * The target step will be the one immediately before or after the active one.
+ */
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
{
BLI_assert(ELEM(step, STEP_UNDO, STEP_REDO));
@@ -308,9 +310,11 @@ static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportLis
return OPERATOR_FINISHED;
}
-/** Undo the step matching given name.
- * May undo several steps at once.
- * The target step will be the one immediately before given named one. */
+/**
+ * Undo the step matching given name.
+ * May undo several steps at once.
+ * The target step will be the one immediately before given named one.
+ */
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
{
BLI_assert(undo_name != NULL);
@@ -354,9 +358,11 @@ static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *
return OPERATOR_FINISHED;
}
-/** Load the step matching given index in the stack.
- * May undo or redo several steps at once.
- * The target step will be the one indicated by the given index. */
+/**
+ * Load the step matching given index in the stack.
+ * May undo or redo several steps at once.
+ * The target step will be the one indicated by the given index.
+ */
static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
{
BLI_assert(undo_index >= 0);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 69a79e2f2ce..923426c21a6 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -381,6 +381,10 @@ endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ target_compile_options(bf_gpu PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>)
+endif()
+
if(WITH_GTESTS)
if(WITH_OPENGL_DRAW_TESTS)
set(TEST_SRC
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index 51cfcd20a6c..b65686165d9 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -290,7 +290,9 @@ void GLTexture::update_sub(
}
}
-/** This will create the mipmap images and populate them with filtered data from base level.
+/**
+ * This will create the mipmap images and populate them with filtered data from base level.
+ *
* WARNING: Depth textures are not populated but they have their mips correctly defined.
* WARNING: This resets the mipmap range.
*/
diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc
index c193a19ad9c..b9fc78dc084 100644
--- a/source/blender/gpu/tests/gpu_testing.cc
+++ b/source/blender/gpu/tests/gpu_testing.cc
@@ -15,7 +15,7 @@ void GPUTest::SetUp()
GHOST_GLSettings glSettings = {0};
ghost_system = GHOST_CreateSystem();
ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings);
- context = GPU_context_create(NULL);
+ context = GPU_context_create(nullptr);
GPU_init();
}
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 0ad66c63169..a90047b9daa 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1854,6 +1854,22 @@ typedef struct SpaceStatusBar {
/** \name Spreadsheet
* \{ */
+typedef struct SpreadsheetColumnID {
+ char *name;
+ int index;
+ char _pad[4];
+} SpreadsheetColumnID;
+
+typedef struct SpreadsheetColumn {
+ struct SpreadsheetColumn *next, *prev;
+ /**
+ * Identifies the data in the column.
+ * This is a pointer instead of a struct to make it easier if we want to "subclass"
+ * #SpreadsheetColumnID in the future for different kinds of ids.
+ */
+ SpreadsheetColumnID *id;
+} SpreadsheetColumn;
+
typedef struct SpaceSpreadsheet {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1863,6 +1879,9 @@ typedef struct SpaceSpreadsheet {
char _pad0[6];
/* End 'SpaceLink' header. */
+ /* List of #SpreadsheetColumn. */
+ ListBase columns;
+
struct ID *pinned_id;
/* eSpaceSpreadsheet_FilterFlag. */
@@ -1880,8 +1899,6 @@ typedef struct SpaceSpreadsheet {
SpaceSpreadsheet_Runtime *runtime;
} SpaceSpreadsheet;
-/** \} */
-
typedef enum eSpaceSpreadsheet_FilterFlag {
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
} eSpaceSpreadsheet_FilterFlag;
@@ -1892,6 +1909,8 @@ typedef enum eSpaceSpreadsheet_ObjectEvalState {
SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2,
} eSpaceSpreadsheet_Context;
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Space Defines (eSpace_Type)
* \{ */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 609b0d53a6d..b79381ac26f 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -497,6 +497,7 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_bo
# include "NOD_common.h"
# include "NOD_composite.h"
+# include "NOD_geometry.h"
# include "NOD_shader.h"
# include "NOD_socket.h"
@@ -3290,6 +3291,35 @@ static StructRNA *rna_NodeCustomGroup_register(Main *bmain,
return nt->rna_ext.srna;
}
+static StructRNA *rna_GeometryNodeCustomGroup_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ bNodeType *nt = rna_Node_register_base(
+ bmain, reports, &RNA_GeometryNodeCustomGroup, data, identifier, validate, call, free);
+
+ if (!nt) {
+ return NULL;
+ }
+
+ nt->group_update_func = node_group_update;
+ nt->type = NODE_CUSTOM_GROUP;
+
+ register_node_type_geo_custom_group(nt);
+
+ nodeRegisterType(nt);
+
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+
+ return nt->rna_ext.srna;
+}
+
+void register_node_type_geo_custom_group(bNodeType *ntype);
+
static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain,
ReportList *reports,
void *data,
@@ -11501,6 +11531,12 @@ void RNA_def_nodetree(BlenderRNA *brna)
"Custom Group",
"Base node type for custom registered node group types",
"rna_NodeCustomGroup_register");
+ def_custom_group(brna,
+ "GeometryNodeCustomGroup",
+ "GeometryNode",
+ "Geometry Custom Group",
+ "Custom Geometry Group Node for Python nodes",
+ "rna_GeometryNodeCustomGroup_register");
/* special socket types */
rna_def_cmp_output_file_slot_file(brna);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index cc7747959a4..1919c6544b2 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -778,7 +778,6 @@ static void rna_Scene_objects_begin(CollectionPropertyIterator *iter, PointerRNA
Scene *scene = (Scene *)ptr->data;
iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- ((BLI_Iterator *)iter->internal.custom)->valid = true;
BKE_scene_objects_iterator_begin(iter->internal.custom, (void *)scene);
iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 994047b714e..03f5e0d66af 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -136,7 +136,7 @@ static void find_used_ids_from_nodes(const bNodeTree &tree, Set<ID *> &ids)
addIdsUsedBySocket(&node->inputs, ids);
addIdsUsedBySocket(&node->outputs, ids);
- if (node->type == NODE_GROUP) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
const bNodeTree *group = (bNodeTree *)node->id;
if (group != nullptr && handled_groups.add(group)) {
find_used_ids_from_nodes(*group, ids);
@@ -173,7 +173,7 @@ static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Objec
add_collection_object_relations_recursive(ctx, *collection_instance);
}
}
- else {
+ else if (ELEM(object.type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
}
}
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 059da891315..67b9d807a44 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -20,11 +20,14 @@
extern "C" {
#endif
+#include "BKE_node.h"
+
extern struct bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
+void register_node_type_geo_custom_group(bNodeType *ntype);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_clamp(void);
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 84d56f1b27f..8b430ea1c48 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -528,7 +528,7 @@ inline bool NodeRef::is_reroute_node() const
inline bool NodeRef::is_group_node() const
{
- return bnode_->type == NODE_GROUP;
+ return bnode_->type == NODE_GROUP || bnode_->type == NODE_CUSTOM_GROUP;
}
inline bool NodeRef::is_group_input_node() const
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index 441ad6bdc13..e2bb7e9f939 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -43,3 +43,17 @@ void register_node_type_geo_group(void)
nodeRegisterType(&ntype);
}
+
+void register_node_type_geo_custom_group(bNodeType *ntype)
+{
+ /* These methods can be overridden but need a default implementation otherwise. */
+ if (ntype->poll == nullptr) {
+ ntype->poll = geo_node_poll_default;
+ }
+ if (ntype->insert_link == nullptr) {
+ ntype->insert_link = node_insert_link_default;
+ }
+ if (ntype->update_internal_links == nullptr) {
+ ntype->update_internal_links = node_update_internal_links_default;
+ }
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index 3b4ea3d1bdf..789323d8a53 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -23,6 +23,8 @@
#include "node_shader_util.h"
+#include "BLI_math_base_safe.h"
+
/* **************** Map Range ******************** */
static bNodeSocketTemplate sh_node_map_range_in[] = {
{SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
@@ -88,6 +90,20 @@ static int gpu_shader_map_range(GPUMaterial *mat,
return ret;
}
+static void map_range_signature(
+ blender::fn::MFSignatureBuilder *signature, bool use_steps)
+{
+ signature->single_input<float>("Value");
+ signature->single_input<float>("From Min");
+ signature->single_input<float>("From Max");
+ signature->single_input<float>("To Min");
+ signature->single_input<float>("To Max");
+ if (use_steps) {
+ signature->single_input<float>("Steps");
+ }
+ signature->single_output<float>("Result");
+}
+
class MapRangeFunction : public blender::fn::MultiFunction {
private:
bool clamp_;
@@ -102,12 +118,7 @@ class MapRangeFunction : public blender::fn::MultiFunction {
static blender::fn::MFSignature create_signature()
{
blender::fn::MFSignatureBuilder signature{"Map Range"};
- signature.single_input<float>("Value");
- signature.single_input<float>("From Min");
- signature.single_input<float>("From Max");
- signature.single_input<float>("To Min");
- signature.single_input<float>("To Max");
- signature.single_output<float>("Result");
+ map_range_signature(&signature, false);
return signature.build();
}
@@ -136,25 +147,163 @@ class MapRangeFunction : public blender::fn::MultiFunction {
}
};
+class MapRangeSteppedFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeSteppedFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Map Range Stepped"};
+ map_range_signature(&signature, true);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ const blender::VArray<float> &steps = params.readonly_single_input<float>(5, "Steps");
+ blender::MutableSpan<float> results = params.uninitialized_single_output<float>(6, "Result");
+
+ for (int64_t i : mask) {
+ float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = safe_divide(floorf(factor * (steps[i] + 1.0f)), steps[i]);
+ results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
+ clamp_f(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSmoothstepFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmoothstepFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
+ map_range_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
+
+ for (int64_t i : mask) {
+ float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = std::clamp(factor, 0.0f, 1.0f);
+ factor = (3.0f - 2.0f * factor) * (factor * factor);
+ results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
+ }
+ }
+};
+
+class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmootherstepFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
+ map_range_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
+
+ for (int64_t i : mask) {
+ float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = std::clamp(factor, 0.0f, 1.0f);
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ results[i] = to_min[i] + factor * (to_max[i] - to_min[i]);
+ }
+ }
+};
+
static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
bNode &bnode = builder.bnode();
bool clamp = bnode.custom1 != 0;
int interpolation_type = bnode.custom2;
- if (interpolation_type == NODE_MAP_RANGE_LINEAR) {
- static MapRangeFunction fn_with_clamp{true};
- static MapRangeFunction fn_without_clamp{false};
-
- if (clamp) {
- builder.set_matching_fn(fn_with_clamp);
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
}
- else {
- builder.set_matching_fn(fn_without_clamp);
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
}
- }
- else {
- builder.set_not_implemented();
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ builder.set_not_implemented();
+ break;
}
}