diff options
author | Hans Goudey <h.goudey@me.com> | 2021-04-10 06:01:57 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-04-10 06:02:04 +0300 |
commit | da3004a0f998033dd3d192b0beba97cf9bd7a19b (patch) | |
tree | 9b0448b5de214d4cb201bd2cbe76034661e2e45e | |
parent | ec090a215beb56e4cfb48e76456a8de2d86f1da2 (diff) | |
parent | 0515ff70ec09694d11e36e90212119574c65ada9 (diff) |
Merge branch 'master' into geometry-nodes-curve-support
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 ¶ms) 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 ¶ms) 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 ¶ms) 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; } } |