From 48c5129d1fcdaf53a281bf0359af85bd0185f038 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Apr 2021 12:34:26 +1000 Subject: Fix errors in Buffer.dimensions `setter` - Error accessing the length from a sequence. - Error comparing a boolean to -1. Issues introduced in 19360c2c1cf50c80b9720137b88db2c2f3626ddc --- source/blender/python/gpu/gpu_py_buffer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index 8ee11ff882c..e36e3b42617 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -81,7 +81,7 @@ static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj, } } else if (PySequence_Check(shape_obj)) { - Py_ssize_t shape_len = PySequence_Size(shape_obj); + shape_len = PySequence_Size(shape_obj); if (shape_len > MAX_DIMENSIONS) { PyErr_SetString(PyExc_AttributeError, "too many dimensions, max is " STRINGIFY(MAX_DIMENSIONS)); @@ -111,8 +111,6 @@ static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj, return false; } } - - *r_shape_len = shape_len; } else { PyErr_Format(PyExc_TypeError, @@ -398,7 +396,7 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args return NULL; } - if (pygpu_buffer_pyobj_as_shape(length_ob, shape, &shape_len) == -1) { + if (!pygpu_buffer_pyobj_as_shape(length_ob, shape, &shape_len)) { return NULL; } -- cgit v1.2.3 From 4554f27adf1e66f05de66e7d6f0a61025f28862b Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 22 Apr 2021 08:15:12 +0200 Subject: Fix T86682: Scene strip DOF not evaluated correctly Camera object used for rendering reffered to original not evaluated data. Use `DEG_get_evaluated_object()` to get evaluated camera. Reviewed By: sergey Differential Revision: https://developer.blender.org/D11039 --- source/blender/sequencer/intern/render.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 572fff0ad38..96c881c9c5f 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -1537,13 +1537,14 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, /* opengl offscreen render */ depsgraph = BKE_scene_ensure_depsgraph(context->bmain, scene, view_layer); BKE_scene_graph_update_for_newframe(depsgraph); + Object *camera_eval = DEG_get_evaluated_object(depsgraph, camera); ibuf = sequencer_view3d_fn( /* set for OpenGL render (NULL when scrubbing) */ depsgraph, scene, &context->scene->display.shading, context->scene->r.seq_prev_type, - camera, + camera_eval, width, height, IB_rect, -- cgit v1.2.3 From 6944521d7e3711e6f055e12427aec9d3618979ec Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 22 Apr 2021 08:16:16 +0200 Subject: Fix T87337: Text strip draws white outline Math for drawing font over byte buffer was incorrect. Effect can be seen when target buffer is fully black and transparent - this results in font color being effectively premultiplied, which causes problems when image is composited further. Use `blend_color_mix_byte()` and `blend_color_mix_float()` for blending. Reviewed By: sergey Differential Revision: https://developer.blender.org/D11035 --- source/blender/blenfont/intern/blf_font.c | 38 +++++++++++-------------------- 1 file changed, 13 insertions(+), 25 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index f83ee409187..b7c226ada1d 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -41,6 +41,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_color_blend.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_string_utf8.h" @@ -640,18 +641,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font, (size_t)buf_info->ch); float *fbuf = buf_info->fbuf + buf_ofs; - if (a >= 1.0f) { - fbuf[0] = b_col_float[0]; - fbuf[1] = b_col_float[1]; - fbuf[2] = b_col_float[2]; - fbuf[3] = 1.0f; - } - else { - fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a)); - fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a)); - fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a)); - fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */ - } + float font_pixel[4]; + font_pixel[0] = b_col_float[0] * a; + font_pixel[1] = b_col_float[1] * a; + font_pixel[2] = b_col_float[2] * a; + font_pixel[3] = a; + blend_color_mix_float(fbuf, fbuf, font_pixel); } } @@ -677,19 +672,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font, (size_t)buf_info->ch); unsigned char *cbuf = buf_info->cbuf + buf_ofs; - if (a >= 1.0f) { - cbuf[0] = b_col_char[0]; - cbuf[1] = b_col_char[1]; - cbuf[2] = b_col_char[2]; - cbuf[3] = 255; - } - else { - cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a))); - cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a))); - cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a))); - /* clamp to 255 */ - cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255); - } + uchar font_pixel[4]; + font_pixel[0] = b_col_char[0]; + font_pixel[1] = b_col_char[1]; + font_pixel[2] = b_col_char[2]; + font_pixel[3] = unit_float_to_uchar_clamp(a); + blend_color_mix_byte(cbuf, cbuf, font_pixel); } } -- cgit v1.2.3 From a43d644decb27a0cf00da92afee71439f6d60d53 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 22 Apr 2021 08:16:52 +0200 Subject: VSE: Fix movies are reloaded after invalidation When cache is strip is invalidated, movie file was reloaded even if it isn't necessary. This caused significant performance issues when strip is being dragged under playhead. This was caused by calling `SEQ_relations_sequence_free_anim()` and it was introduced as fix for T36124. When it is necessary to reload file because another API holds reference to ImBuf, do this explicitly besides cache invalidation. In `rna_ColorManagedColorspaceSettings_reload_update()` this was already done, so no change is needed there. Reviewed By: sergey Differential Revision: https://developer.blender.org/D11024 --- source/blender/sequencer/intern/strip_relations.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 1a2ff08bd08..1215cb78b56 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -114,7 +114,6 @@ static void sequence_invalidate_cache(Scene *scene, Editing *ed = scene->ed; if (invalidate_self) { - SEQ_relations_sequence_free_anim(seq); seq_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false); } -- cgit v1.2.3 From 00ec99050ea435cb255bb81437b381e5a42660af Mon Sep 17 00:00:00 2001 From: Falk David Date: Thu, 22 Apr 2021 15:25:41 +1000 Subject: Fix T85051: Add bisect distance as a parameter to the mirror modifier The `bisect_distance` in the mirror modifier was hard-coded to `0.001`. This would result in some unexpected behavior like vertices close to the mirror plane being deleted or merged. The fix now adds a parameter to the mirror modifier to expose the bisect distance to the user. The default is set to the previous hard-coded value to not "change" previous files. Ref D10201 --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/mesh_mirror.c | 2 +- source/blender/blenloader/intern/versioning_290.c | 13 +++++++++++++ source/blender/makesdna/DNA_modifier_defaults.h | 1 + source/blender/makesdna/DNA_modifier_types.h | 2 ++ source/blender/makesrna/intern/rna_modifier.c | 8 ++++++++ source/blender/modifiers/intern/MOD_mirror.c | 7 +++++++ 7 files changed, 33 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index b4506b1a03c..08aea043fc7 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 18 +#define BLENDER_FILE_SUBVERSION 19 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index a22b52d68d5..93a2e9058fa 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -51,7 +51,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) || (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z)); - const float bisect_distance = 0.001f; + const float bisect_distance = mmd->bisect_threshold; Mesh *result; BMesh *bm; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 916c4bf0cad..fe8e46e8928 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -2059,6 +2059,19 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Set default value for the new bisect_threshold parameter in the mirror modifier. */ + if (!MAIN_VERSION_ATLEAST(bmain, 293, 19)) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData *)md; + /* This was the previous hard-coded value. */ + mmd->bisect_threshold = 0.001f; + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index d8e48c51107..f6dac88051b 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -429,6 +429,7 @@ { \ .flag = MOD_MIR_AXIS_X | MOD_MIR_VGROUP, \ .tolerance = 0.001f, \ + .bisect_threshold = 0.001f, \ .uv_offset = {0.0f, 0.0f}, \ .uv_offset_copy = {0.0f, 0.0f}, \ .mirror_ob = NULL, \ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index ca6f1467d9c..c61e940190f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -368,6 +368,8 @@ typedef struct MirrorModifierData { short axis DNA_DEPRECATED; short flag; float tolerance; + float bisect_threshold; + char _pad[4]; float uv_offset[2]; float uv_offset_copy[2]; struct Object *mirror_ob; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 67335b81a31..e3fb443951f 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2226,6 +2226,14 @@ static void rna_def_modifier_mirror(BlenderRNA *brna) prop, "Merge Distance", "Distance within which mirrored vertices are merged"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "bisect_threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "bisect_threshold"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 0.01, 6); + RNA_def_property_ui_text( + prop, "Bisect Distance", "Distance from the bisect plane within which vertices are removed"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "mirror_object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "mirror_ob"); RNA_def_property_ui_text(prop, "Mirror Object", "Object to use as mirror"); diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index afe94d8dead..b800ce7f803 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -165,6 +165,13 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_mirror_merge")); uiItemR(sub, ptr, "merge_threshold", 0, "", ICON_NONE); + bool is_bisect_set[3]; + RNA_boolean_get_array(ptr, "use_bisect_axis", is_bisect_set); + + sub = uiLayoutRow(col, true); + uiLayoutSetActive(sub, is_bisect_set[0] || is_bisect_set[1] || is_bisect_set[2]); + uiItemR(sub, ptr, "bisect_threshold", 0, IFACE_("Bisect Distance"), ICON_NONE); + modifier_panel_end(layout, ptr); } -- cgit v1.2.3 From 7192ab614b49258cdbd70a9f020f3566a4e0c0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 20 Apr 2021 17:12:12 +0200 Subject: Animation: add "LocRotScaleCProp" keying set Add a keying set that includes location, rotation, scale, and custom properties. The keying set is intentionally not based on the "Whole Character" keying set. Instead, it is generic enough to be used in both object and pose animation, making it possible to quickly switch between animating characters and props without switching keying sets. This is, according to @rikkert, what the Blender Studio animators need 99.9% of the time. --- source/blender/editors/include/ED_keyframing.h | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 12d6f1fce54..179c9d5b30d 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -511,6 +511,7 @@ bool ED_autokeyframe_property(struct bContext *C, #define ANIM_KS_ROTATION_ID "Rotation" #define ANIM_KS_SCALING_ID "Scaling" #define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale" +#define ANIM_KS_LOC_ROT_SCALE_CPROP_ID "LocRotScaleCProp" #define ANIM_KS_AVAILABLE_ID "Available" #define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter" #define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected" -- cgit v1.2.3 From 1095d5964dd259df8e013a686060ffd82c97c6ab Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Thu, 22 Apr 2021 12:19:01 +0200 Subject: Cleanup: doversion for 3.0 is using FileData --- source/blender/blenloader/intern/versioning_300.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 2d29f496e71..6b13b21f057 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -51,7 +51,6 @@ void do_versions_after_linking_300(Main *UNUSED(bmain), ReportList *UNUSED(repor /* NOLINTNEXTLINE: readability-function-size */ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) { - UNUSED_VARS(fd); /** * Versioning code until next subversion bump goes here. -- cgit v1.2.3 From 71db02ed887d8b9db958b482aa42cc27f0e57ed2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 22 Apr 2021 12:48:59 +0200 Subject: Fix: geometry nodes logs incorrect preview data Under some circumstances, modifiers are evaluated more than once. One time to compute the actual output geometry and another time with `MOD_APPLY_ORCO`. This design probably has to be revisited at some point in the context of geometry nodes. However, that would be much more involved than a bug fix. The issue was that during the second evaluation, the node tree is evaluated based on a slightly different input geometry. The data generated during the second evaluation overwrote the cached data from the first evaluation, resulting in incorrect data that is shown in the spreadsheet. The fix for now is to simply not log any data in the second evaluation. --- source/blender/modifiers/intern/MOD_nodes.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 53b79d0b2a5..57de629fc18 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -271,6 +271,17 @@ static bool isDisabled(const struct Scene *UNUSED(scene), return false; } +static bool logging_enabled(const ModifierEvalContext *ctx) +{ + if (!DEG_is_active(ctx->depsgraph)) { + return false; + } + if ((ctx->flag & MOD_APPLY_ORCO) != 0) { + return false; + } + return true; +} + class GeometryNodesEvaluator { public: using LogSocketValueFn = std::function)>; @@ -1290,7 +1301,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, find_sockets_to_preview(nmd, ctx, tree, preview_sockets); auto log_socket_value = [&](const DSocket socket, const Span values) { - if (!DEG_is_active(ctx->depsgraph)) { + if (!logging_enabled(ctx)) { return; } Span keys = preview_sockets.lookup(socket); @@ -1401,7 +1412,7 @@ static void modifyGeometry(ModifierData *md, return; } - if (DEG_is_active(ctx->depsgraph)) { + if (logging_enabled(ctx)) { reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md); } -- cgit v1.2.3 From 0ba0d27d368422b29db42c09f0ef658ce5b1e604 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 22 Apr 2021 14:09:33 +0200 Subject: Fix T87090: VSE scrubbing locks up blender Speed effect caused, that some raw frames are re-used for multiple final frames. When cached final frame is freed due to memory being full, it tried to free also lower level cached frames that were used during compositing. Some lower level cached frames were already freed by different final frame and `BLI_ghash_remove()` failed. Check if key still exists in hash or if linked keys were overwritten before removing them. Reviewed By: sergey Differential Revision: https://developer.blender.org/D10909 --- source/blender/sequencer/intern/image_cache.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'source/blender') diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 290ee185865..089bb5a6bec 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -976,14 +976,34 @@ static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base) SeqCacheKey *next = base->link_next; while (base) { + if (!BLI_ghash_haskey(cache->hash, base)) { + break; /* Key has already been removed from cache. */ + } + SeqCacheKey *prev = base->link_prev; + if (prev != NULL && prev->link_next != base) { + /* Key has been removed and replaced and doesn't belong to this chain anymore. */ + base->link_prev = NULL; + break; + } + BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree); base = prev; } base = next; while (base) { + if (!BLI_ghash_haskey(cache->hash, base)) { + break; /* Key has already been removed from cache. */ + } + next = base->link_next; + if (next != NULL && next->link_prev != base) { + /* Key has been removed and replaced and doesn't belong to this chain anymore. */ + base->link_next = NULL; + break; + } + BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree); base = next; } -- cgit v1.2.3 From 80536e8bae3ef92b894f2005bcf3f96865234e51 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 22 Apr 2021 09:57:45 -0300 Subject: Fix T87615: No snapping to objects instanced by Geometry nodes The code of the snapping system to interact the objects in the scene only considers instances what comes from "DUPLI" objects. This commit adds instances coming from Geometry nodes. Differential Revision: https://developer.blender.org/D11020 --- source/blender/editors/transform/transform_snap_object.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index ec98b6af169..e97d49e0971 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -415,10 +415,12 @@ static void iter_snap_objects(SnapObjectContext *sctx, } Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); - if (obj_eval->transflag & OB_DUPLI) { - DupliObject *dupli_ob; + if (obj_eval->transflag & OB_DUPLI || + (obj_eval->runtime.geometry_set_eval != NULL && + BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) { ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); - for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { + BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); sob_callback(sctx, dupli_ob->ob, dupli_ob->mat, -- cgit v1.2.3 From b9a7b40924f6284af5867cb63078dc79c714a675 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 22 Apr 2021 08:05:02 -0500 Subject: Geometry Nodes: Get attribute domain and type without allocation Because we use virtual classes (and for other reasons), we had to do a small allocation when simply retrieving the data type and domain of an existing attribute. This happened quite a lot actually-- to determine these values for result attributes. This patch adds a simple function to retrieve this meta data without building the virtual array. This should lower the overhead of every attribute node, though the difference probably won't be noticible unless a tree has very many nodes. Differential Revision: https://developer.blender.org/D11047 --- source/blender/blenkernel/BKE_geometry_set.hh | 4 ++++ .../blender/blenkernel/intern/attribute_access.cc | 14 +++++++++++++ .../geometry/nodes/node_geo_attribute_clamp.cc | 12 +++++------ .../nodes/node_geo_attribute_color_ramp.cc | 12 +++++------ .../nodes/node_geo_attribute_combine_xyz.cc | 6 +++--- .../geometry/nodes/node_geo_attribute_compare.cc | 6 +++--- .../geometry/nodes/node_geo_attribute_convert.cc | 20 +++++++++--------- .../geometry/nodes/node_geo_attribute_fill.cc | 9 ++++---- .../geometry/nodes/node_geo_attribute_map_range.cc | 12 +++++------ .../geometry/nodes/node_geo_attribute_math.cc | 6 +++--- .../nodes/geometry/nodes/node_geo_attribute_mix.cc | 6 +++--- .../geometry/nodes/node_geo_attribute_randomize.cc | 8 ++++---- .../nodes/node_geo_attribute_sample_texture.cc | 17 ++++++++------- .../nodes/node_geo_attribute_separate_xyz.cc | 24 +++++++++++----------- .../geometry/nodes/node_geo_point_distribute.cc | 9 +++----- source/blender/nodes/intern/node_geometry_exec.cc | 14 ++++++------- 16 files changed, 96 insertions(+), 83 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 38f692fee0e..e9545cba1f1 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -102,6 +102,10 @@ class GeometryComponent { /* Return true when any attribute with this name exists, including built in attributes. */ bool attribute_exists(const blender::StringRef attribute_name) const; + /* Return the data type and domain of an attribute with the given name if it exists. */ + std::optional attribute_get_meta_data( + const blender::StringRef attribute_name) const; + /* Returns true when the geometry component supports this attribute domain. */ bool attribute_domain_supported(const AttributeDomain domain) const; /* Can only be used with supported domain types. */ diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 3b2ee126d91..571763e3719 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -729,6 +729,20 @@ bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name return false; } +std::optional GeometryComponent::attribute_get_meta_data( + const StringRef attribute_name) const +{ + std::optional result{std::nullopt}; + this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) { + if (attribute_name == name) { + result = meta_data; + return false; + } + return true; + }); + return result; +} + static std::unique_ptr try_adapt_data_type( std::unique_ptr varray, const blender::fn::CPPType &to_type) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc index e7677ed41e1..1943971d49f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc @@ -126,13 +126,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } - ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); - if (source_attribute) { - return source_attribute.domain; + std::optional source_info = component.attribute_get_meta_data(source_name); + if (source_info) { + return source_info->domain; } return ATTR_DOMAIN_POINT; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc index af65fe110e9..9e697226a01 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -47,15 +47,15 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the input attribute's domain if it exists. */ - ReadAttributeLookup input_attribute = component.attribute_try_get_for_read(input_name); - if (input_attribute) { - return input_attribute.domain; + std::optional source_info = component.attribute_get_meta_data(input_name); + if (source_info) { + return source_info->domain; } return ATTR_DOMAIN_POINT; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc index c3db26c7299..69e628267a4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc @@ -77,9 +77,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc index 22855787ab0..ccfaeb9bb47 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc @@ -234,9 +234,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc index bb46c5c84cd..60bb27191b4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc @@ -55,13 +55,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } - ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); - if (source_attribute) { - return source_attribute.domain; + std::optional source_info = component.attribute_get_meta_data(source_name); + if (source_info) { + return source_info->domain; } return ATTR_DOMAIN_POINT; } @@ -75,14 +75,14 @@ static bool conversion_can_be_skipped(const GeometryComponent &component, if (source_name != result_name) { return false; } - ReadAttributeLookup read_attribute = component.attribute_try_get_for_read(source_name); - if (!read_attribute) { + std::optional info = component.attribute_get_meta_data(result_name); + if (!info) { return false; } - if (read_attribute.domain != result_domain) { + if (info->domain != result_domain) { return false; } - if (read_attribute.varray->type() != *bke::custom_data_type_to_cpp_type(result_type)) { + if (info->data_type != result_type) { return false; } return true; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc index 8287313e400..3df64625b99 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc @@ -68,13 +68,12 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node namespace blender::nodes { -static AttributeDomain get_result_domain(const GeometryComponent &component, - StringRef attribute_name) +static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(name); + if (result_info) { + return result_info->domain; } return ATTR_DOMAIN_POINT; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc index 4a98d6caed2..5d82897e9db 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc @@ -318,13 +318,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } - ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); - if (source_attribute) { - return source_attribute.domain; + std::optional source_info = component.attribute_get_meta_data(source_name); + if (source_info) { + return source_info->domain; } return ATTR_DOMAIN_POINT; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index 99ba6acd94d..00ae6b373b2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -200,9 +200,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc index e7f0de8f28e..7129679117d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc @@ -141,9 +141,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index e86fa3ae0ed..cc6aacaca79 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -196,12 +196,12 @@ Array get_geometry_element_ids_as_uints(const GeometryComponent &compo static AttributeDomain get_result_domain(const GeometryComponent &component, const GeoNodeExecParams ¶ms, - StringRef attribute_name) + const StringRef name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(name); + if (result_info) { + return result_info->domain; } /* Otherwise use the input domain chosen in the interface. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc index 5b3fd75342a..fa11ef936cd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc @@ -49,20 +49,19 @@ static void geo_node_attribute_sample_texture_layout(uiLayout *layout, namespace blender::nodes { static AttributeDomain get_result_domain(const GeometryComponent &component, - StringRef result_attribute_name, - StringRef map_attribute_name) + const StringRef result_name, + const StringRef map_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributeLookup result_attribute = component.attribute_try_get_for_read( - result_attribute_name); - if (result_attribute) { - return result_attribute.domain; + std::optional result_info = component.attribute_get_meta_data(result_name); + if (result_info) { + return result_info->domain; } /* Otherwise use the name of the map attribute. */ - ReadAttributeLookup map_attribute = component.attribute_try_get_for_read(map_attribute_name); - if (map_attribute) { - return map_attribute.domain; + std::optional map_info = component.attribute_get_meta_data(map_name); + if (map_info) { + return map_info->domain; } /* The node won't execute in this case, but we still have to return a value. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc index daf61b6bf57..bbc6cb71032 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc @@ -71,23 +71,23 @@ static void extract_input(const int index, const Span &input, MutableSpa static AttributeDomain get_result_domain(const GeometryComponent &component, const GeoNodeExecParams ¶ms, - StringRef result_name_x, - StringRef result_name_y, - StringRef result_name_z) + const StringRef name_x, + const StringRef name_y, + const StringRef name_z) { /* Use the highest priority domain from any existing attribute outputs. */ Vector output_domains; - ReadAttributeLookup attribute_x = component.attribute_try_get_for_read(result_name_x); - ReadAttributeLookup attribute_y = component.attribute_try_get_for_read(result_name_y); - ReadAttributeLookup attribute_z = component.attribute_try_get_for_read(result_name_z); - if (attribute_x) { - output_domains.append(attribute_x.domain); + std::optional info_x = component.attribute_get_meta_data(name_x); + std::optional info_y = component.attribute_get_meta_data(name_y); + std::optional info_z = component.attribute_get_meta_data(name_z); + if (info_x) { + output_domains.append(info_x->domain); } - if (attribute_y) { - output_domains.append(attribute_y.domain); + if (info_y) { + output_domains.append(info_y->domain); } - if (attribute_z) { - output_domains.append(attribute_z.domain); + if (info_z) { + output_domains.append(info_z->domain); } if (output_domains.size() > 0) { return bke::attribute_domain_highest_priority(output_domains); diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 28d5d9a96f7..772bd8a1080 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -306,17 +306,14 @@ BLI_NOINLINE static void interpolate_existing_attributes( const MeshComponent &source_component = *set.get_component_for_read(); const Mesh &mesh = *source_component.get_for_read(); - /* Use a dummy read without specifying a domain or data type in order to - * get the existing attribute's domain. Interpolation is done manually based - * on the bary coords in #interpolate_attribute. */ - ReadAttributeLookup dummy_attribute = source_component.attribute_try_get_for_read( + std::optional attribute_info = component.attribute_get_meta_data( attribute_name); - if (!dummy_attribute) { + if (!attribute_info) { i_instance += set_group.transforms.size(); continue; } - const AttributeDomain source_domain = dummy_attribute.domain; + const AttributeDomain source_domain = attribute_info->domain; GVArrayPtr source_attribute = source_component.attribute_get_for_read( attribute_name, source_domain, output_data_type, nullptr); if (!source_attribute) { diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 2648336f0c0..08fbe1ac1e6 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -126,11 +126,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input(found_socket->identifier); - ReadAttributeLookup attribute = component.attribute_try_get_for_read(name); - if (!attribute) { - return default_type; + std::optional info = component.attribute_get_meta_data(name); + if (info) { + return info->data_type; } - return bke::cpp_type_to_custom_data_type(attribute.varray->type()); + return default_type; } if (found_socket->type == SOCK_FLOAT) { return CD_PROP_FLOAT; @@ -169,9 +169,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input(found_socket->identifier); - ReadAttributeLookup attribute = component.attribute_try_get_for_read(name); - if (attribute) { - input_domains.append(attribute.domain); + std::optional info = component.attribute_get_meta_data(name); + if (info) { + input_domains.append(info->domain); } } } -- cgit v1.2.3 From 9fccbe2d1385df6dfbd3291d2b8950732e028f25 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 22 Apr 2021 10:04:59 -0300 Subject: Fix missing include --- source/blender/editors/transform/transform_snap_object.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index ce3f519271f..512f912a532 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -43,6 +43,7 @@ #include "BKE_curve.h" #include "BKE_duplilist.h" #include "BKE_editmesh.h" +#include "BKE_geometry_set.h" #include "BKE_global.h" #include "BKE_layer.h" #include "BKE_mesh.h" -- cgit v1.2.3 From d1ccc5b9694b7c737158f4d4bd83ae780b32d258 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 22 Apr 2021 09:20:03 -0500 Subject: Geometry Nodes: Add initializer for attribute creation Previously we always had to set attribute values after creating the attribute. This patch adds an initializer argument to `attribute_try_create` which can fill it in a few ways, which are explained in code comments. This fixes T87597. Differential Revision: https://developer.blender.org/D11045 --- source/blender/blenkernel/BKE_geometry_set.hh | 65 +++++++++- .../blender/blenkernel/intern/attribute_access.cc | 132 ++++++++++++++++++--- .../blenkernel/intern/attribute_access_intern.hh | 11 +- .../blenkernel/intern/geometry_component_mesh.cc | 3 +- .../blenkernel/intern/geometry_set_instances.cc | 3 +- 5 files changed, 188 insertions(+), 26 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index e9545cba1f1..027338a5d5c 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -69,6 +69,65 @@ struct AttributeMetaData { using AttributeForeachCallback = blender::FunctionRef; +/** + * Base class for the attribute intializer types described below. + */ +struct AttributeInit { + enum class Type { + Default, + VArray, + MoveArray, + }; + Type type; + AttributeInit(const Type type) : type(type) + { + } +}; + +/** + * Create an attribute using the default value for the data type. + * The default values may depend on the attribute provider implementation. + */ +struct AttributeInitDefault : public AttributeInit { + AttributeInitDefault() : AttributeInit(Type::Default) + { + } +}; + +/** + * Create an attribute by copying data from an existing virtual array. The virtual array + * must have the same type as the newly created attribute. + * + * Note that this can be used to fill the new attribute with the default + */ +struct AttributeInitVArray : public AttributeInit { + const blender::fn::GVArray *varray; + + AttributeInitVArray(const blender::fn::GVArray *varray) + : AttributeInit(Type::VArray), varray(varray) + { + } +}; + +/** + * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data. + * Sometimes data is created before a geometry component is available. In that case, it's + * preferable to move data directly to the created attribute to avoid a new allocation and a copy. + * + * Note that this will only have a benefit for attributes that are stored directly as contigious + * arrays, so not for some built-in attributes. + * + * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it + * can't be used directly, and that is generally how Blender expects custom data to be allocated. + */ +struct AttributeInitMove : public AttributeInit { + void *data = nullptr; + + AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + { + } +}; + /** * This is the base class for specialized geometry component types. */ @@ -137,11 +196,13 @@ class GeometryComponent { /* Returns true when the attribute has been created. */ bool attribute_try_create(const blender::StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type); + const CustomDataType data_type, + const AttributeInit &initializer); /* Try to create the builtin attribute with the given name. No data type or domain has to be * provided, because those are fixed for builtin attributes. */ - bool attribute_try_create_builtin(const blender::StringRef attribute_name); + bool attribute_try_create_builtin(const blender::StringRef attribute_name, + const AttributeInit &initializer); blender::Set attribute_names() const; bool attribute_foreach(const AttributeForeachCallback callback) const; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 571763e3719..6c37d34dc9b 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -254,7 +254,43 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co return delete_success; } -bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const +static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data, + const CustomDataType data_type, + const int domain_size, + const AttributeInit &initializer) +{ + switch (initializer.type) { + case AttributeInit::Type::Default: { + void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); + return data != nullptr; + } + case AttributeInit::Type::VArray: { + void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); + if (data == nullptr) { + return false; + } + const GVArray *varray = static_cast(initializer).varray; + varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + return true; + } + case AttributeInit::Type::MoveArray: { + void *source_data = static_cast(initializer).data; + void *data = CustomData_add_layer( + &custom_data, data_type, CD_ASSIGN, source_data, domain_size); + if (data == nullptr) { + MEM_freeN(source_data); + return false; + } + return true; + } + } + + BLI_assert_unreachable(); + return false; +} + +bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, + const AttributeInit &initializer) const { if (createable_ != Creatable) { return false; @@ -267,10 +303,10 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) co /* Exists already. */ return false; } + const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_add_layer( - custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); - const bool success = data != nullptr; + const bool success = add_custom_data_layer_from_attribute_init( + *custom_data, stored_type_, domain_size, initializer); if (success) { custom_data_access_.update_custom_data_pointers(component); } @@ -372,10 +408,52 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, return false; } +static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name, + CustomData &custom_data, + const CustomDataType data_type, + const int domain_size, + const AttributeInit &initializer) +{ + char attribute_name_c[MAX_NAME]; + attribute_name.copy(attribute_name_c); + + switch (initializer.type) { + case AttributeInit::Type::Default: { + void *data = CustomData_add_layer_named( + &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + return data != nullptr; + } + case AttributeInit::Type::VArray: { + void *data = CustomData_add_layer_named( + &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + if (data == nullptr) { + return false; + } + const GVArray *varray = static_cast(initializer).varray; + varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + return true; + } + case AttributeInit::Type::MoveArray: { + void *source_data = static_cast(initializer).data; + void *data = CustomData_add_layer_named( + &custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c); + if (data == nullptr) { + MEM_freeN(source_data); + return false; + } + return true; + } + } + + BLI_assert_unreachable(); + return false; +} + bool CustomDataAttributeProvider::try_create(GeometryComponent &component, const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type) const + const CustomDataType data_type, + const AttributeInit &initializer) const { if (domain_ != domain) { return false; @@ -393,10 +471,8 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component, } } const int domain_size = component.attribute_domain_size(domain_); - char attribute_name_c[MAX_NAME]; - attribute_name.copy(attribute_name_c); - CustomData_add_layer_named( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + add_named_custom_data_layer_from_attribute_init( + attribute_name, *custom_data, data_type, domain_size, initializer); return true; } @@ -621,7 +697,8 @@ bool GeometryComponent::attribute_try_delete(const StringRef attribute_name) bool GeometryComponent::attribute_try_create(const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type) + const CustomDataType data_type, + const AttributeInit &initializer) { using namespace blender::bke; if (attribute_name.is_empty()) { @@ -640,18 +717,19 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name, if (builtin_provider->data_type() != data_type) { return false; } - return builtin_provider->try_create(*this); + return builtin_provider->try_create(*this, initializer); } for (const DynamicAttributesProvider *dynamic_provider : providers->dynamic_attribute_providers()) { - if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) { + if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) { return true; } } return false; } -bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name) +bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name, + const AttributeInit &initializer) { using namespace blender::bke; if (attribute_name.is_empty()) { @@ -666,7 +744,7 @@ bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef at if (builtin_provider == nullptr) { return false; } - return builtin_provider->try_create(*this); + return builtin_provider->try_create(*this, initializer); } Set GeometryComponent::attribute_names() const @@ -874,7 +952,8 @@ static void save_output_attribute(blender::bke::OutputAttribute &output_attribut const CPPType &cpp_type = output_attribute.cpp_type(); component.attribute_try_delete(name); - if (!component.attribute_try_create(varray.final_name, domain, data_type)) { + if (!component.attribute_try_create( + varray.final_name, domain, data_type, AttributeInitDefault())) { CLOG_WARN(&LOG, "Could not create the '%s' attribute with type '%s'.", name.c_str(), @@ -912,7 +991,15 @@ static blender::bke::OutputAttribute create_output_attribute( if (component.attribute_is_builtin(attribute_name)) { WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { - component.attribute_try_create_builtin(attribute_name); + if (default_value) { + const int64_t domain_size = component.attribute_domain_size(domain); + const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; + component.attribute_try_create_builtin(attribute_name, + AttributeInitVArray(&default_varray)); + } + else { + component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); + } attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { /* Builtin attribute does not exist and can't be created. */ @@ -933,9 +1020,19 @@ static blender::bke::OutputAttribute create_output_attribute( return OutputAttribute(std::move(varray), domain, {}, ignore_old_values); } + const int domain_size = component.attribute_domain_size(domain); + WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { - component.attribute_try_create(attribute_name, domain, data_type); + if (default_value) { + const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; + component.attribute_try_create( + attribute_name, domain, data_type, AttributeInitVArray(&default_varray)); + } + else { + component.attribute_try_create(attribute_name, domain, data_type, AttributeInitDefault()); + } + attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { /* Can't create the attribute. */ @@ -947,7 +1044,6 @@ static blender::bke::OutputAttribute create_output_attribute( return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values); } - const int domain_size = component.attribute_domain_size(domain); /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing * attribute after processing is done. */ void *data = MEM_mallocN_aligned( diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 7cf585dfbfc..b3a795faa30 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -89,7 +89,8 @@ class BuiltinAttributeProvider { virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0; virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0; virtual bool try_delete(GeometryComponent &component) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; + virtual bool try_create(GeometryComponent &UNUSED(component), + const AttributeInit &UNUSED(initializer)) const = 0; virtual bool exists(const GeometryComponent &component) const = 0; StringRefNull name() const @@ -122,7 +123,8 @@ class DynamicAttributesProvider { virtual bool try_create(GeometryComponent &UNUSED(component), const StringRef UNUSED(attribute_name), const AttributeDomain UNUSED(domain), - const CustomDataType UNUSED(data_type)) const + const CustomDataType UNUSED(data_type), + const AttributeInit &UNUSED(initializer)) const { /* Some providers should not create new attributes. */ return false; @@ -162,7 +164,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { bool try_create(GeometryComponent &component, const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type) const final; + const CustomDataType data_type, + const AttributeInit &initializer) const final; bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final; @@ -278,7 +281,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { GVArrayPtr try_get_for_read(const GeometryComponent &component) const final; GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final; bool try_delete(GeometryComponent &component) const final; - bool try_create(GeometryComponent &component) const final; + bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final; bool exists(const GeometryComponent &component) const final; }; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index e5accd98952..e54c3716660 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -1014,7 +1014,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { return false; } - bool try_create(GeometryComponent &UNUSED(component)) const final + bool try_create(GeometryComponent &UNUSED(component), + const AttributeInit &UNUSED(initializer)) const final { return false; } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 2e9f6daabad..47db5d1f901 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -449,7 +449,8 @@ static void join_attributes(Span set_groups, const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output); BLI_assert(cpp_type != nullptr); - result.attribute_try_create(entry.key, domain_output, data_type_output); + result.attribute_try_create( + entry.key, domain_output, data_type_output, AttributeInitDefault()); WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name); if (!write_attribute || &write_attribute.varray->type() != cpp_type || write_attribute.domain != domain_output) { -- cgit v1.2.3