From b647c2b88d684ced787a0dec6ff2d8f9f9b3f05d Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 08:52:33 -0400 Subject: [PATCH 01/61] Cleanup: Remove unused variables/functions Also change from `unsigned int` to `uint` for consistency between function declarations and definitions. --- .../blender/editors/sculpt_paint/sculpt_boundary.cc | 2 -- source/blender/io/collada/MeshImporter.h | 12 +++++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.cc b/source/blender/editors/sculpt_paint/sculpt_boundary.cc index 964633d988d..ce47e6c97cf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.cc +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.cc @@ -7,7 +7,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_edgehash.h" #include "BLI_math.h" #include "BLI_task.h" @@ -199,7 +198,6 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, struct BoundaryFloodFillData { SculptBoundary *boundary; GSet *included_verts; - EdgeSet *preview_edges; PBVHVertRef last_visited_vertex; }; diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index eab9ef7cb8f..7b4188785fd 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -83,7 +83,7 @@ class MeshImporter : public MeshImporterBase { struct Primitive { int poly_index; int *material_indices; - unsigned int totpoly; + uint totpoly; }; typedef std::map> MaterialIdPrimitiveArrayMap; /* crazy name! */ @@ -94,7 +94,7 @@ class MeshImporter : public MeshImporterBase { bool set_poly_indices(int *poly_verts, int loop_index, - const unsigned int *indices, + const uint *indices, int loop_count); void set_face_uv(blender::float2 *mloopuv, @@ -140,9 +140,7 @@ class MeshImporter : public MeshImporterBase { */ static void mesh_add_edges(Mesh *mesh, int len); - unsigned int get_loose_edge_count(COLLADAFW::Mesh *mesh); - - CustomData create_edge_custom_data(EdgeHash *eh); + uint get_loose_edge_count(COLLADAFW::Mesh *mesh); /** * Return the number of faces by summing up @@ -168,11 +166,11 @@ class MeshImporter : public MeshImporterBase { * So this function MUST be called after read_faces() (see below) */ void read_lines(COLLADAFW::Mesh *mesh, Mesh *me); - unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index); + uint get_vertex_count(COLLADAFW::Polygons *mp, int index); void get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride); - bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count); + bool is_flat_face(uint *nind, COLLADAFW::MeshVertexData &nor, int count); /** * Returns the list of Users of the given Mesh object. -- 2.30.2 From 5ab48a53e4df7003d93d7633346747b713e1b01b Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 09:29:08 -0400 Subject: [PATCH 02/61] Cleanup: Use generic edge calculation for legacy curve to mesh Change the "displist to mesh" conversion to use the edge calculation function used everywhere else, to allow removing the old code. This changes edge vertex and corner edge indices, requiring a test update, but the visual result should be the same. --- .../blender/blenkernel/intern/mesh_convert.cc | 92 +------------------ 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index c1decc6b9cb..2daf9fb6443 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -62,98 +62,8 @@ using blender::MutableSpan; using blender::Span; using blender::StringRefNull; -/* Define for cases when you want extra validation of mesh - * after certain modifications. - */ -// #undef VALIDATE_MESH - -#ifdef VALIDATE_MESH -# define ASSERT_IS_VALID_MESH(mesh) \ - (BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true))) -#else -# define ASSERT_IS_VALID_MESH(mesh) -#endif - static CLG_LogRef LOG = {"bke.mesh_convert"}; -static void poly_edgehash_insert(EdgeHash *ehash, const Span poly_verts) -{ - int i = poly_verts.size(); - - int next = 0; /* first loop */ - int poly_corner = (i - 1); /* last loop */ - - while (i-- != 0) { - BLI_edgehash_reinsert(ehash, poly_verts[poly_corner], poly_verts[next], nullptr); - - poly_corner = next; - next++; - } -} - -/** - * Specialized function to use when we _know_ existing edges don't overlap with poly edges. - */ -static void make_edges_mdata_extend(Mesh &mesh) -{ - int totedge = mesh.totedge; - - const blender::OffsetIndices polys = mesh.polys(); - const Span corner_verts = mesh.corner_verts(); - MutableSpan corner_edges = mesh.corner_edges_for_write(); - - const int eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(mesh.totpoly)); - EdgeHash *eh = BLI_edgehash_new_ex(__func__, eh_reserve); - - for (const int i : polys.index_range()) { - poly_edgehash_insert(eh, corner_verts.slice(polys[i])); - } - - const int totedge_new = BLI_edgehash_len(eh); - -#ifdef DEBUG - /* ensure that there's no overlap! */ - if (totedge_new) { - for (const blender::int2 &edge : mesh.edges()) { - BLI_assert(BLI_edgehash_haskey(eh, edge[0], edge[1]) == false); - } - } -#endif - - if (totedge_new) { - /* The only layer should be edges, so no other layers need to be initialized. */ - BLI_assert(mesh.edata.totlayer == 1); - CustomData_realloc(&mesh.edata, totedge, totedge + totedge_new); - mesh.totedge += totedge_new; - MutableSpan edges = mesh.edges_for_write(); - blender::int2 *edge = &edges[totedge]; - - EdgeHashIterator *ehi; - uint e_index = totedge; - for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false; - BLI_edgehashIterator_step(ehi), ++edge, e_index++) { - BLI_edgehashIterator_getKey(ehi, &(*edge)[0], &(*edge)[1]); - BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index)); - } - BLI_edgehashIterator_free(ehi); - - for (const int i : polys.index_range()) { - const IndexRange poly = polys[i]; - int corner = poly.start(); - int corner_prev = poly.start() + (poly.size() - 1); - int j; - for (j = 0; j < poly.size(); j++, corner++) { - /* lookup hashed edge index */ - corner_edges[corner_prev] = POINTER_AS_UINT( - BLI_edgehash_lookup(eh, corner_verts[corner_prev], corner_verts[corner])); - corner_prev = corner; - } - } - } - - BLI_edgehash_free(eh, nullptr); -} - static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase) { using namespace blender::bke; @@ -393,7 +303,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } if (totpoly) { - make_edges_mdata_extend(*mesh); + BKE_mesh_calc_edges(mesh, true, false); } material_indices.finish(); -- 2.30.2 From 91a29c9b9affeb26cbc89a8baa40108bda30fe0c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 19 Apr 2023 15:32:37 +0200 Subject: [PATCH 03/61] Fix #107127: Context property driver to view layer does not work The resolution of the driver value RNA path was using the wrong property (it was forced to be referenced relative to the ID). Pull Request: https://projects.blender.org/blender/blender/pulls/107129 --- .../depsgraph/intern/builder/deg_builder_key.cc | 13 +++++++++++++ .../depsgraph/intern/builder/deg_builder_key.h | 3 +++ .../intern/builder/deg_builder_relations.cc | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.cc b/source/blender/depsgraph/intern/builder/deg_builder_key.cc index b3ba0449e76..62e89878abd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_key.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.cc @@ -84,6 +84,19 @@ RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPoin { } +RNAPathKey::RNAPathKey(const PointerRNA &target_prop, + const char *rna_path_from_target_prop, + const RNAPointerSource source) + : id(target_prop.owner_id), source(source) +{ + /* Try to resolve path. */ + int index; + if (!RNA_path_resolve_full(&target_prop, rna_path_from_target_prop, &ptr, &prop, &index)) { + ptr = PointerRNA_NULL; + prop = nullptr; + } +} + string RNAPathKey::identifier() const { const char *id_name = (id) ? id->name : ""; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.h b/source/blender/depsgraph/intern/builder/deg_builder_key.h index 0335e80951d..6a26a75308e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_key.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.h @@ -188,6 +188,9 @@ struct PersistentOperationKey : public OperationKey { struct RNAPathKey { RNAPathKey(ID *id, const char *path, RNAPointerSource source); + RNAPathKey(const PointerRNA &target_prop, + const char *rna_path_from_target_prop, + RNAPointerSource source); RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); string identifier() const; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 1072509bbf7..8c7831d7e93 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1807,7 +1807,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) add_relation(target_key, driver_key, "Target -> Driver"); } else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') { - RNAPathKey variable_exit_key(target_id, dtar->rna_path, RNAPointerSource::EXIT); + RNAPathKey variable_exit_key(target_prop, dtar->rna_path, RNAPointerSource::EXIT); if (RNA_pointer_is_null(&variable_exit_key.ptr)) { continue; } -- 2.30.2 From d6abd2ce727cb5c973229c80b0fcd943c9bf5204 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 15:48:18 +0200 Subject: [PATCH 04/61] Fix #106138: Node add searches missing context-based poll Before the add node search refactor and link-drag-search, nodes were filtered out based on whether they worked with the active render engine. For example, the Principled Hair BSDF node doesn't work with EEVEE, so it isn't displayed in the UI. While we might want to relax this in the future, we have no better way to show that they don't work right now, so it's best to keep that behavior. The filtering is implemented with a new node type callback, mainly to reduce the boilerplate of implementing many node search callbacks otherwise. It's also relatively clear this way I think. The only downside is that now there are three poll functions. I didn't port the "eevee_cycles_shader_nodes_poll" to the new searches, since I don't understand the purpose of it. Pull Request: https://projects.blender.org/blender/blender/pulls/106829 --- source/blender/blenkernel/BKE_node.h | 6 +++ .../editors/space_node/add_node_search.cc | 5 ++- .../editors/space_node/link_drag_search.cc | 3 ++ source/blender/nodes/NOD_add_node_search.hh | 11 ++++- .../blender/nodes/shader/node_shader_util.cc | 40 +++++++++++++++++++ .../blender/nodes/shader/node_shader_util.hh | 5 +++ .../shader/nodes/node_shader_background.cc | 1 + .../nodes/node_shader_bsdf_anisotropic.cc | 1 + .../shader/nodes/node_shader_bsdf_diffuse.cc | 1 + .../shader/nodes/node_shader_bsdf_glass.cc | 1 + .../shader/nodes/node_shader_bsdf_glossy.cc | 1 + .../shader/nodes/node_shader_bsdf_hair.cc | 1 + .../nodes/node_shader_bsdf_hair_principled.cc | 1 + .../nodes/node_shader_bsdf_principled.cc | 1 + .../nodes/node_shader_bsdf_refraction.cc | 1 + .../shader/nodes/node_shader_bsdf_toon.cc | 1 + .../nodes/node_shader_bsdf_translucent.cc | 1 + .../nodes/node_shader_bsdf_transparent.cc | 1 + .../shader/nodes/node_shader_bsdf_velvet.cc | 1 + .../nodes/node_shader_eevee_specular.cc | 1 + .../nodes/shader/nodes/node_shader_holdout.cc | 1 + .../shader/nodes/node_shader_output_light.cc | 1 + .../nodes/node_shader_output_linestyle.cc | 1 + .../nodes/node_shader_output_material.cc | 1 + .../shader/nodes/node_shader_output_world.cc | 1 + .../shader/nodes/node_shader_shader_to_rgb.cc | 1 + .../node_shader_subsurface_scattering.cc | 1 + .../nodes/node_shader_uv_along_stroke.cc | 1 + 28 files changed, 89 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 3039334b8f8..03cec560682 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -298,6 +298,12 @@ typedef struct bNodeType { void (*freefunc_api)(struct PointerRNA *ptr); void (*copyfunc_api)(struct PointerRNA *ptr, const struct bNode *src_node); + /** + * An additional poll test for deciding whether nodes should be an option in search menus. + * Potentially more strict poll than #poll(), but doesn't have to check the same things. + */ + bool (*add_ui_poll)(const struct bContext *C); + /** * Can this node type be added to a node tree? * \param r_disabled_hint: Hint to display in the UI when the poll fails. diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc index c0ba8cd998e..8cf72e19652 100644 --- a/source/blender/editors/space_node/add_node_search.cc +++ b/source/blender/editors/space_node/add_node_search.cc @@ -161,11 +161,14 @@ static void gather_add_node_operations(const bContext &C, if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { continue; } + if (!(node_type->add_ui_poll && node_type->add_ui_poll(&C))) { + continue; + } if (!node_type->gather_add_node_search_ops) { continue; } Vector info_items; - nodes::GatherAddNodeSearchParams params(*node_type, node_tree, info_items); + nodes::GatherAddNodeSearchParams params(C, *node_type, node_tree, info_items); node_type->gather_add_node_search_ops(params); for (nodes::AddNodeInfo &info : info_items) { AddNodeItem item{}; diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index ae0261a57b9..124fca9ee56 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -288,6 +288,9 @@ static void gather_socket_link_operations(const bContext &C, if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { continue; } + if (!(node_type->add_ui_poll && node_type->add_ui_poll(&C))) { + continue; + } if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) { continue; } diff --git a/source/blender/nodes/NOD_add_node_search.hh b/source/blender/nodes/NOD_add_node_search.hh index b5b21cfe0d0..0fa5395a33c 100644 --- a/source/blender/nodes/NOD_add_node_search.hh +++ b/source/blender/nodes/NOD_add_node_search.hh @@ -25,18 +25,25 @@ struct AddNodeInfo { }; class GatherAddNodeSearchParams { + const bContext &C_; const bNodeType &node_type_; const bNodeTree &node_tree_; Vector &r_items; public: - GatherAddNodeSearchParams(const bNodeType &node_type, + GatherAddNodeSearchParams(const bContext &C, + const bNodeType &node_type, const bNodeTree &node_tree, Vector &r_items) - : node_type_(node_type), node_tree_(node_tree), r_items(r_items) + : C_(C), node_type_(node_type), node_tree_(node_tree), r_items(r_items) { } + const bContext &context() const + { + return C_; + } + const bNodeTree &node_tree() const { return node_tree_; diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc index a47934bda39..a16f5545a66 100644 --- a/source/blender/nodes/shader/node_shader_util.cc +++ b/source/blender/nodes/shader/node_shader_util.cc @@ -6,7 +6,9 @@ */ #include "DNA_node_types.h" +#include "DNA_space_types.h" +#include "BKE_context.h" #include "BKE_node_runtime.hh" #include "node_shader_util.hh" @@ -14,6 +16,8 @@ #include "NOD_add_node_search.hh" #include "NOD_socket_search_link.hh" +#include "RE_engine.h" + #include "node_exec.h" bool sh_node_poll_default(const bNodeType * /*ntype*/, @@ -56,6 +60,42 @@ void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nc ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node; } +bool line_style_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_LINESTYLE; +} + +bool world_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_WORLD; +} + +bool object_shader_nodes_poll(const bContext *C) +{ + const SpaceNode *snode = CTX_wm_space_node(C); + return snode->shaderfrom == SNODE_SHADER_OBJECT; +} + +bool object_cycles_shader_nodes_poll(const bContext *C) +{ + if (!object_shader_nodes_poll(C)) { + return false; + } + const RenderEngineType *engine_type = CTX_data_engine_type(C); + return STREQ(engine_type->idname, "CYCLES"); +} + +bool object_eevee_shader_nodes_poll(const bContext *C) +{ + if (!object_shader_nodes_poll(C)) { + return false; + } + const RenderEngineType *engine_type = CTX_data_engine_type(C); + return STREQ(engine_type->idname, "BLENDER_EEVEE"); +} + /* ****** */ static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index 46454fe645e..6ebfd441405 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -68,6 +68,11 @@ bool sh_node_poll_default(const struct bNodeType *ntype, const char **r_disabled_hint); void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); +bool line_style_shader_nodes_poll(const struct bContext *C); +bool world_shader_nodes_poll(const struct bContext *C); +bool object_shader_nodes_poll(const struct bContext *C); +bool object_cycles_shader_nodes_poll(const struct bContext *C); +bool object_eevee_shader_nodes_poll(const struct bContext *C); /* ********* exec data struct, remains internal *********** */ diff --git a/source/blender/nodes/shader/nodes/node_shader_background.cc b/source/blender/nodes/shader/nodes/node_shader_background.cc index 7ac6b63e7c8..b360f585c89 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.cc +++ b/source/blender/nodes/shader/nodes/node_shader_background.cc @@ -33,6 +33,7 @@ void register_node_type_sh_background() sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = world_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_background; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc index f80f99dc174..f28c31d0288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc @@ -67,6 +67,7 @@ void register_node_type_sh_bsdf_anisotropic() sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_anisotropic; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_anisotropic; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 21978c0da02..ba0ccb21720 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -44,6 +44,7 @@ void register_node_type_sh_bsdf_diffuse() sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_diffuse; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 52ffacf22d5..f243ccd3e41 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -56,6 +56,7 @@ void register_node_type_sh_bsdf_glass() sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_glass; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glass; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 4352a9b4a71..c2a4d1d3501 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -55,6 +55,7 @@ void register_node_type_sh_bsdf_glossy() sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_glossy; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_glossy; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc index 8e127350e5a..b167fb979e2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc @@ -56,6 +56,7 @@ void register_node_type_sh_bsdf_hair() sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_hair; node_type_size(&ntype, 150, 60, 200); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_hair; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc index 3c4b6ae5ee9..3712c53d2a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc @@ -127,6 +127,7 @@ void register_node_type_sh_bsdf_hair_principled() sh_node_type_base( &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_principled_hair; node_type_size_preset(&ntype, NODE_SIZE_LARGE); ntype.initfunc = file_ns::node_shader_init_hair_principled; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index f0fcc82d4c1..8cb4e3ad632 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -245,6 +245,7 @@ void register_node_type_sh_bsdf_principled() sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_principled; node_type_size_preset(&ntype, NODE_SIZE_LARGE); ntype.initfunc = file_ns::node_shader_init_principled; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index 18352f1132a..21cfe4eb6af 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -54,6 +54,7 @@ void register_node_type_sh_bsdf_refraction() sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_refraction; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_refraction; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc index c45e497c8e0..adc02379926 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc @@ -57,6 +57,7 @@ void register_node_type_sh_bsdf_toon() sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_toon; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_toon; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index ebaf95056cc..2d5ea718e11 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -39,6 +39,7 @@ void register_node_type_sh_bsdf_translucent() sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_translucent; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc index 05b371407ab..9eb11a66ef7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc @@ -34,6 +34,7 @@ void register_node_type_sh_bsdf_transparent() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_transparent; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc index 36bd1031db3..2df2de229db 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc @@ -43,6 +43,7 @@ void register_node_type_sh_bsdf_velvet() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_velvet; diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc index d8e341f2b2e..67b9a873a49 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc @@ -80,6 +80,7 @@ void register_node_type_sh_eevee_specular() sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_eevee_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_eevee_specular; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.cc b/source/blender/nodes/shader/nodes/node_shader_holdout.cc index f5d8f9b5548..b8e4ef38e72 100644 --- a/source/blender/nodes/shader/nodes/node_shader_holdout.cc +++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc @@ -30,6 +30,7 @@ void register_node_type_sh_holdout() static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER); + ntype.add_ui_poll = object_shader_nodes_poll; ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_rgb; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.cc b/source/blender/nodes/shader/nodes/node_shader_output_light.cc index 81cc1e35820..b55eeb13afa 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc @@ -37,6 +37,7 @@ void register_node_type_sh_output_light() sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_cycles_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_light; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc index 475dc9d1e17..6e7dd1cef30 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc @@ -49,6 +49,7 @@ void register_node_type_sh_output_linestyle() sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = line_style_shader_nodes_poll; ntype.draw_buttons = file_ns::node_buts_output_linestyle; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 6fb5e30d834..98df8d52ab9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -54,6 +54,7 @@ void register_node_type_sh_output_material() sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_material; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.cc b/source/blender/nodes/shader/nodes/node_shader_output_world.cc index 0d2cca1927d..738ef6f5be8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc @@ -41,6 +41,7 @@ void register_node_type_sh_output_world() sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = world_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_output_world; ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc index 815671b8284..bf8fbf6bcf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc @@ -34,6 +34,7 @@ void register_node_type_sh_shadertorgb() sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_eevee_shader_nodes_poll; ntype.gpu_fn = file_ns::node_shader_gpu_shadertorgb; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index 94fcdb73c78..3278907b9b8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -87,6 +87,7 @@ void register_node_type_sh_subsurface_scattering() sh_node_type_base( &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = object_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_subsurface; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.initfunc = file_ns::node_shader_init_subsurface_scattering; diff --git a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc index 4a3aed67b11..738b0cf488c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc +++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc @@ -29,6 +29,7 @@ void register_node_type_sh_uvalongstroke() sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; + ntype.add_ui_poll = line_style_shader_nodes_poll; ntype.draw_buttons = file_ns::node_shader_buts_uvalongstroke; nodeRegisterType(&ntype); -- 2.30.2 From a7422f3cd79b17073a421d53d308389d9fa2cf8f Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 19 Apr 2023 07:57:46 -0600 Subject: [PATCH 05/61] deps_builder/windows: Cleanup dpcpp harvest The dpcpp folder grew from 200M to 500M with the last update due to lld being enabled and having 5 different copies in the bin folder. We do not need to ship lld so it can be safely removed. However previous harvest cleaned up the build folder before copying the libs to their final destination in output, this will no longer work, since we actually do need lld to build embree. So copy to the full build folder to output first, then remove the binaries we do not need. Embree will use the binaries in the build folder so it will be unaffected by this. --- build_files/build_environment/cmake/dpcpp.cmake | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build_files/build_environment/cmake/dpcpp.cmake b/build_files/build_environment/cmake/dpcpp.cmake index 272a360fc67..e3c8bbeee98 100644 --- a/build_files/build_environment/cmake/dpcpp.cmake +++ b/build_files/build_environment/cmake/dpcpp.cmake @@ -113,8 +113,14 @@ add_dependencies( if(BUILD_MODE STREQUAL Release AND WIN32) ExternalProject_Add_Step(external_dpcpp after_install - COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cl.exe - COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cpp.exe COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/dpcpp ${HARVEST_TARGET}/dpcpp + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cl.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cpp.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld64.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld-link.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/wasm-ld.exe ) endif() -- 2.30.2 From 599e52119f072df05d2d1ccd0bba7d385f106fe3 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Wed, 19 Apr 2023 16:27:21 +0200 Subject: [PATCH 06/61] Fix #107101: Update depsgraph on muting VSE channel Muting a VSE channel does not mute the sound, this is caused by lack of depsgraph updates for sound when mute state changed for the channel. Now fixed. Caused by ad146bd17a813fd1c40f83876141571ca221642a Pull Request: https://projects.blender.org/blender/blender/pulls/107116 --- source/blender/makesrna/intern/rna_sequencer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 1cad3b2bb75..6013f09ddbe 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1496,8 +1496,8 @@ static void rna_SequenceTimelineChannel_name_set(PointerRNA *ptr, const char *va sizeof(channel->name)); } -static void rna_SequenceTimelineChannel_mute_update(Main *UNUSED(bmain), - Scene *UNUSED(active_scene), +static void rna_SequenceTimelineChannel_mute_update(Main *bmain, + Scene *active_scene, PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; @@ -1516,6 +1516,8 @@ static void rna_SequenceTimelineChannel_mute_update(Main *UNUSED(bmain), LISTBASE_FOREACH (Sequence *, seq, seqbase) { SEQ_relations_invalidate_cache_composite(scene, seq); } + + rna_Sequence_sound_update(bmain, active_scene, ptr); } static char *rna_SeqTimelineChannel_path(const PointerRNA *ptr) -- 2.30.2 From 45c0762f1b9b04a49c59a98d30aaa61bdbbc1721 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 19 Apr 2023 16:50:46 +0200 Subject: [PATCH 07/61] Fix #107125: Entering Grease Pencil Vertex Paint mode crashes Caused by uninitialized `ToolSettings` `GpPaint` [which was later accessed in `BKE_gpencil_palette_ensure`]. Not 100% sure why `ToolSettings` `GpPaint` is properly initialized in a default startup fille, but for some files, this was not the case (as in the report) See 22462fed000d7494522f7824ede7ff9f99d2bddf for a similar commit. Now initialize `ToolSettings` `GpPaint` (alongside `GpVertexPaint`) when entering grease pencil vertex paint mode. Should probably go into LTS releases as well. Pull Request: https://projects.blender.org/blender/blender/pulls/107131 --- source/blender/editors/gpencil_legacy/gpencil_edit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil_legacy/gpencil_edit.c b/source/blender/editors/gpencil_legacy/gpencil_edit.c index b6eb55bc937..d98615ab166 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_edit.c +++ b/source/blender/editors/gpencil_legacy/gpencil_edit.c @@ -725,7 +725,9 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_VERTEX_GPENCIL) { - /* Be sure we have brushes. */ + /* Be sure we have brushes. + * Need Draw as well (used for Palettes). */ + BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); const bool reset_mode = (ts->gp_vertexpaint->paint.brush == NULL); -- 2.30.2 From d5757a0a100163d9490e9a8084f177faac67c39e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 19 Apr 2023 18:18:05 +0200 Subject: [PATCH 08/61] Cycles: re-enable AMD GPU binaries on Windows Using the new HIP SDK 5.5 that includes a fix for the compiler bug. This also enables the light tree. For Linux the binaries are still disabled. ROCm 5.5 is planned to include the same fix but not released yet. When that happens we should be able to enable Linux as well. Ref #104786 Fix #104085 Pull Request: https://projects.blender.org/blender/blender/pulls/107098 --- CMakeLists.txt | 3 ++- build_files/cmake/Modules/FindHIP.cmake | 22 ++++++++++++++----- .../cmake/config/blender_release.cmake | 2 +- build_files/config/pipeline_config.yaml | 2 +- intern/cycles/blender/addon/properties.py | 20 ++++++++--------- intern/cycles/cmake/external_libs.cmake | 20 ++++++++++------- intern/cycles/device/hip/device.cpp | 2 +- intern/cycles/kernel/types.h | 3 +-- 8 files changed, 45 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 020c95cee0c..8cd3afc2e12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -521,7 +521,8 @@ endif() if(NOT APPLE) option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON) option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF) - set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for") + # Radeon VII (gfx906) not currently working with HIP SDK, so left out of the list. + set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for") mark_as_advanced(WITH_CYCLES_DEVICE_HIP) mark_as_advanced(CYCLES_HIP_BINARIES_ARCH) endif() diff --git a/build_files/cmake/Modules/FindHIP.cmake b/build_files/cmake/Modules/FindHIP.cmake index 9625a91d280..c6358c9ef7b 100644 --- a/build_files/cmake/Modules/FindHIP.cmake +++ b/build_files/cmake/Modules/FindHIP.cmake @@ -37,18 +37,24 @@ elseif(HIP_HIPCC_EXECUTABLE) set(HIP_VERSION_MINOR 0) set(HIP_VERSION_PATCH 0) + if(WIN32) + set(_hipcc_executable ${HIP_HIPCC_EXECUTABLE}.bat) + else() + set(_hipcc_executable ${HIP_HIPCC_EXECUTABLE}) + endif() + # Get version from the output. - execute_process(COMMAND ${HIP_HIPCC_EXECUTABLE} --version - OUTPUT_VARIABLE HIP_VERSION_RAW + execute_process(COMMAND ${_hipcc_executable} --version + OUTPUT_VARIABLE _hip_version_raw ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) # Parse parts. - if(HIP_VERSION_RAW MATCHES "HIP version: .*") + if(_hip_version_raw MATCHES "HIP version: .*") # Strip the HIP prefix and get list of individual version components. string(REGEX REPLACE ".*HIP version: ([.0-9]+).*" "\\1" - HIP_SEMANTIC_VERSION "${HIP_VERSION_RAW}") + HIP_SEMANTIC_VERSION "${_hip_version_raw}") string(REPLACE "." ";" HIP_VERSION_PARTS "${HIP_SEMANTIC_VERSION}") list(LENGTH HIP_VERSION_PARTS NUM_HIP_VERSION_PARTS) @@ -71,7 +77,13 @@ elseif(HIP_HIPCC_EXECUTABLE) # Construct full semantic version. set(HIP_VERSION "${HIP_VERSION_MAJOR}.${HIP_VERSION_MINOR}.${HIP_VERSION_PATCH}") - unset(HIP_VERSION_RAW) + unset(_hip_version_raw) + unset(_hipcc_executable) else() set(HIP_FOUND FALSE) endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(HIP + REQUIRED_VARS HIP_HIPCC_EXECUTABLE + VERSION_VAR HIP_VERSION) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index bcee440adcb..61ec88c879e 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -82,7 +82,7 @@ if(NOT APPLE) set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE) set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE) - set(WITH_CYCLES_HIP_BINARIES OFF CACHE BOOL "" FORCE) + set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE) set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE) endif() diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml index 11a095e10ba..832a9b119e6 100644 --- a/build_files/config/pipeline_config.yaml +++ b/build_files/config/pipeline_config.yaml @@ -9,7 +9,7 @@ buildbot: cuda11: version: '11.4.1' hip: - version: '5.3.22480' + version: '5.5.30571' optix: version: '7.3.0' ocloc: diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 79356c1c67e..9d16b4983a7 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1683,16 +1683,16 @@ class CyclesPreferences(bpy.types.AddonPreferences): col.label(text=iface_("and NVIDIA driver version %s or newer") % driver_version, icon='BLANK1', translate=False) elif device_type == 'HIP': - if True: - col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1') - else: - import sys - if sys.platform[:3] == "win": - driver_version = "21.Q4" - col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') - col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version, - icon='BLANK1', translate=False) - elif sys.platform.startswith("linux"): + import sys + if sys.platform[:3] == "win": + driver_version = "21.Q4" + col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') + col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version, + icon='BLANK1', translate=False) + elif sys.platform.startswith("linux"): + if True: + col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1') + else: driver_version = "22.10" col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1') col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1', diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index b10aeec8bdf..536639b3154 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -42,15 +42,19 @@ endif() ########################################################################### if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) - set(WITH_CYCLES_HIP_BINARIES OFF) - message(STATUS "HIP temporarily disabled due to compiler bugs") + if(UNIX) + # Disabled until there is a HIP 5.5 release for Linux. + set(WITH_CYCLES_HIP_BINARIES OFF) + message(STATUS "HIP temporarily disabled due to compiler bugs") + else() + # Need at least HIP 5.5 to solve compiler bug affecting the kernel. + find_package(HIP 5.5.0) + set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) - # find_package(HIP) - # set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) - - # if(HIP_FOUND) - # message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") - # endif() + if(HIP_FOUND) + message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") + endif() + endif() endif() if(NOT WITH_HIP_DYNLOAD) diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp index d3566347834..c853114cea7 100644 --- a/intern/cycles/device/hip/device.cpp +++ b/intern/cycles/device/hip/device.cpp @@ -137,7 +137,7 @@ void device_hip_info(vector &devices) info.num = num; info.has_nanovdb = true; - info.has_light_tree = false; + info.has_light_tree = true; info.denoisers = 0; info.has_gpu_queue = true; diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 58c3d95deb5..4fa379e4b15 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -79,9 +79,8 @@ CCL_NAMESPACE_BEGIN #define __VISIBILITY_FLAG__ #define __VOLUME__ -/* TODO: solve internal compiler errors and enable light tree on HIP. */ /* TODO: solve internal compiler perf issue and enable light tree on Metal/AMD. */ -#if defined(__KERNEL_HIP__) || defined(__KERNEL_METAL_AMD__) +#if defined(__KERNEL_METAL_AMD__) # undef __LIGHT_TREE__ #endif -- 2.30.2 From 98ccee78fe85cbe997624b1c52dd79aaa6b904e3 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 12:35:09 -0400 Subject: [PATCH 09/61] Geometry Nodes: Slightly optimize mesh to curve node Avoid copying the selected edges if all edges are selected, and parallelize gathering the selection otherwise. Also use `int2` instead of `std::pair`. In simple test file I observed an approximate 10% FPS improvement, though in real world cases the impact is probably much smaller. --- .../geometry/intern/mesh_to_curve_convert.cc | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 14dfcc5bacb..a68e0489494 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -19,7 +19,7 @@ namespace blender::geometry { bke::CurvesGeometry create_curve_from_vert_indices( - const Mesh &mesh, + const bke::AttributeAccessor &mesh_attributes, const Span vert_indices, const Span curve_offsets, const IndexRange cyclic_curves, @@ -30,7 +30,6 @@ bke::CurvesGeometry create_curve_from_vert_indices( curves.offsets_for_write().last() = vert_indices.size(); curves.fill_curve_types(CURVE_TYPE_POLY); - const bke::AttributeAccessor mesh_attributes = mesh.attributes(); bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write(); if (!cyclic_curves.is_empty()) { @@ -82,7 +81,7 @@ struct CurveFromEdgesOutput { }; static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, - Span> edges) + const Span edges) { Vector vert_indices; vert_indices.reserve(edges.size()); @@ -90,9 +89,9 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, /* Compute the number of edges connecting to each vertex. */ Array neighbor_count(verts_num, 0); - for (const std::pair &edge : edges) { - neighbor_count[edge.first]++; - neighbor_count[edge.second]++; + for (const int2 &edge : edges) { + neighbor_count[edge[0]]++; + neighbor_count[edge[1]]++; } /* Compute an offset into the array of neighbor edges based on the counts. */ @@ -108,8 +107,8 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, /* Calculate the indices of each vertex's neighboring edges. */ Array neighbors(edges.size() * 2); for (const int i : edges.index_range()) { - const int v1 = edges[i].first; - const int v2 = edges[i].second; + const int v1 = edges[i][0]; + const int v2 = edges[i][1]; neighbors[neighbor_offsets[v1] + used_slots[v1]] = v2; neighbors[neighbor_offsets[v2] + used_slots[v2]] = v1; used_slots[v1]++; @@ -199,19 +198,17 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(const int verts_num, return {std::move(vert_indices), std::move(curve_offsets), cyclic_curves}; } -/** - * Get a separate array of the indices for edges in a selection (a boolean attribute). - * This helps to make the above algorithm simpler by removing the need to check for selection - * in many places. - */ -static Vector> get_selected_edges(const Mesh &mesh, const IndexMask selection) +static bke::CurvesGeometry edges_to_curves_convert( + const Mesh &mesh, + const Span edges, + const bke::AnonymousAttributePropagationInfo &propagation_info) { - Vector> selected_edges; - const Span edges = mesh.edges(); - for (const int i : selection) { - selected_edges.append({edges[i][0], edges[i][1]}); - } - return selected_edges; + CurveFromEdgesOutput output = edges_to_curve_point_indices(mesh.totvert, edges); + return create_curve_from_vert_indices(mesh.attributes(), + output.vert_indices, + output.curve_offsets, + output.cyclic_curves, + propagation_info); } bke::CurvesGeometry mesh_to_curve_convert( @@ -219,11 +216,13 @@ bke::CurvesGeometry mesh_to_curve_convert( const IndexMask selection, const bke::AnonymousAttributePropagationInfo &propagation_info) { - Vector> selected_edges = get_selected_edges(mesh, selection); - CurveFromEdgesOutput output = edges_to_curve_point_indices(mesh.totvert, selected_edges); - - return create_curve_from_vert_indices( - mesh, output.vert_indices, output.curve_offsets, output.cyclic_curves, propagation_info); + const Span edges = mesh.edges(); + if (selection.size() == edges.size()) { + return edges_to_curves_convert(mesh, edges, propagation_info); + } + Array selected_edges(selection.size()); + array_utils::gather(edges, selection, selected_edges.as_mutable_span()); + return edges_to_curves_convert(mesh, selected_edges, propagation_info); } } // namespace blender::geometry -- 2.30.2 From 097b9c5a366f218ec3c078fad0bd312c26b8a0c9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 13:05:08 -0400 Subject: [PATCH 10/61] Fix: Build error after last commit Also fix fallthrough warnings --- .../compositor/realtime_compositor/intern/shader_node.cc | 3 +++ source/blender/geometry/GEO_mesh_to_curve.hh | 2 +- .../nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/blender/compositor/realtime_compositor/intern/shader_node.cc b/source/blender/compositor/realtime_compositor/intern/shader_node.cc index 4ac83c010b2..e3c0b032dd7 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_node.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_node.cc @@ -98,6 +98,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } case SOCK_VECTOR: { @@ -115,6 +116,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } case SOCK_RGBA: { @@ -131,6 +133,7 @@ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket return; default: BLI_assert_unreachable(); + return; } } default: diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh index 17eb311ccc2..d52246db724 100644 --- a/source/blender/geometry/GEO_mesh_to_curve.hh +++ b/source/blender/geometry/GEO_mesh_to_curve.hh @@ -25,7 +25,7 @@ bke::CurvesGeometry mesh_to_curve_convert( const bke::AnonymousAttributePropagationInfo &propagation_info); bke::CurvesGeometry create_curve_from_vert_indices( - const Mesh &mesh, + const bke::AttributeAccessor &mesh_attributes, Span vert_indices, Span curve_offsets, IndexRange cyclic_curves, diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc index 772c4721284..ef1995e72b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc @@ -61,7 +61,7 @@ static Curves *edge_paths_to_curves_convert( return nullptr; } Curves *curves_id = bke::curves_new_nomain(geometry::create_curve_from_vert_indices( - mesh, vert_indices, curve_offsets, IndexRange(0), propagation_info)); + mesh.attributes(), vert_indices, curve_offsets, IndexRange(0), propagation_info)); return curves_id; } -- 2.30.2 From acb34c718e0d2c423c920b5ac52684a4d18fa824 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 19 Apr 2023 19:43:15 +0200 Subject: [PATCH 11/61] Fix #107120: Small fixes to OS File Operations Small fixes to recent file operations changes. FileOperations enum starting with zero results in bad behavior with EnumPropertyItem. Typo fix. Pull Request: https://projects.blender.org/blender/blender/pulls/107138 --- source/blender/blenlib/BLI_fileops.h | 2 +- source/blender/editors/space_file/file_ops.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index e0c4bda6747..a4f1eef647c 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -118,7 +118,7 @@ ENUM_OPERATORS(eFileAttributes, FILE_ATTR_HARDLINK); * \{ */ typedef enum FileExternalOperation { - FILE_EXTERNAL_OPERATION_OPEN = 0, + FILE_EXTERNAL_OPERATION_OPEN = 1, FILE_EXTERNAL_OPERATION_FOLDER_OPEN, /* Following are Windows-only: */ FILE_EXTERNAL_OPERATION_EDIT, diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 4aa53f952cc..a9c041fb505 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1832,7 +1832,7 @@ static int file_external_operation_exec(bContext *C, wmOperator *op) #endif BKE_reportf( - op->reports, RPT_ERROR, "Failure to perform exernal file operation on \"%s\"", filepath); + op->reports, RPT_ERROR, "Failure to perform external file operation on \"%s\"", filepath); WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT); return OPERATOR_CANCELLED; } @@ -1869,7 +1869,7 @@ void FILE_OT_external_operation(wmOperatorType *ot) RNA_def_enum(ot->srna, "operation", file_external_operation, - 0, + FILE_EXTERNAL_OPERATION_OPEN, "Operation", "Operation to perform on the file or path"); } -- 2.30.2 From 199c7da06dd3f24cbd58c7ad0de0cc340864c662 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 19 Apr 2023 19:55:26 +0200 Subject: [PATCH 12/61] Assets: Do Not Show Blank Read-Only Metadata Do not show asset metadata "description", "license", "copyright", or "author" if they are empty AND read-only, since they can't be edited and contain no useful information to show. Pull Request: https://projects.blender.org/blender/blender/pulls/105812 --- scripts/startup/bl_ui/space_filebrowser.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/startup/bl_ui/space_filebrowser.py b/scripts/startup/bl_ui/space_filebrowser.py index e52d380f67e..df13bb26e0c 100644 --- a/scripts/startup/bl_ui/space_filebrowser.py +++ b/scripts/startup/bl_ui/space_filebrowser.py @@ -706,6 +706,15 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): bl_label = "Asset Metadata" bl_options = {'HIDE_HEADER'} + @staticmethod + def metadata_prop(layout, asset_data, propname): + """ + Only display properties that are either set or can be modified (i.e. the + asset is in the current file). Empty, non-editable fields are not really useful. + """ + if getattr(asset_data, propname) or not asset_data.is_property_readonly(propname): + layout.prop(asset_data, propname) + def draw(self, context): layout = self.layout wm = context.window_manager @@ -745,10 +754,11 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): row.prop(wm, "asset_path_dummy", text="Source", icon='CURRENT_FILE' if is_local_asset else 'NONE') row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS') - layout.prop(asset_file_handle.asset_data, "description") - layout.prop(asset_file_handle.asset_data, "license") - layout.prop(asset_file_handle.asset_data, "copyright") - layout.prop(asset_file_handle.asset_data, "author") + asset_data = asset_file_handle.asset_data + self.metadata_prop(layout, asset_data, "description") + self.metadata_prop(layout, asset_data, "license") + self.metadata_prop(layout, asset_data, "copyright") + self.metadata_prop(layout, asset_data, "author") class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): -- 2.30.2 From c6d4de9e49db1cb9b7256aa06f283100fb86cad6 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Wed, 19 Apr 2023 12:40:50 -0700 Subject: [PATCH 13/61] Render: Fix crash in baking corner_edges was being passed to a function that expected corner_verts. --- source/blender/render/intern/texture_margin.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 8b1175a06c8..309d9c36b04 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -476,11 +476,12 @@ static void generate_margin(ImBuf *ibuf, const int edges_num, const OffsetIndices polys, const Span corner_edges, + const Span corner_verts, const Span mloopuv, const float uv_offset[2]) { Array looptris(poly_to_tri_count(polys.size(), corner_edges.size())); - bke::mesh::looptris_calc(vert_positions, polys, corner_edges, looptris); + bke::mesh::looptris_calc(vert_positions, polys, corner_verts, looptris); TextureMarginMap map(ibuf->x, ibuf->y, uv_offset, edges_num, polys, corner_edges, mloopuv); @@ -563,6 +564,7 @@ void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf, mesh->totedge, mesh->polys(), mesh->corner_edges(), + mesh->corner_verts(), {mloopuv, mesh->totloop}, uv_offset); } @@ -581,6 +583,7 @@ void RE_generate_texturemargin_adjacentfaces_dm( dm->getNumEdges(dm), blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1), {dm->getCornerEdgeArray(dm), dm->getNumLoops(dm)}, + {dm->getCornerVertArray(dm), dm->getNumLoops(dm)}, {mloopuv, dm->getNumLoops(dm)}, uv_offset); } -- 2.30.2 From 9344deed8981cbb1d8ac9488b552708083beae12 Mon Sep 17 00:00:00 2001 From: zanqdo Date: Wed, 19 Apr 2023 21:52:20 +0200 Subject: [PATCH 14/61] UI: Change the name of Invert nodes to Invert Color The nodes for inverting a color are named simply Invert, which begs the question: invert what? This patch changes the naming for the node in Shading, Texture and Compositing nodes to *Invert Color* This matches the naming of other color dedicated nodes like Separate Color or Combine Color Pull Request: https://projects.blender.org/blender/blender/pulls/106750 --- source/blender/nodes/NOD_static_types.h | 6 +++--- .../blender/nodes/composite/nodes/node_composite_invert.cc | 2 +- source/blender/nodes/shader/nodes/node_shader_invert.cc | 2 +- source/blender/nodes/texture/nodes/node_texture_invert.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index c4f7541e4bb..a43f767bda2 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -41,7 +41,7 @@ DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP" DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "Perform math operations") DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "Perform vector math operation") DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "") -DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "Invert a color, producing a negative") +DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert Color", "Invert a color, producing a negative") DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "Split a color into its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "Generate a color from its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value","Apply a color transformation in the HSV color model") @@ -178,7 +178,7 @@ DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" ) DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Brightness/Contrast","" ) DefNode(CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" ) -DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" ) +DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert Color", "" ) DefNode(CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" ) DefNode(CompositorNode, CMP_NODE_CROP, def_cmp_crop, "CROP", Crop, "Crop", "" ) DefNode(CompositorNode, CMP_NODE_DBLUR, def_cmp_dblur, "DBLUR", DBlur, "Directional Blur", "" ) @@ -234,7 +234,7 @@ DefNode(TextureNode, TEX_NODE_RGBTOBW, 0, "RGBTOB DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "Color Ramp", "" ) DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" ) DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" ) -DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" ) +DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert Color", "" ) DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value", "" ) DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" ) DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" ) diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc index 58732cb80f5..76cfbbc9ecd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_invert.cc +++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc @@ -93,7 +93,7 @@ void register_node_type_cmp_invert() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::cmp_node_invert_declare; ntype.draw_buttons = file_ns::node_composit_buts_invert; ntype.initfunc = file_ns::node_composit_init_invert; diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc index 3a3cebde7e0..32161030bad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.cc +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -33,7 +33,7 @@ void register_node_type_sh_invert() static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::node_declare; ntype.gpu_fn = file_ns::gpu_shader_invert; diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.cc b/source/blender/nodes/texture/nodes/node_texture_invert.cc index 9253a2701d3..46e29a63b3a 100644 --- a/source/blender/nodes/texture/nodes/node_texture_invert.cc +++ b/source/blender/nodes/texture/nodes/node_texture_invert.cc @@ -47,7 +47,7 @@ void register_node_type_tex_invert() { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert Color", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); ntype.exec_fn = exec; -- 2.30.2 From 60bb57663a7f1cf7f3e6468fcad15868027b94f9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 15:15:18 -0400 Subject: [PATCH 15/61] Cleanup: IO: Separate creating mesh and adding to Main Create a "nomain" mesh when converting intermediate representations to a Mesh, meaning those areas don't have to know about data-block names or the main database, and also that the boilerplate of adding attributes individually can be avoided. The attribute arrays aren't copied here, so the performance should be unaffected. --- source/blender/io/ply/importer/ply_import.cc | 10 ++--- .../io/ply/importer/ply_import_mesh.cc | 39 +++++++------------ .../io/ply/importer/ply_import_mesh.hh | 5 +-- source/blender/io/stl/importer/stl_import.cc | 14 +++---- .../stl/importer/stl_import_ascii_reader.cc | 6 +-- .../stl/importer/stl_import_ascii_reader.hh | 2 +- .../stl/importer/stl_import_binary_reader.cc | 6 +-- .../stl/importer/stl_import_binary_reader.hh | 2 +- .../io/stl/importer/stl_import_mesh.cc | 15 +------ .../io/stl/importer/stl_import_mesh.hh | 2 +- 10 files changed, 38 insertions(+), 63 deletions(-) diff --git a/source/blender/io/ply/importer/ply_import.cc b/source/blender/io/ply/importer/ply_import.cc index a17aa51bf23..cee1ad6d469 100644 --- a/source/blender/io/ply/importer/ply_import.cc +++ b/source/blender/io/ply/importer/ply_import.cc @@ -203,21 +203,19 @@ void importer_main(Main *bmain, } /* Create mesh and do all prep work. */ - Mesh *mesh = BKE_mesh_add(bmain, ob_name); + Mesh *mesh_in_main = BKE_mesh_add(bmain, ob_name); BKE_view_layer_base_deselect_all(scene, view_layer); LayerCollection *lc = BKE_layer_collection_get_active(view_layer); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); - BKE_mesh_assign_object(bmain, obj, mesh); + BKE_mesh_assign_object(bmain, obj, mesh_in_main); BKE_collection_object_add(bmain, lc->collection, obj); BKE_view_layer_synced_ensure(scene, view_layer); Base *base = BKE_view_layer_base_find(view_layer, obj); BKE_view_layer_base_select_and_set_active(view_layer, base); /* Stuff ply data into the mesh. */ - Mesh *temp_val = convert_ply_to_mesh(*data, mesh, import_params); - if (import_params.merge_verts && temp_val != mesh) { - BKE_mesh_nomain_to_mesh(temp_val, mesh, obj); - } + Mesh *mesh = convert_ply_to_mesh(*data, import_params); + BKE_mesh_nomain_to_mesh(mesh, mesh_in_main, obj); /* Object matrix and finishing up. */ float global_scale = import_params.global_scale; diff --git a/source/blender/io/ply/importer/ply_import_mesh.cc b/source/blender/io/ply/importer/ply_import_mesh.cc index bc2b67dbf21..342147f06ea 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.cc +++ b/source/blender/io/ply/importer/ply_import_mesh.cc @@ -7,6 +7,7 @@ #include "BKE_attribute.h" #include "BKE_attribute.hh" #include "BKE_customdata.h" +#include "BKE_lib_id.h" #include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" @@ -17,23 +18,18 @@ #include "ply_import_mesh.hh" namespace blender::io::ply { -Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ms) +Mesh *convert_ply_to_mesh(PlyData &data, const PLYImportParams ¶ms) { + Mesh *mesh = BKE_mesh_new_nomain( + data.vertices.size(), data.edges.size(), data.face_vertices.size(), data.face_sizes.size()); - /* Add vertices to the mesh. */ - mesh->totvert = int(data.vertices.size()); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(data.vertices); bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); if (!data.edges.is_empty()) { - mesh->totedge = int(data.edges.size()); - CustomData_add_layer_named( - &mesh->edata, CD_PROP_INT32_2D, CD_CONSTRUCT, mesh->totedge, ".edge_verts"); MutableSpan edges = mesh->edges_for_write(); - for (int i = 0; i < mesh->totedge; i++) { + for (const int i : data.edges.index_range()) { int32_t v1 = data.edges[i].first; int32_t v2 = data.edges[i].second; if (v1 >= mesh->totvert) { @@ -50,18 +46,12 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ /* Add faces to the mesh. */ if (!data.face_sizes.is_empty()) { - /* Create poly and loop layers. */ - mesh->totpoly = int(data.face_sizes.size()); - mesh->totloop = int(data.face_vertices.size()); - BKE_mesh_poly_offsets_ensure_alloc(mesh); - CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh->totloop, ".corner_vert"); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); /* Fill in face data. */ uint32_t offset = 0; - for (int i = 0; i < mesh->totpoly; i++) { + for (const int i : data.face_sizes.index_range()) { uint32_t size = data.face_sizes[i]; poly_offsets[i] = offset; for (int j = 0; j < size; j++) { @@ -83,12 +73,12 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ attributes.lookup_or_add_for_write_span("Col", ATTR_DOMAIN_POINT); if (params.vertex_colors == PLY_VERTEX_COLOR_SRGB) { - for (int i = 0; i < data.vertex_colors.size(); i++) { + for (const int i : data.vertex_colors.index_range()) { srgb_to_linearrgb_v4(colors.span[i], data.vertex_colors[i]); } } else { - for (int i = 0; i < data.vertex_colors.size(); i++) { + for (const int i : data.vertex_colors.index_range()) { copy_v4_v4(colors.span[i], data.vertex_colors[i]); } } @@ -101,7 +91,7 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ if (!data.uv_coordinates.is_empty()) { bke::SpanAttributeWriter uv_map = attributes.lookup_or_add_for_write_only_span( "UVMap", ATTR_DOMAIN_CORNER); - for (size_t i = 0; i < data.face_vertices.size(); i++) { + for (const int i : data.face_vertices.index_range()) { uv_map.span[i] = data.uv_coordinates[data.face_vertices[i]]; } uv_map.finish(); @@ -116,17 +106,18 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ mesh, reinterpret_cast(data.vertex_normals.data())); } + BKE_mesh_smooth_flag_set(mesh, false); + /* Merge all vertices on the same location. */ if (params.merge_verts) { - std::optional return_value = blender::geometry::mesh_merge_by_distance_all( + std::optional merged_mesh = blender::geometry::mesh_merge_by_distance_all( *mesh, IndexMask(mesh->totvert), 0.0001f); - if (return_value.has_value()) { - mesh = return_value.value(); + if (merged_mesh) { + BKE_id_free(nullptr, &mesh->id); + mesh = *merged_mesh; } } - BKE_mesh_smooth_flag_set(mesh, false); - return mesh; } } // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_mesh.hh b/source/blender/io/ply/importer/ply_import_mesh.hh index 7dddff4f41a..e1d057f4358 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.hh +++ b/source/blender/io/ply/importer/ply_import_mesh.hh @@ -13,9 +13,8 @@ namespace blender::io::ply { /** * Converts the #PlyData data-structure to a mesh. - * \param data: The PLY data. - * \return The mesh that can be used inside blender. + * \return A new mesh that can be used inside blender. */ -Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ms); +Mesh *convert_ply_to_mesh(PlyData &data, const PLYImportParams ¶ms); } // namespace blender::io::ply diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc index 9ca002b71e8..628b3603a1f 100644 --- a/source/blender/io/stl/importer/stl_import.cc +++ b/source/blender/io/stl/importer/stl_import.cc @@ -78,13 +78,9 @@ void importer_main(Main *bmain, BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX); BLI_path_extension_strip(ob_name); - Mesh *mesh = nullptr; - if (is_ascii_stl) { - mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal); - } - else { - mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal); - } + Mesh *mesh = is_ascii_stl ? + read_stl_ascii(import_params.filepath, import_params.use_facet_normal) : + read_stl_binary(file, import_params.use_facet_normal); if (mesh == nullptr) { fprintf(stderr, "STL Importer: Failed to import mesh '%s'\n", import_params.filepath); @@ -99,10 +95,12 @@ void importer_main(Main *bmain, BKE_mesh_validate(mesh, verbose_validate, false); } + Mesh *mesh_in_main = BKE_mesh_add(bmain, ob_name); + BKE_mesh_nomain_to_mesh(mesh, mesh_in_main, nullptr); BKE_view_layer_base_deselect_all(scene, view_layer); LayerCollection *lc = BKE_layer_collection_get_active(view_layer); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); - BKE_mesh_assign_object(bmain, obj, mesh); + BKE_mesh_assign_object(bmain, obj, mesh_in_main); BKE_collection_object_add(bmain, lc->collection, obj); BKE_view_layer_synced_ensure(scene, view_layer); Base *base = BKE_view_layer_base_find(view_layer, obj); diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc index 8bfe4924cc5..e213fa94bf0 100644 --- a/source/blender/io/stl/importer/stl_import_ascii_reader.cc +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc @@ -111,13 +111,13 @@ static inline void parse_float3(StringBuffer &buf, float out[3]) } } -Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals) +Mesh *read_stl_ascii(const char *filepath, const bool use_custom_normals) { size_t buffer_len; void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len); if (buffer == nullptr) { fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath); - return BKE_mesh_add(bmain, mesh_name); + return nullptr; } BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); }); @@ -154,7 +154,7 @@ Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool us } } - return stl_mesh.to_mesh(bmain, mesh_name); + return stl_mesh.to_mesh(); } } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh index e8aed911bf1..9998f111eda 100644 --- a/source/blender/io/stl/importer/stl_import_ascii_reader.hh +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh @@ -30,6 +30,6 @@ namespace blender::io::stl { -Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals); +Mesh *read_stl_ascii(const char *filepath, bool use_custom_normals); } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc index 26d9e3406e7..d6b6aa1b33f 100644 --- a/source/blender/io/stl/importer/stl_import_binary_reader.cc +++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc @@ -29,7 +29,7 @@ struct STLBinaryTriangle { }; #pragma pack(pop) -Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals) +Mesh *read_stl_binary(FILE *file, const bool use_custom_normals) { const int chunk_size = 1024; uint32_t num_tris = 0; @@ -40,7 +40,7 @@ Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_ } if (num_tris == 0) { - return BKE_mesh_add(bmain, mesh_name); + return BKE_mesh_new_nomain(0, 0, 0, 0); } Array tris_buf(chunk_size); @@ -57,7 +57,7 @@ Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_ } } - return stl_mesh.to_mesh(bmain, mesh_name); + return stl_mesh.to_mesh(); } } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh index 71d5dbbbe58..729da94f6bc 100644 --- a/source/blender/io/stl/importer/stl_import_binary_reader.hh +++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh @@ -26,6 +26,6 @@ namespace blender::io::stl { const size_t BINARY_HEADER_SIZE = 80; const size_t BINARY_STRIDE = 12 * 4 + 2; -Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals); +Mesh *read_stl_binary(FILE *file, bool use_custom_normals); } // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index 1c19a96cc0d..de944720323 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -60,7 +60,7 @@ void STLMeshHelper::add_triangle(const float3 &a, } } -Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) +Mesh *STLMeshHelper::to_mesh() { if (degenerate_tris_num_ > 0) { std::cout << "STL Importer: " << degenerate_tris_num_ << " degenerate triangles were removed" @@ -71,21 +71,10 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) << std::endl; } - Mesh *mesh = BKE_mesh_add(bmain, mesh_name); - /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */ - id_us_min(&mesh->id); + Mesh *mesh = BKE_mesh_new_nomain(verts_.size(), 0, tris_.size() * 3, tris_.size()); - mesh->totvert = verts_.size(); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(verts_); - mesh->totpoly = tris_.size(); - mesh->totloop = tris_.size() * 3; - BKE_mesh_poly_offsets_ensure_alloc(mesh); - CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totloop, ".corner_vert"); - MutableSpan poly_offsets = mesh->poly_offsets_for_write(); threading::parallel_for(poly_offsets.index_range(), 4096, [&](const IndexRange range) { for (const int i : range) { diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh index 658d42ca7a7..7d6ae101b09 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.hh +++ b/source/blender/io/stl/importer/stl_import_mesh.hh @@ -65,7 +65,7 @@ class STLMeshHelper { const float3 &b, const float3 &c, const float3 &custom_normal); - Mesh *to_mesh(Main *bmain, char *mesh_name); + Mesh *to_mesh(); }; } // namespace blender::io::stl -- 2.30.2 From 10d175e223561e864f39286041478e3931a4b178 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 15:28:53 -0400 Subject: [PATCH 16/61] Cleanup: Use consistent argument order for mesh creation functions The typical order is vertex, edge, face(polygon), corner(loop), but in these three functions polys and loops were reversed. Also use more typical "num" variable names rather than "len" --- source/blender/blenkernel/BKE_mesh.h | 14 ++--- .../intern/curve_to_mesh_convert.cc | 2 +- source/blender/blenkernel/intern/fluid.cc | 4 +- source/blender/blenkernel/intern/mesh.cc | 58 ++++++++++--------- .../blenkernel/intern/mesh_boolean_convert.cc | 2 +- .../blender/blenkernel/intern/mesh_convert.cc | 2 +- .../blender/blenkernel/intern/mesh_mirror.cc | 2 +- .../blenkernel/intern/mesh_remesh_voxel.cc | 7 +-- .../blender/blenkernel/intern/subdiv_mesh.cc | 2 +- .../blenkernel/intern/volume_to_mesh.cc | 2 +- .../editors/sculpt_paint/paint_mask.cc | 2 +- .../geometry/intern/mesh_merge_by_distance.cc | 2 +- .../geometry/intern/mesh_primitive_cuboid.cc | 2 +- .../geometry/intern/realize_instances.cc | 2 +- .../io/alembic/intern/abc_reader_mesh.cc | 2 +- .../io/ply/importer/ply_import_mesh.cc | 2 +- .../io/stl/importer/stl_import_mesh.cc | 2 +- .../blender/io/usd/intern/usd_reader_mesh.cc | 2 +- .../blender/io/usd/intern/usd_reader_shape.cc | 2 +- .../wavefront_obj/importer/obj_import_mesh.cc | 2 +- source/blender/modifiers/intern/MOD_array.cc | 2 +- source/blender/modifiers/intern/MOD_build.cc | 2 +- source/blender/modifiers/intern/MOD_mask.cc | 4 +- source/blender/modifiers/intern/MOD_ocean.cc | 2 +- .../modifiers/intern/MOD_particleinstance.cc | 2 +- source/blender/modifiers/intern/MOD_remesh.cc | 2 +- source/blender/modifiers/intern/MOD_screw.cc | 2 +- .../modifiers/intern/MOD_solidify_extrude.cc | 4 +- .../intern/MOD_solidify_nonmanifold.cc | 2 +- .../geometry/nodes/node_geo_convex_hull.cc | 4 +- .../geometry/nodes/node_geo_curve_fill.cc | 2 +- .../nodes/node_geo_delete_geometry.cc | 8 +-- .../geometry/nodes/node_geo_dual_mesh.cc | 2 +- .../nodes/node_geo_duplicate_elements.cc | 2 +- .../nodes/node_geo_mesh_primitive_circle.cc | 4 +- .../nodes/node_geo_mesh_primitive_cone.cc | 2 +- .../nodes/node_geo_mesh_primitive_grid.cc | 4 +- .../node_geo_mesh_primitive_uv_sphere.cc | 4 +- .../geometry/nodes/node_geo_volume_to_mesh.cc | 2 +- source/blender/render/intern/multires_bake.cc | 2 +- 40 files changed, 89 insertions(+), 84 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 6e909a63b5b..0a5e3e0f6c6 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -158,15 +158,15 @@ void BKE_mesh_ensure_skin_customdata(struct Mesh *me); /** Add poly offsets to describe faces to a new mesh. */ void BKE_mesh_poly_offsets_ensure_alloc(struct Mesh *mesh); -struct Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int loops_len, int polys_len); +struct Mesh *BKE_mesh_new_nomain(int verts_num, int edges_num, int polys_num, int loops_num); struct Mesh *BKE_mesh_new_nomain_from_template( - const struct Mesh *me_src, int verts_len, int edges_len, int loops_len, int polys_len); + const struct Mesh *me_src, int verts_num, int edges_num, int polys_num, int loops_num); struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src, - int verts_len, - int edges_len, - int tessface_len, - int loops_len, - int polys_len, + int verts_num, + int edges_num, + int tessface_num, + int polys_num, + int loops_num, struct CustomData_MeshMasks mask); void BKE_mesh_eval_delete(struct Mesh *mesh_eval); diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 45bbca42871..484ed7e71a0 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -691,7 +691,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, } Mesh *mesh = BKE_mesh_new_nomain( - offsets.vert.last(), offsets.edge.last(), offsets.loop.last(), offsets.poly.last()); + offsets.vert.last(), offsets.edge.last(), offsets.poly.last(), offsets.loop.last()); mesh->flag |= ME_AUTOSMOOTH; mesh->smoothresh = DEG2RADF(180.0f); MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/blenkernel/intern/fluid.cc b/source/blender/blenkernel/intern/fluid.cc index 88105132d83..1a3e094037d 100644 --- a/source/blender/blenkernel/intern/fluid.cc +++ b/source/blender/blenkernel/intern/fluid.cc @@ -3229,7 +3229,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, return nullptr; } - me = BKE_mesh_new_nomain(num_verts, 0, num_faces * 3, num_faces); + me = BKE_mesh_new_nomain(num_verts, 0, num_faces, num_faces * 3); if (!me) { return nullptr; } @@ -3367,7 +3367,7 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje return BKE_mesh_copy_for_eval(orgmesh, false); } - result = BKE_mesh_new_nomain(num_verts, 0, num_faces * 4, num_faces); + result = BKE_mesh_new_nomain(num_verts, 0, num_faces, num_faces * 4); float(*positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan poly_offsets = result->poly_offsets_for_write(); blender::MutableSpan corner_verts = result->corner_verts_for_write(); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 538a4806bed..9b228ace3b6 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1032,7 +1032,10 @@ static void mesh_ensure_cdlayers_primary(Mesh &mesh) } } -Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int loops_len, int polys_len) +Mesh *BKE_mesh_new_nomain(const int verts_num, + const int edges_num, + const int polys_num, + const int loops_num) { Mesh *mesh = (Mesh *)BKE_libblock_alloc( nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); @@ -1042,13 +1045,13 @@ Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int loops_len, int polys copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); + copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); - mesh->totvert = verts_len; - mesh->totedge = edges_len; - mesh->totloop = loops_len; - mesh->totpoly = polys_len; + mesh->totvert = verts_num; + mesh->totedge = edges_num; + mesh->totpoly = polys_num; + mesh->totloop = loops_num; mesh_ensure_cdlayers_primary(*mesh); BKE_mesh_poly_offsets_ensure_alloc(mesh); @@ -1112,35 +1115,35 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) } Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, - int verts_len, - int edges_len, - int tessface_len, - int loops_len, - int polys_len, - CustomData_MeshMasks mask) + const int verts_num, + const int edges_num, + const int tessface_num, + const int polys_num, + const int loops_num, + const CustomData_MeshMasks mask) { /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ - const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); + const bool do_tessface = (tessface_num || ((me_src->totface != 0) && (me_src->totpoly == 0))); Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); - me_dst->totvert = verts_len; - me_dst->totedge = edges_len; - me_dst->totface = tessface_len; - me_dst->totloop = loops_len; - me_dst->totpoly = polys_len; + me_dst->totvert = verts_num; + me_dst->totedge = edges_num; + me_dst->totpoly = polys_num; + me_dst->totloop = loops_num; + me_dst->totface = tessface_num; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); - CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); - CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); - CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); + CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_num); + CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_num); + CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_num); + CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_num); if (do_tessface) { CustomData_copy_layout( - &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); + &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_num); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1160,11 +1163,14 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, return me_dst; } -Mesh *BKE_mesh_new_nomain_from_template( - const Mesh *me_src, int verts_len, int edges_len, int loops_len, int polys_len) +Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src, + const int verts_num, + const int edges_num, + const int polys_num, + const int loops_num) { return BKE_mesh_new_nomain_from_template_ex( - me_src, verts_len, edges_len, 0, loops_len, polys_len, CD_MASK_EVERYTHING); + me_src, verts_num, edges_num, 0, polys_num, loops_num, CD_MASK_EVERYTHING); } void BKE_mesh_eval_delete(struct Mesh *mesh_eval) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index cd7d7d88982..c00ba6d5008 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -700,7 +700,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) } /* Will calculate edges later. */ Mesh *result = BKE_mesh_new_nomain_from_template( - mim.meshes[0], out_totvert, 0, out_totloop, out_totpoly); + mim.meshes[0], out_totvert, 0, out_totpoly, out_totloop); merge_vertex_loop_poly_customdata_layers(result, mim); /* Set the vertex coordinate values and other data. */ diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 2daf9fb6443..b8f06dfd244 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -113,7 +113,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba return BKE_mesh_new_nomain(0, 0, 0, 0); } - Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, totloop, totpoly); + Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, totpoly, totloop); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index d2169960c97..7ad5b5d2907 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -191,7 +191,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, const int src_loops_num = mesh->totloop; Mesh *result = BKE_mesh_new_nomain_from_template( - mesh, src_verts_num * 2, src_edges_num * 2, src_loops_num * 2, src_polys.size() * 2); + mesh, src_verts_num * 2, src_edges_num * 2, src_polys.size() * 2, src_loops_num * 2); /* Copy custom-data to original geometry. */ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, src_verts_num); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index aa0aecb676f..be66df2e7e0 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -117,7 +117,7 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh, } /* Construct the new output mesh */ - Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, qrd.out_totfaces * 4, qrd.out_totfaces); + Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, qrd.out_totfaces, qrd.out_totfaces * 4); BKE_mesh_copy_parameters(mesh, input_mesh); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); @@ -222,7 +222,7 @@ static Mesh *remesh_voxel_volume_to_mesh(const openvdb::FloatGrid::Ptr level_set *level_set_grid, vertices, tris, quads, isovalue, adaptivity, relax_disoriented_triangles); Mesh *mesh = BKE_mesh_new_nomain( - vertices.size(), 0, quads.size() * 4 + tris.size() * 3, quads.size() + tris.size()); + vertices.size(), 0, quads.size() + tris.size(), quads.size() * 4 + tris.size() * 3); MutableSpan vert_positions = mesh->vert_positions_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan mesh_corner_verts = mesh->corner_verts_for_write(); @@ -317,8 +317,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) const OffsetIndices target_polys = target->polys(); const Span target_corner_verts = target->corner_verts(); - const VArray src_face_sets = - * src_attributes.lookup(".sculpt_face_set", ATTR_DOMAIN_FACE); + const VArray src_face_sets = *src_attributes.lookup(".sculpt_face_set", ATTR_DOMAIN_FACE); if (!src_face_sets) { return; } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 9c7893d6de9..fa4a08a178d 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -532,7 +532,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex SubdivMeshContext *subdiv_context = static_cast(foreach_context->user_data); subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex( - subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask); + subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_polygons, num_loops, mask); subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices); subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags.clear(); diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index f2a7d9472a9..1836ad843b8 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -165,7 +165,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid, const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size(); const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size(); - Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, tot_loops, tot_polys); + Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, tot_polys, tot_loops); fill_mesh_from_openvdb_data(mesh_data.verts, mesh_data.tris, diff --git a/source/blender/editors/sculpt_paint/paint_mask.cc b/source/blender/editors/sculpt_paint/paint_mask.cc index 2ccfa93c5b5..6a6bc0759ad 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.cc +++ b/source/blender/editors/sculpt_paint/paint_mask.cc @@ -1135,7 +1135,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex const int trim_totverts = tot_screen_points * 2; const int trim_totpolys = (2 * (tot_screen_points - 2)) + (2 * tot_screen_points); - trim_operation->mesh = BKE_mesh_new_nomain(trim_totverts, 0, trim_totpolys * 3, trim_totpolys); + trim_operation->mesh = BKE_mesh_new_nomain(trim_totverts, 0, trim_totpolys, trim_totpolys * 3); trim_operation->true_mesh_co = static_cast( MEM_malloc_arrayN(trim_totverts, sizeof(float[3]), "mesh orco")); diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc index 53b57289f0d..ba869b10e9b 100644 --- a/source/blender/geometry/intern/mesh_merge_by_distance.cc +++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc @@ -1544,7 +1544,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh, const int result_npolys = src_polys.size() - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; Mesh *result = BKE_mesh_new_nomain_from_template( - &mesh, result_nverts, result_nedges, result_nloops, result_npolys); + &mesh, result_nverts, result_nedges, result_npolys, result_nloops); MutableSpan dst_edges = result->edges_for_write(); MutableSpan dst_poly_offsets = result->poly_offsets_for_write(); MutableSpan dst_corner_verts = result->corner_verts_for_write(); diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index fe1d466dcc3..a07c8a7268f 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -400,7 +400,7 @@ Mesh *create_cuboid_mesh(const float3 &size, { const CuboidConfig config(size, verts_x, verts_y, verts_z); - Mesh *mesh = BKE_mesh_new_nomain(config.vertex_count, 0, config.loop_count, config.poly_count); + Mesh *mesh = BKE_mesh_new_nomain(config.vertex_count, 0, config.poly_count, config.loop_count); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); MutableSpan corner_verts = mesh->corner_verts_for_write(); diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 30324dbdab1..ecf7951e149 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -1081,7 +1081,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const int tot_loops = last_task.start_indices.loop + last_mesh.totloop; const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly; - Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_loops, tot_poly); + Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_poly, tot_loops); MeshComponent &dst_component = r_realized_geometry.get_component_for_write(); dst_component.replace(dst_mesh); bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write(); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index fa8b8ea1c96..4c673260802 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -723,7 +723,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, if (topology_changed(existing_mesh, sample_sel)) { new_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions->size(), 0, face_indices->size(), face_counts->size()); + existing_mesh, positions->size(), 0, face_counts->size(), face_indices->size()); settings.read_flag |= MOD_MESHSEQ_READ_ALL; } diff --git a/source/blender/io/ply/importer/ply_import_mesh.cc b/source/blender/io/ply/importer/ply_import_mesh.cc index 342147f06ea..2a3d8df326f 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.cc +++ b/source/blender/io/ply/importer/ply_import_mesh.cc @@ -21,7 +21,7 @@ namespace blender::io::ply { Mesh *convert_ply_to_mesh(PlyData &data, const PLYImportParams ¶ms) { Mesh *mesh = BKE_mesh_new_nomain( - data.vertices.size(), data.edges.size(), data.face_vertices.size(), data.face_sizes.size()); + data.vertices.size(), data.edges.size(), data.face_sizes.size(), data.face_vertices.size()); mesh->vert_positions_for_write().copy_from(data.vertices); diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index de944720323..799fd3bdf6a 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -71,7 +71,7 @@ Mesh *STLMeshHelper::to_mesh() << std::endl; } - Mesh *mesh = BKE_mesh_new_nomain(verts_.size(), 0, tris_.size() * 3, tris_.size()); + Mesh *mesh = BKE_mesh_new_nomain(verts_.size(), 0, tris_.size(), tris_.size() * 3); mesh->vert_positions_for_write().copy_from(verts_); diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 762686331f8..79c382581e1 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -942,7 +942,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, if (topology_changed(existing_mesh, params.motion_sample_time)) { new_mesh = true; active_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions_.size(), 0, face_indices_.size(), face_counts_.size()); + existing_mesh, positions_.size(), 0, face_counts_.size(), face_indices_.size()); for (pxr::TfToken token : uv_tokens) { add_customdata_cb(active_mesh, token.GetText(), CD_PROP_FLOAT2); diff --git a/source/blender/io/usd/intern/usd_reader_shape.cc b/source/blender/io/usd/intern/usd_reader_shape.cc index d1352c3006a..32bedc3114f 100644 --- a/source/blender/io/usd/intern/usd_reader_shape.cc +++ b/source/blender/io/usd/intern/usd_reader_shape.cc @@ -179,7 +179,7 @@ Mesh *USDShapeReader::mesh_from_prim(Mesh *existing_mesh, Mesh *active_mesh = nullptr; if (!position_counts_match || !poly_counts_match) { active_mesh = BKE_mesh_new_nomain_from_template( - existing_mesh, positions.size(), 0, face_indices.size(), face_counts.size()); + existing_mesh, positions.size(), 0, face_counts.size(), face_indices.size()); } else { active_mesh = existing_mesh; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index d4869cec929..358f1e8fc24 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -48,7 +48,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain, const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()}; const int64_t tot_loops{mesh_geometry_.total_loops_}; - Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, tot_loops, tot_face_elems); + Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, tot_face_elems, tot_loops); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name.c_str()); obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str()); diff --git a/source/blender/modifiers/intern/MOD_array.cc b/source/blender/modifiers/intern/MOD_array.cc index 80ea448ed51..3174c0eafc4 100644 --- a/source/blender/modifiers/intern/MOD_array.cc +++ b/source/blender/modifiers/intern/MOD_array.cc @@ -551,7 +551,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, /* Initialize a result dm */ result = BKE_mesh_new_nomain_from_template( - mesh, result_nverts, result_nedges, result_nloops, result_npolys); + mesh, result_nverts, result_nedges, result_npolys, result_nloops); float(*result_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan result_edges = result->edges_for_write(); blender::MutableSpan result_poly_offsets = result->poly_offsets_for_write(); diff --git a/source/blender/modifiers/intern/MOD_build.cc b/source/blender/modifiers/intern/MOD_build.cc index f9533cf6b2c..63cb59f09c0 100644 --- a/source/blender/modifiers/intern/MOD_build.cc +++ b/source/blender/modifiers/intern/MOD_build.cc @@ -189,7 +189,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* now we know the number of verts, edges and faces, we can create the mesh. */ result = BKE_mesh_new_nomain_from_template( - mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), loops_dst_num, faces_dst_num); + mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash), faces_dst_num, loops_dst_num); blender::MutableSpan result_edges = result->edges_for_write(); blender::MutableSpan result_poly_offsets = result->poly_offsets_for_write(); blender::MutableSpan result_corner_verts = result->corner_verts_for_write(); diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 53da9d7b856..25bccff6670 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -702,8 +702,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, M Mesh *result = BKE_mesh_new_nomain_from_template(mesh, verts_masked_num + verts_add_num, edges_masked_num + edges_add_num, - loops_masked_num + loops_add_num, - polys_masked_num + polys_add_num); + polys_masked_num + polys_add_num, + loops_masked_num + loops_add_num); copy_masked_verts_to_new_mesh(*mesh, *result, vertex_map); if (use_interpolation) { diff --git a/source/blender/modifiers/intern/MOD_ocean.cc b/source/blender/modifiers/intern/MOD_ocean.cc index a7453756f56..06a78e81dfc 100644 --- a/source/blender/modifiers/intern/MOD_ocean.cc +++ b/source/blender/modifiers/intern/MOD_ocean.cc @@ -255,7 +255,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co gogd.sx /= gogd.rx; gogd.sy /= gogd.ry; - result = BKE_mesh_new_nomain(verts_num, 0, polys_num * 4, polys_num); + result = BKE_mesh_new_nomain(verts_num, 0, polys_num, polys_num * 4); BKE_mesh_copy_parameters_for_eval(result, mesh_orig); gogd.vert_positions = BKE_mesh_vert_positions_for_write(result); diff --git a/source/blender/modifiers/intern/MOD_particleinstance.cc b/source/blender/modifiers/intern/MOD_particleinstance.cc index 49e8bf751ae..9948f300730 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.cc +++ b/source/blender/modifiers/intern/MOD_particleinstance.cc @@ -312,7 +312,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * max_co = max[track]; } - result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxloop, maxpoly); + result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxpoly, maxloop); const blender::OffsetIndices orig_polys = mesh->polys(); const blender::Span orig_corner_verts = mesh->corner_verts(); diff --git a/source/blender/modifiers/intern/MOD_remesh.cc b/source/blender/modifiers/intern/MOD_remesh.cc index a867db11127..32589bae6e7 100644 --- a/source/blender/modifiers/intern/MOD_remesh.cc +++ b/source/blender/modifiers/intern/MOD_remesh.cc @@ -93,7 +93,7 @@ static void *dualcon_alloc_output(int totvert, int totquad) return nullptr; } - output->mesh = BKE_mesh_new_nomain(totvert, 0, 4 * totquad, totquad); + output->mesh = BKE_mesh_new_nomain(totvert, 0, totquad, 4 * totquad); output->vert_positions = BKE_mesh_vert_positions_for_write(output->mesh); output->poly_offsets = output->mesh->poly_offsets_for_write().data(); output->corner_verts = output->mesh->corner_verts_for_write().data(); diff --git a/source/blender/modifiers/intern/MOD_screw.cc b/source/blender/modifiers/intern/MOD_screw.cc index 00c850af1c2..17f21b6674e 100644 --- a/source/blender/modifiers/intern/MOD_screw.cc +++ b/source/blender/modifiers/intern/MOD_screw.cc @@ -390,7 +390,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const bool do_remove_doubles = (ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f); result = BKE_mesh_new_nomain_from_template( - mesh, int(maxVerts), int(maxEdges), int(maxPolys) * 4, int(maxPolys)); + mesh, int(maxVerts), int(maxEdges), int(maxPolys), int(maxPolys) * 4); /* The modifier doesn't support original index mapping on the edge or face domains. Remove * original index layers, since otherwise edges aren't displayed at all in wireframe view. */ CustomData_free_layers(&result->edata, CD_ORIGINDEX, result->totedge); diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.cc b/source/blender/modifiers/intern/MOD_solidify_extrude.cc index 6314ec510ca..394fb1ffead 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.cc +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.cc @@ -321,8 +321,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex result = BKE_mesh_new_nomain_from_template(mesh, int((verts_num * stride) + newVerts), int((edges_num * stride) + newEdges + rimVerts), - int((loops_num * stride) + newLoops), - int((polys_num * stride) + newPolys)); + int((polys_num * stride) + newPolys), + int((loops_num * stride) + newLoops)); float(*vert_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan edges = result->edges_for_write(); diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc index 95f72f160d9..415334056e1 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc @@ -1982,7 +1982,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, /* Create Mesh *result with proper capacity. */ result = BKE_mesh_new_nomain_from_template( - mesh, int(new_verts_num), int(new_edges_num), int(new_loops_num), int(new_polys_num)); + mesh, int(new_verts_num), int(new_edges_num), int(new_polys_num), int(new_loops_num)); float(*vert_positions)[3] = BKE_mesh_vert_positions_for_write(result); blender::MutableSpan edges = result->edges_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 9073614b262..5636a17b82d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -37,10 +37,10 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span coords) /* Create Mesh *result with proper capacity. */ Mesh *result; if (mesh) { - result = BKE_mesh_new_nomain_from_template(mesh, verts_num, edges_num, loops_num, faces_num); + result = BKE_mesh_new_nomain_from_template(mesh, verts_num, edges_num, faces_num, loops_num); } else { - result = BKE_mesh_new_nomain(verts_num, edges_num, loops_num, faces_num); + result = BKE_mesh_new_nomain(verts_num, edges_num, faces_num, loops_num); BKE_id_material_eval_ensure_default_slot(&result->id); } BKE_mesh_smooth_flag_set(result, false); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 16a56539ef9..8f563fa52ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -79,7 +79,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result &result) loop_len += face.size(); } - Mesh *mesh = BKE_mesh_new_nomain(vert_len, edge_len, loop_len, poly_len); + Mesh *mesh = BKE_mesh_new_nomain(vert_len, edge_len, poly_len, loop_len); MutableSpan positions = mesh->vert_positions_for_write(); mesh->edges_for_write().copy_from(result.edge.as_span().cast()); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 2fdb9ff8d9b..222e8ac0d75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -913,8 +913,8 @@ static void do_mesh_separation(GeometrySet &geometry_set, mesh_out = BKE_mesh_new_nomain_from_template(&mesh_in, selected_verts_num, selected_edges_num, - selected_loops_num, - selected_polys_num); + selected_polys_num, + selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map); @@ -986,7 +986,7 @@ static void do_mesh_separation(GeometrySet &geometry_set, break; } mesh_out = BKE_mesh_new_nomain_from_template( - &mesh_in, mesh_in.totvert, selected_edges_num, selected_loops_num, selected_polys_num); + &mesh_in, mesh_in.totvert, selected_edges_num, selected_polys_num, selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map); @@ -1049,7 +1049,7 @@ static void do_mesh_separation(GeometrySet &geometry_set, break; } mesh_out = BKE_mesh_new_nomain_from_template( - &mesh_in, mesh_in.totvert, mesh_in.totedge, selected_loops_num, selected_polys_num); + &mesh_in, mesh_in.totvert, mesh_in.totedge, selected_polys_num, selected_loops_num); /* Copy the selected parts of the mesh over to the new mesh. */ mesh_out->edges_for_write().copy_from(mesh_in.edges()); diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 868ffaa5521..9eb00fd9d46 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -869,7 +869,7 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, } } Mesh *mesh_out = BKE_mesh_new_nomain( - vert_positions.size(), new_edges.size(), loops.size(), loop_lengths.size()); + vert_positions.size(), new_edges.size(), loop_lengths.size(), loops.size()); BKE_mesh_smooth_flag_set(mesh_out, false); transfer_attributes(vertex_types, diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 4f7d7d49fb3..23f55a6dd25 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -512,7 +512,7 @@ static void duplicate_faces(GeometrySet &geometry_set, const OffsetIndices duplicates(offset_data); - Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, total_loops, total_polys); + Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, total_polys, total_loops); MutableSpan new_edges = new_mesh->edges_for_write(); MutableSpan new_poly_offsets = new_mesh->poly_offsets_for_write(); MutableSpan new_corner_verts = new_mesh->corner_verts_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index f846bc924e5..239077e0f44 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -110,8 +110,8 @@ static Mesh *create_circle_mesh(const float radius, { Mesh *mesh = BKE_mesh_new_nomain(circle_vert_total(fill_type, verts_num), circle_edge_total(fill_type, verts_num), - circle_corner_total(fill_type, verts_num), - circle_face_total(fill_type, verts_num)); + circle_face_total(fill_type, verts_num), + circle_corner_total(fill_type, verts_num)); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 7ea33b376ce..6ba771768f5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -704,7 +704,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, } Mesh *mesh = BKE_mesh_new_nomain( - config.tot_verts, config.tot_edges, config.tot_corners, config.tot_faces); + config.tot_verts, config.tot_edges, config.tot_faces, config.tot_corners); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 0e7d78a25fd..5703eea738c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -51,8 +51,8 @@ Mesh *create_grid_mesh(const int verts_x, const int edges_y = verts_y - 1; Mesh *mesh = BKE_mesh_new_nomain(verts_x * verts_y, edges_x * verts_y + edges_y * verts_x, - edges_x * edges_y * 4, - edges_x * edges_y); + edges_x * edges_y, + edges_x * edges_y * 4); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); MutableSpan poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 5d5f25a944f..d49ddb439ba 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -306,8 +306,8 @@ static Mesh *create_uv_sphere_mesh(const float radius, { Mesh *mesh = BKE_mesh_new_nomain(sphere_vert_total(segments, rings), sphere_edge_total(segments, rings), - sphere_corner_total(segments, rings), - sphere_face_total(segments, rings)); + sphere_face_total(segments, rings), + sphere_corner_total(segments, rings)); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan edges = mesh->edges_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 8686832e38b..5ba2ebcc9d1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -123,7 +123,7 @@ static Mesh *create_mesh_from_volume_grids(Span gri loop_offset += (3 * data.tris.size() + 4 * data.quads.size()); } - Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, loop_offset, poly_offset); + Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, poly_offset, loop_offset); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan dst_poly_offsets = mesh->poly_offsets_for_write(); diff --git a/source/blender/render/intern/multires_bake.cc b/source/blender/render/intern/multires_bake.cc index fedddec9025..097fad22b45 100644 --- a/source/blender/render/intern/multires_bake.cc +++ b/source/blender/render/intern/multires_bake.cc @@ -492,7 +492,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, void *bake_data = nullptr; Mesh *temp_mesh = BKE_mesh_new_nomain( - dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumLoops(dm), dm->getNumPolys(dm)); + dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm)); temp_mesh->vert_positions_for_write().copy_from( {reinterpret_cast(dm->getVertArray(dm)), temp_mesh->totvert}); temp_mesh->edges_for_write().copy_from( -- 2.30.2 From 7535ab412a8362056a1c3e5a6179e4002b1a65da Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 15:49:13 -0400 Subject: [PATCH 17/61] Cleanup: Remove redundant "reference" argument to geometry copy Implicit sharing means attribute ownership is shared between geometry data-blocks, and the sharing happens automatically. So it's unnecessary to choose whether to enable it when copying a mesh. --- source/blender/blenkernel/BKE_curves.h | 2 +- source/blender/blenkernel/BKE_lib_id.h | 2 -- source/blender/blenkernel/BKE_mesh.h | 2 +- source/blender/blenkernel/BKE_pointcloud.h | 2 +- source/blender/blenkernel/BKE_volume.h | 2 +- .../blender/blenkernel/intern/DerivedMesh.cc | 31 ++++++++----------- source/blender/blenkernel/intern/cloth.cc | 2 +- .../blender/blenkernel/intern/crazyspace.cc | 4 +-- source/blender/blenkernel/intern/curves.cc | 12 ++----- .../blender/blenkernel/intern/dynamicpaint.cc | 10 +++--- source/blender/blenkernel/intern/fluid.cc | 12 +++---- .../intern/geometry_component_curves.cc | 6 ++-- .../intern/geometry_component_mesh.cc | 6 ++-- .../intern/geometry_component_pointcloud.cc | 6 ++-- .../intern/geometry_component_volume.cc | 6 ++-- source/blender/blenkernel/intern/mesh.cc | 12 ++----- .../blender/blenkernel/intern/mesh_convert.cc | 4 +-- source/blender/blenkernel/intern/multires.cc | 2 +- .../blender/blenkernel/intern/pointcloud.cc | 12 ++----- source/blender/blenkernel/intern/volume.cc | 13 ++------ source/blender/editors/object/object_add.cc | 4 +-- .../blender/editors/object/object_remesh.cc | 4 +-- .../modifiers/intern/MOD_particlesystem.cc | 4 +-- source/blender/modifiers/intern/MOD_util.cc | 6 ++-- source/blender/render/intern/bake.cc | 4 +-- 25 files changed, 68 insertions(+), 102 deletions(-) diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h index 83a0ba201f8..1cd74cffe0b 100644 --- a/source/blender/blenkernel/BKE_curves.h +++ b/source/blender/blenkernel/BKE_curves.h @@ -28,7 +28,7 @@ bool BKE_curves_attribute_required(const struct Curves *curves, const char *name /* Depsgraph */ -struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src, bool reference); +struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src); void BKE_curves_data_update(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index cb8b6e665af..889988cc7d9 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -152,8 +152,6 @@ enum { LIB_ID_COPY_CACHES = 1 << 18, /** Don't copy `id->adt`, used by ID data-block localization routines. */ LIB_ID_COPY_NO_ANIMDATA = 1 << 19, - /** Mesh: Reference CD data layers instead of doing real copy - USE WITH CAUTION! */ - LIB_ID_COPY_CD_REFERENCE = 1 << 20, /** Do not copy id->override_library, used by ID data-block override routines. */ LIB_ID_COPY_NO_LIB_OVERRIDE = 1 << 21, /** When copying local sub-data (like constraints or modifiers), do not set their "library diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 0a5e3e0f6c6..578904dbcc2 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -175,7 +175,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval); * Performs copy for use during evaluation, * optional referencing original arrays to reduce memory. */ -struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference); +struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source); /** * These functions construct a new Mesh, diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index 6eadac4cced..c386091076f 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -79,7 +79,7 @@ bool BKE_pointcloud_attribute_required(const struct PointCloud *pointcloud, cons /* Dependency Graph */ -struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference); +struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src); void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index 42af44a299e..7c4e6a69d43 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -130,7 +130,7 @@ void BKE_volume_grid_transform_matrix_set(const struct Volume *volume, * file path. Grids are shared with the source data-block, not copied. */ struct Volume *BKE_volume_new_for_eval(const struct Volume *volume_src); -struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src, bool reference); +struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src); struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume, const char *name, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 89802d9cb71..023d062b9dd 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -380,7 +380,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) BKE_mesh_ensure_default_orig_index_customdata(mesh); } else { - mesh = BKE_mesh_copy_for_eval(me, true); + mesh = BKE_mesh_copy_for_eval(me); } orco = get_orco_coords(ob, em, layer, &free); @@ -654,7 +654,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) { if (mesh_final == nullptr) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } MutableAttributeAccessor attributes = mesh_final->attributes_for_write(); @@ -685,7 +685,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { blender::bke::ScopedModifierTimer modifier_timer{*md}; if (!mesh_final) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } BKE_modifier_deform_verts(md, @@ -703,12 +703,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, * places that wish to use the original mesh but with deformed * coordinates (like vertex paint). */ if (r_deform) { - if (mesh_final) { - mesh_deform = BKE_mesh_copy_for_eval(mesh_final, false); - } - else { - mesh_deform = BKE_mesh_copy_for_eval(mesh_input, false); - } + mesh_deform = BKE_mesh_copy_for_eval(mesh_final ? mesh_final : mesh_input); } } @@ -779,7 +774,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (mti->type == eModifierTypeType_OnlyDeform) { if (!mesh_final) { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } BKE_modifier_deform_verts(md, @@ -798,7 +793,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } } else { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); ASSERT_IS_VALID_MESH(mesh_final); check_for_needs_mapping = true; } @@ -966,7 +961,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, mesh_final = mesh_input; } else { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); } } @@ -1011,7 +1006,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Not yet finalized by any instance, do it now * Isolate since computing normals is multithreaded and we are holding a lock. */ blender::threading::isolate_task([&] { - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); mesh_calc_modifier_final_normals( mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); mesh_calc_finalize(mesh_input, mesh_final); @@ -1026,7 +1021,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) { /* Modifier stack was (re-)evaluated with a request for additional normals * different than the instanced mesh, can't instance anymore now. */ - mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); + mesh_final = BKE_mesh_copy_for_eval(mesh_input); mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); mesh_calc_finalize(mesh_input, mesh_final); } @@ -1255,7 +1250,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* apply vertex coordinates or build a DerivedMesh as necessary */ if (mesh_final) { if (deformed_verts) { - Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); + Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final); if (mesh_final != mesh_cage) { BKE_id_free(nullptr, mesh_final); } @@ -1264,7 +1259,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } else if (mesh_final == mesh_cage) { /* 'me' may be changed by this modifier, so we need to copy it. */ - mesh_final = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_final = BKE_mesh_copy_for_eval(mesh_final); } } else { @@ -1337,7 +1332,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_cage && i == cageIndex) { if (mesh_final && deformed_verts) { - mesh_cage = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_cage = BKE_mesh_copy_for_eval(mesh_final); BKE_mesh_vert_coords_apply(mesh_cage, deformed_verts); } else if (mesh_final) { @@ -1373,7 +1368,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mesh_final) { if (deformed_verts) { if (mesh_final == mesh_cage) { - mesh_final = BKE_mesh_copy_for_eval(mesh_final, false); + mesh_final = BKE_mesh_copy_for_eval(mesh_final); } BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } diff --git a/source/blender/blenkernel/intern/cloth.cc b/source/blender/blenkernel/intern/cloth.cc index 1c27b8b2989..7e9aea008c4 100644 --- a/source/blender/blenkernel/intern/cloth.cc +++ b/source/blender/blenkernel/intern/cloth.cc @@ -1176,7 +1176,7 @@ static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh) static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh) { using namespace blender; - Mesh *new_mesh = BKE_mesh_copy_for_eval(mesh, false); + Mesh *new_mesh = BKE_mesh_copy_for_eval(mesh); ClothVertex *verts = clmd->clothObject->verts; MutableSpan positions = mesh->vert_positions_for_write(); diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 0dc5004cf2a..7202066b563 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -389,7 +389,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, if (defmats == nullptr) { /* NOTE: Evaluated object is re-set to its original un-deformed state. */ Mesh *me = static_cast(object_eval.data); - me_eval = BKE_mesh_copy_for_eval(me, true); + me_eval = BKE_mesh_copy_for_eval(me); crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts); } @@ -470,7 +470,7 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, } if (mesh_eval == nullptr) { - mesh_eval = BKE_mesh_copy_for_eval(mesh, true); + mesh_eval = BKE_mesh_copy_for_eval(mesh); } mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert); diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 59866c40e05..b8af50dc1f5 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -220,16 +220,10 @@ bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name) return STREQ(name, ATTR_POSITION); } -Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference) +Curves *BKE_curves_copy_for_eval(Curves *curves_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Curves *result = (Curves *)BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } static void curves_evaluate_modifiers(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/dynamicpaint.cc b/source/blender/blenkernel/intern/dynamicpaint.cc index 41c2645da5b..3b107c04118 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.cc +++ b/source/blender/blenkernel/intern/dynamicpaint.cc @@ -1904,7 +1904,7 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata, */ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh) { - Mesh *result = BKE_mesh_copy_for_eval(mesh, false); + Mesh *result = BKE_mesh_copy_for_eval(mesh); if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING) && pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) { @@ -2049,7 +2049,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (runtime_data->brush_mesh != nullptr) { BKE_id_free(nullptr, runtime_data->brush_mesh); } - runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false); + runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result); } return result; @@ -2070,7 +2070,7 @@ static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh) BKE_id_free(nullptr, runtime->canvas_mesh); } - runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false); + runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh); } /* @@ -3796,7 +3796,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, SUBFRAME_RECURSION, BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); - mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false); + mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush)); numOfVerts_p = mesh_p->totvert; float(*positions_p)[3] = BKE_mesh_vert_positions_for_write(mesh_p); @@ -4282,7 +4282,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, Bounds3D mesh_bb = {{0}}; VolumeGrid *grid = bData->grid; - mesh = BKE_mesh_copy_for_eval(brush_mesh, false); + mesh = BKE_mesh_copy_for_eval(brush_mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(mesh); const blender::Span vert_normals = mesh->vert_normals(); const blender::Span corner_verts = mesh->corner_verts(); diff --git a/source/blender/blenkernel/intern/fluid.cc b/source/blender/blenkernel/intern/fluid.cc index 1a3e094037d..a45bf709b31 100644 --- a/source/blender/blenkernel/intern/fluid.cc +++ b/source/blender/blenkernel/intern/fluid.cc @@ -1003,7 +1003,7 @@ static void obstacles_from_mesh(Object *coll_ob, float *vert_vel = nullptr; bool has_velocity = false; - Mesh *me = BKE_mesh_copy_for_eval(fes->mesh, false); + Mesh *me = BKE_mesh_copy_for_eval(fes->mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(me); int min[3], max[3], res[3]; @@ -2062,7 +2062,7 @@ static void emit_from_mesh( /* Copy mesh for thread safety as we modify it. * Main issue is its VertArray being modified, then replaced and freed. */ - Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, false); + Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh); float(*positions)[3] = BKE_mesh_vert_positions_for_write(me); const blender::Span corner_verts = me->corner_verts(); @@ -3364,7 +3364,7 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */ if (fds->total_cells <= 1 || (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) { - return BKE_mesh_copy_for_eval(orgmesh, false); + return BKE_mesh_copy_for_eval(orgmesh); } result = BKE_mesh_new_nomain(num_verts, 0, num_faces, num_faces * 4); @@ -3590,7 +3590,7 @@ static void fluid_modifier_processFlow(FluidModifierData *fmd, if (fmd->flow->mesh) { BKE_id_free(nullptr, fmd->flow->mesh); } - fmd->flow->mesh = BKE_mesh_copy_for_eval(me, false); + fmd->flow->mesh = BKE_mesh_copy_for_eval(me); } if (scene_framenr > fmd->time) { @@ -3617,7 +3617,7 @@ static void fluid_modifier_processEffector(FluidModifierData *fmd, if (fmd->effector->mesh) { BKE_id_free(nullptr, fmd->effector->mesh); } - fmd->effector->mesh = BKE_mesh_copy_for_eval(me, false); + fmd->effector->mesh = BKE_mesh_copy_for_eval(me); } if (scene_framenr > fmd->time) { @@ -4125,7 +4125,7 @@ Mesh *BKE_fluid_modifier_do( } if (!result) { - result = BKE_mesh_copy_for_eval(me, false); + result = BKE_mesh_copy_for_eval(me); } else { BKE_mesh_copy_parameters_for_eval(result, me); diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index eb185d979a8..62f8e50a3b7 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -33,7 +33,7 @@ GeometryComponent *CurveComponent::copy() const { CurveComponent *new_component = new CurveComponent(); if (curves_ != nullptr) { - new_component->curves_ = BKE_curves_copy_for_eval(curves_, false); + new_component->curves_ = BKE_curves_copy_for_eval(curves_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -87,7 +87,7 @@ Curves *CurveComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - curves_ = BKE_curves_copy_for_eval(curves_, false); + curves_ = BKE_curves_copy_for_eval(curves_); ownership_ = GeometryOwnershipType::Owned; } return curves_; @@ -107,7 +107,7 @@ void CurveComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - curves_ = BKE_curves_copy_for_eval(curves_, false); + curves_ = BKE_curves_copy_for_eval(curves_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0f70d9ac48a..62bc979eb6e 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -36,7 +36,7 @@ GeometryComponent *MeshComponent::copy() const { MeshComponent *new_component = new MeshComponent(); if (mesh_ != nullptr) { - new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -83,7 +83,7 @@ Mesh *MeshComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + mesh_ = BKE_mesh_copy_for_eval(mesh_); ownership_ = GeometryOwnershipType::Owned; } return mesh_; @@ -103,7 +103,7 @@ void MeshComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + mesh_ = BKE_mesh_copy_for_eval(mesh_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 267daad48d7..0e43a83ed31 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -23,7 +23,7 @@ GeometryComponent *PointCloudComponent::copy() const { PointCloudComponent *new_component = new PointCloudComponent(); if (pointcloud_ != nullptr) { - new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -70,7 +70,7 @@ PointCloud *PointCloudComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); ownership_ = GeometryOwnershipType::Owned; } return pointcloud_; @@ -90,7 +90,7 @@ void PointCloudComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc index 405521675cc..9fdffdeb473 100644 --- a/source/blender/blenkernel/intern/geometry_component_volume.cc +++ b/source/blender/blenkernel/intern/geometry_component_volume.cc @@ -21,7 +21,7 @@ GeometryComponent *VolumeComponent::copy() const { VolumeComponent *new_component = new VolumeComponent(); if (volume_ != nullptr) { - new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); + new_component->volume_ = BKE_volume_copy_for_eval(volume_); new_component->ownership_ = GeometryOwnershipType::Owned; } return new_component; @@ -68,7 +68,7 @@ Volume *VolumeComponent::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { - volume_ = BKE_volume_copy_for_eval(volume_, false); + volume_ = BKE_volume_copy_for_eval(volume_); ownership_ = GeometryOwnershipType::Owned; } return volume_; @@ -83,7 +83,7 @@ void VolumeComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { - volume_ = BKE_volume_copy_for_eval(volume_, false); + volume_ = BKE_volume_copy_for_eval(volume_); ownership_ = GeometryOwnershipType::Owned; } } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 9b228ace3b6..e14fa192c8a 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1182,16 +1182,10 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval) MEM_freeN(mesh_eval); } -Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) +Mesh *BKE_mesh_copy_for_eval(const Mesh *source) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &source->id, nullptr, LIB_ID_COPY_LOCALIZE)); } BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me, diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index b8f06dfd244..40dbc03586f 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -693,7 +693,7 @@ static const Curves *get_evaluated_curves_from_object(const Object *object) static Mesh *mesh_new_from_evaluated_curve_type_object(const Object *evaluated_object) { if (const Mesh *mesh = BKE_object_get_evaluated_mesh(evaluated_object)) { - return BKE_mesh_copy_for_eval(mesh, false); + return BKE_mesh_copy_for_eval(mesh); } if (const Curves *curves = get_evaluated_curves_from_object(evaluated_object)) { const blender::bke::AnonymousAttributePropagationInfo propagation_info; @@ -752,7 +752,7 @@ static Mesh *mesh_new_from_mball_object(Object *object) return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - return BKE_mesh_copy_for_eval(mesh_eval, false); + return BKE_mesh_copy_for_eval(mesh_eval); } static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index fde8f8b842f..0cd8cf5079c 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -241,7 +241,7 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh); if (result == deformed_mesh) { - result = BKE_mesh_copy_for_eval(deformed_mesh, true); + result = BKE_mesh_copy_for_eval(deformed_mesh); } return result; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index c342c82176a..7225492ae07 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -322,16 +322,10 @@ bool BKE_pointcloud_attribute_required(const PointCloud * /*pointcloud*/, const /* Dependency Graph */ -PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference) +PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - PointCloud *result = (PointCloud *)BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, flags); - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 9eb26eb4c59..39e94c4d888 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -1523,17 +1523,10 @@ Volume *BKE_volume_new_for_eval(const Volume *volume_src) return volume_dst; } -Volume *BKE_volume_copy_for_eval(Volume *volume_src, bool reference) +Volume *BKE_volume_copy_for_eval(Volume *volume_src) { - int flags = LIB_ID_COPY_LOCALIZE; - - if (reference) { - flags |= LIB_ID_COPY_CD_REFERENCE; - } - - Volume *result = (Volume *)BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, flags); - - return result; + return reinterpret_cast( + BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, LIB_ID_COPY_LOCALIZE)); } #ifdef WITH_OPENVDB diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 34d83e9118d..aee9a1a5fa0 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -3156,7 +3156,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); - me_eval = BKE_mesh_copy_for_eval(me_eval, false); + me_eval = BKE_mesh_copy_for_eval(me_eval); BKE_object_material_from_eval_data(bmain, newob, &me_eval->id); Mesh *new_mesh = (Mesh *)newob->data; BKE_mesh_nomain_to_mesh(me_eval, new_mesh, newob); @@ -3388,7 +3388,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) newob->type = OB_MESH; if (const Mesh *mesh_eval = geometry.get_mesh_for_read()) { - BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(mesh_eval, false), new_mesh, newob); + BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(mesh_eval), new_mesh, newob); BKE_object_material_from_eval_data(bmain, newob, &mesh_eval->id); new_mesh->attributes_for_write().remove_anonymous(); } diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index f9bad0c6e06..a9ee1d32803 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -778,7 +778,7 @@ static Mesh *remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes) mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE; Mesh *mesh_bisect, *mesh_bisect_temp; - mesh_bisect = BKE_mesh_copy_for_eval(mesh, false); + mesh_bisect = BKE_mesh_copy_for_eval(mesh); int axis; float plane_co[3], plane_no[3]; @@ -860,7 +860,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update, /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without * freeing the original ID */ - bisect_mesh = BKE_mesh_copy_for_eval(mesh, false); + bisect_mesh = BKE_mesh_copy_for_eval(mesh); /* Bisect the input mesh using the paint symmetry settings */ bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes); diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index 13220306d65..433e398a9f2 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -154,7 +154,7 @@ static void deformVerts(ModifierData *md, } /* make new mesh */ - psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false); + psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src); BKE_mesh_vert_coords_apply(psmd->mesh_final, vertexCos); BKE_mesh_tessface_ensure(psmd->mesh_final); @@ -185,7 +185,7 @@ static void deformVerts(ModifierData *md, /* Make a persistent copy of the mesh. We don't actually need * all this data, just some topology for remapping. Could be * optimized once. */ - psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false); + psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original); } BKE_mesh_tessface_ensure(psmd->mesh_original); diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index f1080f76d47..1e544875a7d 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -182,10 +182,8 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether * we really need a copy here. Maybe the CoW ob->data can be directly used. */ Mesh *mesh_prior_modifiers = BKE_object_get_pre_modified_mesh(ob); - mesh = (Mesh *)BKE_id_copy_ex(nullptr, - &mesh_prior_modifiers->id, - nullptr, - (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_CD_REFERENCE)); + mesh = (Mesh *)BKE_id_copy_ex( + nullptr, &mesh_prior_modifiers->id, nullptr, LIB_ID_COPY_LOCALIZE); mesh->runtime->deformed_only = true; } diff --git a/source/blender/render/intern/bake.cc b/source/blender/render/intern/bake.cc index b6600a43d9e..3cffb99078b 100644 --- a/source/blender/render/intern/bake.cc +++ b/source/blender/render/intern/bake.cc @@ -579,7 +579,7 @@ bool RE_bake_pixels_populate_from_objects(Mesh *me_low, treeData = MEM_cnew_array(tot_highpoly, "Highpoly BVH Trees"); if (!is_cage) { - me_eval_low = BKE_mesh_copy_for_eval(me_low, false); + me_eval_low = BKE_mesh_copy_for_eval(me_low); tris_low = mesh_calc_tri_tessface(me_low, true, me_eval_low); } else if (is_custom_cage) { @@ -854,7 +854,7 @@ void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[], TriTessFace *triangles; - Mesh *me_eval = BKE_mesh_copy_for_eval(me, false); + Mesh *me_eval = BKE_mesh_copy_for_eval(me); triangles = mesh_calc_tri_tessface(me, true, me_eval); -- 2.30.2 From 2ab500c234c78ce16b5bc8868ffd938a0e35e530 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 15:52:06 -0400 Subject: [PATCH 18/61] Cleanup: Remove unnecessary point cloud function argument The "nomain to main" function for point clouds now always takes ownership of the source data-block, just like the mesh version. --- source/blender/blenkernel/BKE_pointcloud.h | 3 +-- source/blender/blenkernel/intern/pointcloud.cc | 8 ++------ source/blender/editors/object/object_modifier.cc | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index c386091076f..51ab0ab397e 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -70,8 +70,7 @@ void *BKE_pointcloud_add(struct Main *bmain, const char *name); void *BKE_pointcloud_add_default(struct Main *bmain, const char *name); struct PointCloud *BKE_pointcloud_new_nomain(int totpoint); void BKE_pointcloud_nomain_to_pointcloud(struct PointCloud *pointcloud_src, - struct PointCloud *pointcloud_dst, - bool take_ownership); + struct PointCloud *pointcloud_dst); struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob); diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 7225492ae07..f06d560955c 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -249,9 +249,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) return pointcloud; } -void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, - PointCloud *pointcloud_dst, - bool take_ownership) +void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, PointCloud *pointcloud_dst) { BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN); @@ -260,9 +258,7 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, const int totpoint = pointcloud_dst->totpoint = pointcloud_src->totpoint; CustomData_copy(&pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, totpoint); - if (take_ownership) { - BKE_id_free(nullptr, pointcloud_src); - } + BKE_id_free(nullptr, pointcloud_src); } bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) const diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index e7458f168bc..faea7712c26 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -1107,7 +1107,7 @@ static bool modifier_apply_obdata( /* Copy the relevant information to the original. */ Main *bmain = DEG_get_bmain(depsgraph); BKE_object_material_from_eval_data(bmain, ob, &pointcloud_eval->id); - BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points, true); + BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points); } else { /* TODO: implement for volumes. */ -- 2.30.2 From e05cbad0d13631a2b166a6a9075f4c800c362206 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Wed, 19 Apr 2023 12:58:08 -0700 Subject: [PATCH 19/61] Sculpt: Fix #107093: expand helper function not specialized to pbvh sculpt_expand_is_face_in_active_component wasn't specialzied for the different PBVH types. --- .../editors/sculpt_paint/sculpt_expand.cc | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.cc b/source/blender/editors/sculpt_paint/sculpt_expand.cc index 2aeff54e39f..523fcbae2c5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.cc +++ b/source/blender/editors/sculpt_paint/sculpt_expand.cc @@ -148,8 +148,24 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, ExpandCache *expand_cache, const int f) { - const int vert = ss->corner_verts[ss->polys[f].start()]; - return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_make_vref(vert)); + PBVHVertRef vertex; + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + vertex.i = ss->corner_verts[ss->polys[f].start()]; + break; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + vertex.i = ss->polys[f].start() * key->grid_area; + + break; + } + case PBVH_BMESH: { + vertex.i = reinterpret_cast(ss->bm->ftable[f]->l_first->v); + break; + } + } + return sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex); } /** -- 2.30.2 From 911f9bea849b78c9246dcbc8a3ff7fd40b529a55 Mon Sep 17 00:00:00 2001 From: Martijn Versteegh Date: Wed, 19 Apr 2023 22:25:43 +0200 Subject: [PATCH 20/61] Fix #107067: Properly clear CD_FLAG_ACTIVE/DEFAULT_COLOR flags Runtime this information is stored in the active_color_attribute and default_color_attribute strings on the mesh, however when saving it is still saved in the old format with flags on the CustomData layers. When converting from the strings to the layers not all flags were properly cleared from the CustomData layers, leading to multiple layers having the CD_FLAG_COLOR_ACTIVE/RENDER flag. --- source/blender/blenkernel/intern/mesh_legacy_convert.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 151bcf67b79..116e3db14bf 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -2197,7 +2197,10 @@ void BKE_mesh_legacy_attribute_strings_to_flags(Mesh *mesh) CustomData_clear_layer_flag( vdata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); + CustomData_clear_layer_flag( + ldata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); CustomData_clear_layer_flag(ldata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); + CustomData_clear_layer_flag(vdata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER); if (const char *name = mesh->active_color_attribute) { int i; -- 2.30.2 From f87e474af00483dd3516fc2f6b36b1dffb89f678 Mon Sep 17 00:00:00 2001 From: Erik Abrahamsson Date: Thu, 20 Apr 2023 00:06:49 +0200 Subject: [PATCH 21/61] Cleanup: Move view3d_gizmo_ruler.c to C++ Move view3d_gizmo_ruler.c to C++ to make further changes easier. See #103343 Pull Request: https://projects.blender.org/blender/blender/pulls/107148 --- .../editors/space_view3d/CMakeLists.txt | 2 +- ...3d_gizmo_ruler.c => view3d_gizmo_ruler.cc} | 339 +++++++++--------- 2 files changed, 168 insertions(+), 173 deletions(-) rename source/blender/editors/space_view3d/{view3d_gizmo_ruler.c => view3d_gizmo_ruler.cc} (80%) diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 2ca90a2f788..747e3a537fa 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -45,7 +45,7 @@ set(SRC view3d_gizmo_navigate_type.c view3d_gizmo_preselect.c view3d_gizmo_preselect_type.cc - view3d_gizmo_ruler.c + view3d_gizmo_ruler.cc view3d_gizmo_tool_generic.c view3d_header.c view3d_iterators.cc diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc similarity index 80% rename from source/blender/editors/space_view3d/view3d_gizmo_ruler.c rename to source/blender/editors/space_view3d/view3d_gizmo_ruler.cc index 16195a896bd..d4e8d6e08cb 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc @@ -6,6 +6,9 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_matrix.hh" +#include "BLI_math_matrix_types.hh" +#include "BLI_math_vector_types.hh" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -58,6 +61,13 @@ #include "BLF_api.h" +using blender::float2; +using blender::float2x2; +using blender::float3; +using blender::float3x2; +using blender::float3x3; +using blender::float4; + /** * Supporting transform features could be removed if the actual transform system is used. * Keep the option open since each transform feature is duplicating logic. @@ -115,7 +125,7 @@ enum { struct RulerItem; -typedef struct RulerInfo { +struct RulerInfo { struct RulerItem *item_active; int flag; int snap_flag; @@ -143,27 +153,26 @@ typedef struct RulerInfo { wmGizmo *gizmo; PropertyRNA *prop_prevpoint; } snap_data; - -} RulerInfo; +}; /* -------------------------------------------------------------------- */ /* Ruler Item (two or three points) */ -typedef struct RulerItem { +struct RulerItem { wmGizmo gz; /** World-space coords, middle being optional. */ - float co[3][3]; + float3x3 co; int flag; int raycast_dir; /* RULER_DIRECTION_* */ -} RulerItem; +}; -typedef struct RulerInteraction { +struct RulerInteraction { /* selected coord */ char co_index; /* 0 -> 2 */ - float drag_start_co[3]; -} RulerInteraction; + float3 drag_start_co; +}; /* -------------------------------------------------------------------- */ /** \name Internal Ruler Utilities @@ -173,16 +182,16 @@ static RulerItem *ruler_item_add(wmGizmoGroup *gzgroup) { /* could pass this as an arg */ const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true); - RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, NULL); + RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, nullptr); WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true); return ruler_item; } static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item) { - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (ruler_info->item_active == ruler_item) { - ruler_info->item_active = NULL; + ruler_info->item_active = nullptr; } WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C); } @@ -222,10 +231,10 @@ static void ruler_item_as_string( static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, RulerItem *ruler_item, - const float mval[2], + const float2 mval, int *r_co_index) { - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); ARegion *region = ruler_info->region; bool found = false; @@ -233,7 +242,7 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, int co_index_best = -1; { - float co_ss[3][2]; + float3x2 co_ss; float dist; int j; @@ -250,10 +259,10 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, found = true; { - const float dist_points[3] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[1], mval), - len_squared_v2v2(co_ss[2], mval), + const float3 dist_points = { + blender::math::distance_squared(co_ss[0], mval), + blender::math::distance_squared(co_ss[1], mval), + blender::math::distance_squared(co_ss[2], mval), }; if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = min_axis_v3(dist_points); @@ -271,9 +280,9 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, found = true; { - const float dist_points[2] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[2], mval), + const float2 dist_points = { + blender::math::distance_squared(co_ss[0], mval), + blender::math::distance_squared(co_ss[2], mval), }; if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; @@ -316,9 +325,13 @@ static void ruler_state_set(RulerInfo *ruler_info, int state) ruler_info->state = state; } -static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2]) +static void view3d_ruler_item_project(RulerInfo *ruler_info, float3 &r_co, const int xy[2]) { - ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co); + ED_view3d_win_to_3d_int(static_cast(ruler_info->area->spacedata.first), + ruler_info->region, + r_co, + xy, + r_co); } /** @@ -333,81 +346,77 @@ static bool view3d_ruler_item_mousemove(const bContext *C, const bool do_snap) { wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo; - const float eps_bias = 0.0002f; + constexpr float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ if (ruler_item) { - RulerInteraction *inter = ruler_item->gz.interaction_data; - float *co = ruler_item->co[inter->co_index]; + RulerInteraction *inter = static_cast(ruler_item->gz.interaction_data); + float3 &co = ruler_item->co[inter->co_index]; /* restore the initial depth */ - copy_v3_v3(co, inter->drag_start_co); + co = inter->drag_start_co; view3d_ruler_item_project(ruler_info, co, mval); if (do_thickness && inter->co_index != 1) { Scene *scene = DEG_get_input_scene(depsgraph); - View3D *v3d = ruler_info->area->spacedata.first; + View3D *v3d = static_cast(ruler_info->area->spacedata.first); SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo); - const float mval_fl[2] = {UNPACK2(mval)}; - float ray_normal[3]; - float ray_start[3]; - float *co_other; + const float2 mval_fl = {float(mval[0]), float(mval[1])}; + float3 ray_normal; + float3 ray_start; + float3 &co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; - co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; + SnapObjectParams snap_object_params{}; + snap_object_params.snap_target_select = SCE_SNAP_TARGET_ALL; + snap_object_params.edit_mode_type = SNAP_GEOM_CAGE; - if (ED_transform_snap_object_project_view3d(snap_context, - depsgraph, - ruler_info->region, - v3d, - SCE_SNAP_MODE_FACE_RAYCAST, - &(const struct SnapObjectParams){ - .snap_target_select = SCE_SNAP_TARGET_ALL, - .edit_mode_type = SNAP_GEOM_CAGE, - }, - NULL, - mval_fl, - NULL, - &dist_px, - co, - ray_normal)) { - negate_v3(ray_normal); + eSnapMode hit = ED_transform_snap_object_project_view3d(snap_context, + depsgraph, + ruler_info->region, + v3d, + SCE_SNAP_MODE_FACE_RAYCAST, + &snap_object_params, + nullptr, + mval_fl, + nullptr, + &dist_px, + co, + ray_normal); + if (hit) { /* add some bias */ - madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); + ray_start = co - ray_normal * eps_bias; ED_transform_snap_object_project_ray(snap_context, depsgraph, v3d, - &(const struct SnapObjectParams){ - .snap_target_select = SCE_SNAP_TARGET_ALL, - .edit_mode_type = SNAP_GEOM_CAGE, - }, + &snap_object_params, ray_start, - ray_normal, - NULL, + -ray_normal, + nullptr, co_other, - NULL); + nullptr); } } else { - View3D *v3d = ruler_info->area->spacedata.first; + View3D *v3d = static_cast(ruler_info->area->spacedata.first); if (do_snap) { - float *prev_point = NULL; + float3 *prev_point = nullptr; BLI_assert(ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)); if (inter->co_index != 1) { if (ruler_item->flag & RULERITEM_USE_ANGLE) { - prev_point = ruler_item->co[1]; + prev_point = &ruler_item->co[1]; } else if (inter->co_index == 0) { - prev_point = ruler_item->co[2]; + prev_point = &ruler_item->co[2]; } else { - prev_point = ruler_item->co[0]; + prev_point = &ruler_item->co[0]; } } - if (prev_point != NULL) { + if (prev_point != nullptr) { RNA_property_float_set_array( - snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point); } - ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, NULL, NULL, NULL); + ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, nullptr, nullptr, nullptr); } #ifdef USE_AXIS_CONSTRAINTS @@ -416,7 +425,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, Scene *scene = DEG_get_input_scene(depsgraph); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - RegionView3D *rv3d = ruler_info->region->regiondata; + RegionView3D *rv3d = static_cast(ruler_info->region->regiondata); BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); @@ -429,13 +438,12 @@ static bool view3d_ruler_item_mousemove(const bContext *C, } const int pivot_point = scene->toolsettings->transform_pivot_point; - float mat[3][3]; + float3x3 mat; ED_transform_calc_orientation_from_type_ex( - scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat); + scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat.ptr()); - invert_m3(mat); - mul_m3_m3_pre(ruler_item->co, mat); + ruler_item->co = blender::math::invert(mat) * ruler_item->co; /* Loop through the axes and constrain the dragged point to the current constrained axis. */ @@ -444,8 +452,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, ruler_item->co[inter->co_index][i] = ruler_item->co[(inter->co_index == 0) ? 2 : 0][i]; } } - invert_m3(mat); - mul_m3_m3_pre(ruler_item->co, mat); + ruler_item->co = mat * ruler_item->co; } #endif } @@ -464,7 +471,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C, */ static bool gizmo_ruler_check_for_operator(const wmGizmoGroup *gzgroup) { - return gzgroup->customdata != NULL; + return gzgroup->customdata != nullptr; } /** \} */ @@ -481,13 +488,13 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) return gpl; } } - return NULL; + return nullptr; } static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup) { #ifndef NDEBUG - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo); #endif return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next; @@ -508,13 +515,13 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) const char *ruler_name = RULER_ID; bool changed = false; - if (scene->gpd == NULL) { + if (scene->gpd == nullptr) { scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); } gpd = scene->gpd; gpl = view3d_ruler_layer_get(gpd); - if (gpl == NULL) { + if (gpl == nullptr) { gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false, false); copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; @@ -530,10 +537,11 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) int j; /* allocate memory for a new stroke */ - gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + gps = (bGPDstroke *)MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); if (ruler_item->flag & RULERITEM_USE_ANGLE) { gps->totpoints = 3; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, + "gp_stroke_points"); for (j = 0; j < 3; j++) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -543,7 +551,8 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) } else { gps->totpoints = 2; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, + "gp_stroke_points"); for (j = 0; j < 3; j += 2) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -578,10 +587,10 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); if (gpf) { bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + for (gps = static_cast(gpf->strokes.first); gps; gps = gps->next) { bGPDspoint *pt = gps->points; int j; - RulerItem *ruler_item = NULL; + RulerItem *ruler_item = nullptr; if (gps->totpoints == 3) { ruler_item = ruler_item_add(gzgroup); for (j = 0; j < 3; j++) { @@ -617,20 +626,19 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) { Scene *scene = CTX_data_scene(C); UnitSettings *unit = &scene->unit; - RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gz->parent_gzgroup->customdata); RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = ruler_info->region; - RegionView3D *rv3d = region->regiondata; + RegionView3D *rv3d = static_cast(region->regiondata); const float cap_size = 4.0f * UI_SCALE_FAC; const float bg_margin = 4.0f * UI_SCALE_FAC; const float arc_size = 64.0f * UI_SCALE_FAC; -#define ARC_STEPS 24 - const int arc_steps = ARC_STEPS; - const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + constexpr int arc_steps = 24; + const float4 color_act = {1.0f, 1.0f, 1.0f, 1.0f}; + const float4 color_base = {0.0f, 0.0f, 0.0f, 1.0f}; uchar color_text[3]; uchar color_wire[3]; - float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + float4 color_back = {1.0f, 1.0f, 1.0f, 0.5f}; /* Pixel Space. */ GPU_matrix_push_projection(); @@ -650,13 +658,13 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) UI_GetThemeColor3ubv(TH_WIRE, color_wire); /* Avoid white on white text. (TODO: Fix by using theme). */ - if ((int)color_text[0] + (int)color_text[1] + (int)color_text[2] > 127 * 3 * 0.6f) { + if (int(color_text[0]) + int(color_text[1]) + int(color_text[2]) > 127 * 3 * 0.6f) { copy_v3_fl(color_back, 0.0f); } const bool is_act = (ruler_info->item_active == ruler_item); - float dir_ruler[2]; - float co_ss[3][2]; + float2 dir_ruler; + float3x2 co_ss; bool proj_ok[3]; int j; @@ -682,14 +690,14 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) if (ruler_item->flag & RULERITEM_USE_ANGLE) { immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; + float4 viewport_size(0.0f); GPU_viewport_size_get_f(viewport_size); immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); immUniform1i("colors_len", 2); /* "advanced" mode */ - const float *col = is_act ? color_act : color_base; + const float4 &col = is_act ? color_act : color_base; immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f); - immUniform4f("color2", col[0], col[1], col[2], col[3]); + immUniform4fv("color2", col); immUniform1f("dash_width", 6.0f); immUniform1f("udash_factor", 0.5f); @@ -707,37 +715,34 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* arc */ { - float dir_tmp[3]; - float ar_coord[3]; + float3 dir_tmp; + float3 ar_coord; - float dir_a[3]; - float dir_b[3]; - float quat[4]; - float axis[3]; + float3 dir_a; + float3 dir_b; + float4 quat; + float3 axis; float angle; const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) * min_fff(arc_size, - len_v2v2(co_ss[0], co_ss[1]) / 2.0f, - len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); + blender::math::distance(co_ss[0], co_ss[1]) / 2.0f, + blender::math::distance(co_ss[2], co_ss[1]) / 2.0f)); - sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); - sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); - normalize_v3(dir_a); - normalize_v3(dir_b); - - cross_v3_v3v3(axis, dir_a, dir_b); + dir_a = blender::math::normalize(ruler_item->co[0] - ruler_item->co[1]); + dir_b = blender::math::normalize(ruler_item->co[2] - ruler_item->co[1]); + axis = blender::math::cross(dir_a, dir_b); angle = angle_normalized_v3v3(dir_a, dir_b); axis_angle_to_quat(quat, axis, angle / arc_steps); - copy_v3_v3(dir_tmp, dir_a); + dir_tmp = dir_a; immUniformColor3ubv(color_wire); immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1); for (j = 0; j <= arc_steps; j++) { - madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale); + ar_coord = ruler_item->co[1] + dir_tmp * px_scale; mul_qt_v3(quat, dir_tmp); immVertex3fv(shdr_pos_3d, ar_coord); @@ -758,7 +763,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniform1i("colors_len", 2); /* "advanced" mode */ const float *col = is_act ? color_act : color_base; immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f); - immUniform4f("color2", col[0], col[1], col[2], col[3]); + immUniform4fv("color2", col); immUniform1f("dash_width", 6.0f); immUniform1f("udash_factor", 0.5f); @@ -784,19 +789,13 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); /* capping */ { - float rot_90_vec_a[2]; - float rot_90_vec_b[2]; - float cap[2]; + float2 cap; - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); - rot_90_vec_a[0] = -dir_ruler[1]; - rot_90_vec_a[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_a); + dir_ruler = co_ss[0] - co_ss[1]; + float2 rot_90_vec_a = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); - sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); - rot_90_vec_b[0] = -dir_ruler[1]; - rot_90_vec_b[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_b); + dir_ruler = co_ss[1] - co_ss[2]; + float2 rot_90_vec_b = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); GPU_blend(GPU_BLEND_ALPHA); @@ -820,16 +819,16 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4); if (proj_ok[0]) { - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + cap = co_ss[0] + rot_90_vec_a * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + cap = co_ss[0] - rot_90_vec_a * cap_size; immVertex2fv(shdr_pos_2d, cap); } if (proj_ok[2]) { - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + cap = co_ss[2] + rot_90_vec_b * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + cap = co_ss[2] - rot_90_vec_b * cap_size; immVertex2fv(shdr_pos_2d, cap); } @@ -849,7 +848,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* text */ char numstr[256]; - float numstr_size[2]; + float2 numstr_size; float posit[2]; const int prec = 2; /* XXX, todo, make optional */ @@ -885,14 +884,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) else { immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); + dir_ruler = co_ss[0] - co_ss[2]; /* capping */ { - float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; - float cap[2]; - - normalize_v2(rot_90_vec); + float2 rot_90_vec = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]}); + float2 cap; GPU_blend(GPU_BLEND_ALPHA); @@ -902,16 +899,16 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2); if (proj_ok[0]) { - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + cap = co_ss[0] + rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + cap = co_ss[0] - rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); } if (proj_ok[2]) { - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + cap = co_ss[2] + rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + cap = co_ss[2] - rot_90_vec * cap_size; immVertex2fv(shdr_pos_2d, cap); } @@ -923,19 +920,18 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) /* text */ char numstr[256]; - float numstr_size[2]; + float2 numstr_size; const int prec = 6; /* XXX, todo, make optional */ - float posit[2]; + float2 posit; ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - mid_v2_v2v2(posit, co_ss[0], co_ss[2]); + posit = (co_ss[0] + co_ss[2]) / 2.0f; /* center text */ - posit[0] -= numstr_size[0] / 2.0f; - posit[1] -= numstr_size[1] / 2.0f; + posit -= numstr_size / 2.0f; /* draw text (bg) */ if (proj_ok[0] && proj_ok[2]) { @@ -965,14 +961,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_matrix_pop(); GPU_matrix_pop_projection(); - -#undef ARC_STEPS } -static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) +static int gizmo_ruler_test_select(bContext *, wmGizmo *gz, const int mval[2]) { RulerItem *ruler_item_pick = (RulerItem *)gz; - const float mval_fl[2] = {UNPACK2(mval)}; + const float mval_fl[2] = {float(mval[0]), float(mval[1])}; int co_index; /* select and drag */ @@ -996,7 +990,7 @@ static int gizmo_ruler_modal(bContext *C, { bool do_draw = false; int exit_code = OPERATOR_RUNNING_MODAL; - RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gz->parent_gzgroup->customdata); RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = CTX_wm_region(C); bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE); @@ -1036,7 +1030,8 @@ static int gizmo_ruler_modal(bContext *C, const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP); #else /* Ensure snap is up to date. */ - ED_gizmotypes_snap_3d_data_get(C, ruler_info->snap_data.gizmo, NULL, NULL, NULL, NULL); + ED_gizmotypes_snap_3d_data_get( + C, ruler_info->snap_data.gizmo, nullptr, nullptr, nullptr, nullptr); const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo); #endif @@ -1066,9 +1061,9 @@ static int gizmo_ruler_modal(bContext *C, static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) { wmGizmoGroup *gzgroup = gz->parent_gzgroup; - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); RulerItem *ruler_item_pick = (RulerItem *)gz; - RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__); + RulerInteraction *inter = (RulerInteraction *)MEM_callocN(sizeof(RulerInteraction), __func__); gz->interaction_data = inter; ARegion *region = ruler_info->region; @@ -1091,7 +1086,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* find the factor */ { - float co_ss[2][2]; + float2x2 co_ss; float fac; ED_view3d_project_float_global( @@ -1102,8 +1097,8 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); CLAMP(fac, 0.0f, 1.0f); - interp_v3_v3v3( - ruler_item_pick->co[1], ruler_item_pick->co[0], ruler_item_pick->co[2], fac); + ruler_item_pick->co[1] = blender::math::interpolate( + ruler_item_pick->co[0], ruler_item_pick->co[2], fac); } /* update the new location */ @@ -1117,7 +1112,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) ruler_state_set(ruler_info, RULER_STATE_DRAG); /* store the initial depth */ - copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]); + inter->drag_start_co = ruler_item_pick->co[inter->co_index]; } if (inter->co_index == 1) { @@ -1129,20 +1124,20 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) { /* Set Snap prev point. */ - float *prev_point; + float3 *prev_point; if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) { - prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL; + prev_point = (inter->co_index != 1) ? &ruler_item_pick->co[1] : nullptr; } else if (inter->co_index == 0) { - prev_point = ruler_item_pick->co[2]; + prev_point = &ruler_item_pick->co[2]; } else { - prev_point = ruler_item_pick->co[0]; + prev_point = &ruler_item_pick->co[0]; } if (prev_point) { RNA_property_float_set_array( - ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point); } else { RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); @@ -1157,7 +1152,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) { wmGizmoGroup *gzgroup = gz->parent_gzgroup; - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { @@ -1205,21 +1200,21 @@ void VIEW3D_GT_ruler_item(wmGizmoType *gzt) static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) { - RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + RulerInfo *ruler_info = (RulerInfo *)MEM_callocN(sizeof(RulerInfo), __func__); wmGizmo *gizmo; { /* The gizmo snap has to be the first gizmo. */ const wmGizmoType *gzt_snap; gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); - gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, nullptr); RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM); ED_gizmotypes_snap_3d_flag_set(gizmo, V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE); - WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + WM_gizmo_set_color(gizmo, blender::float4(1.0f)); wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true); - WM_gizmo_operator_set(gizmo, 0, ot, NULL); + WM_gizmo_operator_set(gizmo, 0, ot, nullptr); } if (view3d_ruler_from_gpencil(C, gzgroup)) { @@ -1264,8 +1259,8 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt) static bool view3d_ruler_poll(bContext *C) { bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); - if ((tref_rt == NULL) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) || - CTX_wm_region_view3d(C) == NULL) { + if ((tref_rt == nullptr) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) || + CTX_wm_region_view3d(C) == nullptr) { return false; } return true; @@ -1298,10 +1293,10 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e /* This is a little weak, but there is no real good way to tweak directly. */ WM_gizmo_highlight_set(gzmap, &ruler_item->gz); if (WM_operator_name_call( - C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_REGION_WIN, NULL, event) == + C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_REGION_WIN, nullptr, event) == OPERATOR_RUNNING_MODAL) { - RulerInfo *ruler_info = gzgroup->customdata; - RulerInteraction *inter = ruler_item->gz.interaction_data; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); + RulerInteraction *inter = static_cast(ruler_item->gz.interaction_data); struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); inter->co_index = 0; @@ -1344,7 +1339,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot) /** \name Remove Ruler Operator * \{ */ -static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -1360,7 +1355,7 @@ static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent if (!gizmo_ruler_check_for_operator(gzgroup)) { return OPERATOR_CANCELLED; } - RulerInfo *ruler_info = gzgroup->customdata; + RulerInfo *ruler_info = static_cast(gzgroup->customdata); if (ruler_info->item_active) { RulerItem *ruler_item = ruler_info->item_active; if ((ruler_item->flag & RULERITEM_USE_ANGLE) && -- 2.30.2 From 80edd101684a4eb89819758ea80ab4dd796adb15 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:18:26 +1000 Subject: [PATCH 22/61] Fix regression in BLI_path_suffix for long extensions Changes from [0] passed in a pointer size to BLI_strncpy. [0]: f8e23e495b037a1e70e04406e421fa918a3d5bac --- source/blender/blenlib/intern/path_util.c | 2 +- source/blender/blenlib/tests/BLI_path_util_test.cc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 70cb1c7083e..aeb43401881 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -596,7 +596,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char if (string_len + sep_len + suffix_len >= maxlen) { return false; } - BLI_strncpy(extension_copy, string + string_end, sizeof(extension)); + BLI_strncpy(extension_copy, string + string_end, sizeof(extension_copy)); BLI_sprintf(string + string_end, "%s%s%s", sep, suffix, extension_copy); return true; } diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index db032ef0be7..6a56014d4d3 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -1010,6 +1010,11 @@ TEST(path_util, PathSuffix) PATH_SUFFIX("", FILE_MAX, "_", "123", true, "_123"); /* Empty input/output. */ PATH_SUFFIX("", FILE_MAX, "", "", true, ""); + + /* Long suffix. */ + PATH_SUFFIX("file.txt", FILE_MAX, "_", "1234567890", true, "file_1234567890.txt"); + /* Long extension. */ + PATH_SUFFIX("file.txt1234567890", FILE_MAX, "_", "123", true, "file_123.txt1234567890"); } #undef PATH_SUFFIX -- 2.30.2 From 5294758830be77a5f0f07fcc7216fe5d8c9ca192 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:45:05 +1000 Subject: [PATCH 23/61] Fix buffer overflow in BLI_path_frame_strip with long extensions The file extension was copied into a buffer without checking it's size. While large extensions aren't typical, some callers used small fixed size buffers so an unusually named file could crash. --- source/blender/blenkernel/intern/cachefile.c | 2 +- source/blender/blenkernel/intern/volume.cc | 2 +- source/blender/blenlib/BLI_path_util.h | 2 +- source/blender/blenlib/intern/path_util.c | 5 ++--- source/blender/blenlib/tests/BLI_path_util_test.cc | 2 +- source/blender/editors/space_sequencer/sequencer_add.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 530445c806c..e0a1e98f164 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -399,7 +399,7 @@ bool BKE_cachefile_filepath_get(const Main *bmain, const int frame = (int)BKE_cachefile_time_offset(cache_file, (double)ctime, fps); char ext[32]; - BLI_path_frame_strip(r_filepath, ext); + BLI_path_frame_strip(r_filepath, ext, sizeof(ext)); BLI_path_frame(r_filepath, frame, frame_len); BLI_path_extension_ensure(r_filepath, FILE_MAX, ext); diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 39e94c4d888..68ec2b7957a 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -768,7 +768,7 @@ static void volume_filepath_get(const Main *bmain, const Volume *volume, char r_ int path_frame, path_digits; if (volume->is_sequence && BLI_path_frame_get(r_filepath, &path_frame, &path_digits)) { char ext[32]; - BLI_path_frame_strip(r_filepath, ext); + BLI_path_frame_strip(r_filepath, ext, sizeof(ext)); BLI_path_frame(r_filepath, volume->runtime.frame, path_digits); BLI_path_extension_ensure(r_filepath, FILE_MAX, ext); } diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 37458402bd2..177be777031 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -416,7 +416,7 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_ * So: `/some/path_123.jpeg` * Becomes: `/some/path_###` with `r_ext` set to `.jpeg`. */ -void BLI_path_frame_strip(char *path, char *r_ext) ATTR_NONNULL(); +void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxlen) ATTR_NONNULL(); /** * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index aeb43401881..5069bd40ca6 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -771,7 +771,7 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) return true; } -void BLI_path_frame_strip(char *path, char *r_ext) +void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen) { *r_ext = '\0'; if (*path == '\0') { @@ -791,8 +791,7 @@ void BLI_path_frame_strip(char *path, char *r_ext) } c++; - int suffix_length = file_len - (suffix - file); - memcpy(r_ext, suffix, suffix_length + 1); + BLI_strncpy(r_ext, suffix, ext_maxlen); /* replace the number with the suffix and terminate the string */ while (digits_len--) { diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 6a56014d4d3..b7b98cd0dd3 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -655,7 +655,7 @@ TEST(path_util, SplitDirfile) char path[FILE_MAX]; \ char ext[FILE_MAX]; \ BLI_strncpy(path, (input_path), FILE_MAX); \ - BLI_path_frame_strip(path, ext); \ + BLI_path_frame_strip(path, ext, sizeof(ext)); \ EXPECT_STREQ(path, expect_path); \ EXPECT_STREQ(ext, expect_ext); \ } \ diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index e20f2b63d53..87b733168bf 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -1242,7 +1242,7 @@ void sequencer_image_seq_reserve_frames( char ext[PATH_MAX]; char filename_stripped[PATH_MAX]; /* Strip the frame from filename and substitute with `#`. */ - BLI_path_frame_strip(filename, ext); + BLI_path_frame_strip(filename, ext, sizeof(ext)); for (int i = 0; i < len; i++, se++) { BLI_strncpy(filename_stripped, filename, sizeof(filename_stripped)); -- 2.30.2 From 7cc7cd0e80870fe8441692327dd5c6ddc4a30509 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:20 +1000 Subject: [PATCH 24/61] Cleanup: use a define for all style flags This ensures new styles only need to be added in one place. --- source/blender/blenkernel/BKE_vfont.h | 5 +++-- source/blender/blenkernel/intern/vfont.c | 3 +-- source/blender/makesdna/DNA_curve_types.h | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_vfont.h b/source/blender/blenkernel/BKE_vfont.h index 73d24bfa155..f410a0a25b0 100644 --- a/source/blender/blenkernel/BKE_vfont.h +++ b/source/blender/blenkernel/BKE_vfont.h @@ -53,8 +53,9 @@ typedef struct EditFont { int selstart, selend; /** - * Combined styles (#CharInfo.flag) for selected string. A flag will be - * set only if ALL characters in the selected string have it. + * Combined styles from #CharInfo.flag for the selected range selected + * (only including values from #CU_CHINFO_STYLE_ALL). + * A flag will be set only if ALL characters in the selected string have it. */ int select_char_info_flag; diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c index f7a3b18b438..20b772d6c78 100644 --- a/source/blender/blenkernel/intern/vfont.c +++ b/source/blender/blenkernel/intern/vfont.c @@ -1143,8 +1143,7 @@ static bool vfont_to_curve(Object *ob, if (ef && ef->selboxes) { /* Set combined style flags for the selected string. Start with all styles then * remove one if ANY characters do not have it. Break out if we've removed them all. */ - ef->select_char_info_flag = CU_CHINFO_BOLD | CU_CHINFO_ITALIC | CU_CHINFO_UNDERLINE | - CU_CHINFO_SMALLCAPS; + ef->select_char_info_flag = CU_CHINFO_STYLE_ALL; for (int k = selstart; k <= selend && ef->select_char_info_flag; k++) { info = &custrinfo[k]; ef->select_char_info_flag &= info->flag; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 7829c5d3f44..c659069c19a 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -602,6 +602,10 @@ enum { CU_CHINFO_OVERFLOW = 1 << 6, }; +/** User adjustable as styles (not relating to run-time layout calculation). */ +#define CU_CHINFO_STYLE_ALL \ + (CU_CHINFO_BOLD | CU_CHINFO_ITALIC | CU_CHINFO_UNDERLINE | CU_CHINFO_SMALLCAPS) + /* mixed with KEY_LINEAR but define here since only curve supports */ #define KEY_CU_EASE 3 -- 2.30.2 From 373cfa731f03ccd24645aef92fe3ebcd92ab68f6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:22 +1000 Subject: [PATCH 25/61] Cleanup: use EXPECT_STREQ instead of EXPECT_EQ_ARRAY While both work, the output of strings being different is more useful. --- source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 161c2817ba3..8028419ef10 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -99,7 +99,7 @@ TEST(obj_exporter_utils, append_negative_frame_to_filename) char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); EXPECT_TRUE(ok); - EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); + EXPECT_STREQ(path_with_frame, path_truth); } TEST(obj_exporter_utils, append_positive_frame_to_filename) @@ -110,7 +110,7 @@ TEST(obj_exporter_utils, append_positive_frame_to_filename) char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); EXPECT_TRUE(ok); - EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); + EXPECT_STREQ(path_with_frame, path_truth); } static std::string read_temp_file_in_string(const std::string &file_path) -- 2.30.2 From b6e527febb68ed79cba93d867d5f2961f7b7b529 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:23 +1000 Subject: [PATCH 26/61] Tests: add more path extension tests --- source/blender/blenlib/tests/BLI_path_util_test.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index b7b98cd0dd3..29f16036689 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -771,7 +771,7 @@ TEST(path_util, PathExtensionReplace) { PATH_EXTENSION_REPLACE("test", ".txt", true, "test.txt"); PATH_EXTENSION_REPLACE("test.", ".txt", true, "test.txt"); - /* Unlike #BLI_path_extension_ensure, exceeds '.' are not stripped. */ + /* Unlike #BLI_path_extension_ensure, excess '.' are not stripped. */ PATH_EXTENSION_REPLACE("test..", ".txt", true, "test..txt"); PATH_EXTENSION_REPLACE("test.txt", ".txt", true, "test.txt"); @@ -780,8 +780,15 @@ TEST(path_util, PathExtensionReplace) PATH_EXTENSION_REPLACE("test", "_txt", true, "test_txt"); PATH_EXTENSION_REPLACE("test.ext", "_txt", true, "test_txt"); + PATH_EXTENSION_REPLACE("test", "", true, "test"); + + /* Same as #BLI_path_extension_strip. */ + PATH_EXTENSION_REPLACE("test.txt", "", true, "test"); + + /* Empty strings. */ PATH_EXTENSION_REPLACE("test", "", true, "test"); PATH_EXTENSION_REPLACE("", "_txt", true, "_txt"); + PATH_EXTENSION_REPLACE("", "", true, ""); /* Ensure leading '.' isn't treated as an extension. */ PATH_EXTENSION_REPLACE(".hidden", ".hidden", true, ".hidden.hidden"); @@ -823,8 +830,13 @@ TEST(path_util, PathExtensionEnsure) PATH_EXTENSION_ENSURE("test", "_txt", true, "test_txt"); PATH_EXTENSION_ENSURE("test.ext", "_txt", true, "test.ext_txt"); + /* An empty string does nothing (unlike replace which strips). */ + PATH_EXTENSION_ENSURE("test.txt", "", true, "test.txt"); + + /* Empty strings. */ PATH_EXTENSION_ENSURE("test", "", true, "test"); PATH_EXTENSION_ENSURE("", "_txt", true, "_txt"); + PATH_EXTENSION_ENSURE("", "", true, ""); /* Ensure leading '.' isn't treated as an extension. */ PATH_EXTENSION_ENSURE(".hidden", ".hidden", true, ".hidden.hidden"); -- 2.30.2 From 9be0304b676e25147ddffe4e64f97cfa7aadfbbd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:25 +1000 Subject: [PATCH 27/61] Cleanup: order expected value last in path_util tests --- .../blenlib/tests/BLI_path_util_test.cc | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 29f16036689..5db568c90f2 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -42,7 +42,7 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) /** \name Tests for: #BLI_path_normalize * \{ */ -#define NORMALIZE_WITH_BASEDIR(input, input_base, output) \ +#define NORMALIZE_WITH_BASEDIR(input, input_base, output_expect) \ { \ char path[FILE_MAX] = input; \ const char *input_base_test = input_base; \ @@ -57,11 +57,11 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) free((void *)input_base_test); \ } \ } \ - EXPECT_STREQ(output, path); \ + EXPECT_STREQ(path, output_expect); \ } \ ((void)0) -#define NORMALIZE(input, output) NORMALIZE_WITH_BASEDIR(input, nullptr, output) +#define NORMALIZE(input, output_expect) NORMALIZE_WITH_BASEDIR(input, nullptr, output_expect) /* #BLI_path_normalize: "/./" -> "/" */ TEST(path_util, Clean_Dot) @@ -102,7 +102,7 @@ TEST(path_util, Clean_Parent) /** \name Tests for: #BLI_path_parent_dir * \{ */ -#define PARENT_DIR(input, output) \ +#define PARENT_DIR(input, output_expect) \ { \ char path[FILE_MAX] = input; \ if (SEP == '\\') { \ @@ -112,7 +112,7 @@ TEST(path_util, Clean_Parent) if (SEP == '\\') { \ BLI_str_replace_char(path, '\\', '/'); \ } \ - EXPECT_STREQ(output, path); \ + EXPECT_STREQ(path, output_expect); \ } \ ((void)0) @@ -177,7 +177,7 @@ TEST(path_util, ParentDir_Complex) } \ else { \ EXPECT_TRUE(ret); \ - EXPECT_EQ(strlen(expect), len_output); \ + EXPECT_EQ(len_output, strlen(expect)); \ path[index_output + len_output] = '\0'; \ EXPECT_STREQ(&path[index_output], expect); \ } \ @@ -515,42 +515,42 @@ TEST(path_util, Frame) char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 1); EXPECT_TRUE(ret); - EXPECT_STREQ("123", path); + EXPECT_STREQ(path, "123"); } { char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 12); EXPECT_TRUE(ret); - EXPECT_STREQ("000000000123", path); + EXPECT_STREQ(path, "000000000123"); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 123, 1); EXPECT_TRUE(ret); - EXPECT_STREQ("test_123", path); + EXPECT_STREQ(path, "test_123"); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 1, 12); EXPECT_TRUE(ret); - EXPECT_STREQ("test_000000000001", path); + EXPECT_STREQ(path, "test_000000000001"); } { char path[FILE_MAX] = "test_############"; ret = BLI_path_frame(path, 1, 0); EXPECT_TRUE(ret); - EXPECT_STREQ("test_000000000001", path); + EXPECT_STREQ(path, "test_000000000001"); } { char path[FILE_MAX] = "test_#_#_middle"; ret = BLI_path_frame(path, 123, 0); EXPECT_TRUE(ret); - EXPECT_STREQ("test_#_123_middle", path); + EXPECT_STREQ(path, "test_#_123_middle"); } /* intentionally fail */ @@ -558,14 +558,14 @@ TEST(path_util, Frame) char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 0); EXPECT_FALSE(ret); - EXPECT_STREQ("", path); + EXPECT_STREQ(path, ""); } { char path[FILE_MAX] = "test_middle"; ret = BLI_path_frame(path, 123, 0); EXPECT_FALSE(ret); - EXPECT_STREQ("test_middle", path); + EXPECT_STREQ(path, "test_middle"); } /* negative frame numbers */ @@ -573,13 +573,13 @@ TEST(path_util, Frame) char path[FILE_MAX] = "test_####"; ret = BLI_path_frame(path, -1, 4); EXPECT_TRUE(ret); - EXPECT_STREQ("test_-0001", path); + EXPECT_STREQ(path, "test_-0001"); } { char path[FILE_MAX] = "test_####"; ret = BLI_path_frame(path, -100, 4); EXPECT_TRUE(ret); - EXPECT_STREQ("test_-0100", path); + EXPECT_STREQ(path, "test_-0100"); } } @@ -595,52 +595,52 @@ TEST(path_util, SplitDirfile) const char *path = ""; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, ""); } { const char *path = "/"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, "/"); + EXPECT_STREQ(file, ""); } { const char *path = "fileonly"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("", dir); - EXPECT_STREQ("fileonly", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, "fileonly"); } { const char *path = "dironly/"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("dironly/", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, "dironly/"); + EXPECT_STREQ(file, ""); } { const char *path = "/a/b"; char dir[FILE_MAX], file[FILE_MAX]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/a/", dir); - EXPECT_STREQ("b", file); + EXPECT_STREQ(dir, "/a/"); + EXPECT_STREQ(file, "b"); } { const char *path = "/dirtoobig/filetoobig"; char dir[5], file[5]; BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - EXPECT_STREQ("/dir", dir); - EXPECT_STREQ("file", file); + EXPECT_STREQ(dir, "/dir"); + EXPECT_STREQ(file, "file"); BLI_split_dirfile(path, dir, file, 1, 1); - EXPECT_STREQ("", dir); - EXPECT_STREQ("", file); + EXPECT_STREQ(dir, ""); + EXPECT_STREQ(file, ""); } } @@ -680,27 +680,27 @@ TEST(path_util, PathFrameStrip) TEST(path_util, PathExtension) { - EXPECT_EQ(nullptr, BLI_path_extension("some.def/file")); - EXPECT_EQ(nullptr, BLI_path_extension("Text")); - EXPECT_EQ(nullptr, BLI_path_extension("Text…001")); - EXPECT_EQ(nullptr, BLI_path_extension(".hidden")); - EXPECT_EQ(nullptr, BLI_path_extension(".hidden/")); - EXPECT_EQ(nullptr, BLI_path_extension("/.hidden")); - EXPECT_EQ(nullptr, BLI_path_extension("dir/.hidden")); - EXPECT_EQ(nullptr, BLI_path_extension("/dir/.hidden")); + EXPECT_EQ(BLI_path_extension("some.def/file"), nullptr); + EXPECT_EQ(BLI_path_extension("Text"), nullptr); + EXPECT_EQ(BLI_path_extension("Text…001"), nullptr); + EXPECT_EQ(BLI_path_extension(".hidden"), nullptr); + EXPECT_EQ(BLI_path_extension(".hidden/"), nullptr); + EXPECT_EQ(BLI_path_extension("/.hidden"), nullptr); + EXPECT_EQ(BLI_path_extension("dir/.hidden"), nullptr); + EXPECT_EQ(BLI_path_extension("/dir/.hidden"), nullptr); - EXPECT_EQ(nullptr, BLI_path_extension(".")); - EXPECT_EQ(nullptr, BLI_path_extension("..")); - EXPECT_EQ(nullptr, BLI_path_extension("...")); - EXPECT_STREQ(".", BLI_path_extension("...a.")); - EXPECT_STREQ(".", BLI_path_extension("...a..")); - EXPECT_EQ(nullptr, BLI_path_extension("...a../")); + EXPECT_EQ(BLI_path_extension("."), nullptr); + EXPECT_EQ(BLI_path_extension(".."), nullptr); + EXPECT_EQ(BLI_path_extension("..."), nullptr); + EXPECT_STREQ(BLI_path_extension("...a."), "."); + EXPECT_STREQ(BLI_path_extension("...a.."), "."); + EXPECT_EQ(BLI_path_extension("...a../"), nullptr); - EXPECT_STREQ(".", BLI_path_extension("some/file.")); - EXPECT_STREQ(".gz", BLI_path_extension("some/file.tar.gz")); - EXPECT_STREQ(".abc", BLI_path_extension("some.def/file.abc")); - EXPECT_STREQ(".abc", BLI_path_extension("C:\\some.def\\file.abc")); - EXPECT_STREQ(".001", BLI_path_extension("Text.001")); + EXPECT_STREQ(BLI_path_extension("some/file."), "."); + EXPECT_STREQ(BLI_path_extension("some/file.tar.gz"), ".gz"); + EXPECT_STREQ(BLI_path_extension("some.def/file.abc"), ".abc"); + EXPECT_STREQ(BLI_path_extension("C:\\some.def\\file.abc"), ".abc"); + EXPECT_STREQ(BLI_path_extension("Text.001"), ".001"); } /** \} */ @@ -763,7 +763,7 @@ TEST(path_util, PathExtensionCheck) else { \ EXPECT_FALSE(ret); \ } \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_STREQ(path, expect_path); \ } \ ((void)0) @@ -814,7 +814,7 @@ TEST(path_util, PathExtensionReplace) else { \ EXPECT_FALSE(ret); \ } \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_STREQ(path, expect_path); \ } \ ((void)0) @@ -966,10 +966,10 @@ TEST(path_util, PathFrameGet) char tail[FILE_MAX]; \ ushort numdigits = 0; \ const int result = BLI_path_sequence_decode(path, head, tail, &numdigits); \ - EXPECT_EQ(expect_result, result); \ - EXPECT_STREQ(expect_head, head); \ - EXPECT_STREQ(expect_tail, tail); \ - EXPECT_EQ(expect_numdigits, numdigits); \ + EXPECT_EQ(result, expect_result); \ + EXPECT_STREQ(head, expect_head); \ + EXPECT_STREQ(tail, expect_tail); \ + EXPECT_EQ(numdigits, expect_numdigits); \ } \ (void)0; @@ -999,8 +999,8 @@ TEST(path_util, PathSequenceDecode) { \ char path[FILE_MAX] = path_literal; \ const bool result = BLI_path_suffix(path, path_literal_max, suffix, sep); \ - EXPECT_EQ(expect_result, result); \ - EXPECT_STREQ(expect_path, path); \ + EXPECT_EQ(result, expect_result); \ + EXPECT_STREQ(path, expect_path); \ } \ (void)0; @@ -1037,7 +1037,7 @@ TEST(path_util, PathSuffix) /** \name Tests for: #BLI_path_rel * \{ */ -#define PATH_REL(abs_path, ref_path, rel_path) \ +#define PATH_REL(abs_path, ref_path, rel_path_expect) \ { \ char path[FILE_MAX]; \ const char *ref_path_test = ref_path; \ @@ -1051,7 +1051,7 @@ TEST(path_util, PathSuffix) BLI_str_replace_char(path, '\\', '/'); \ free((void *)ref_path_test); \ } \ - EXPECT_STREQ(rel_path, path); \ + EXPECT_STREQ(path, rel_path_expect); \ } \ void(0) -- 2.30.2 From 95296dc3aa5671bceb47ccb9c3570c5841117343 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:27 +1000 Subject: [PATCH 28/61] Cleanup: remove "Path" prefix from path_utils tests --- .../blenlib/tests/BLI_path_util_test.cc | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 5db568c90f2..4c17b3138f9 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -661,7 +661,7 @@ TEST(path_util, SplitDirfile) } \ ((void)0) -TEST(path_util, PathFrameStrip) +TEST(path_util, FrameStrip) { PATH_FRAME_STRIP("", "", ""); PATH_FRAME_STRIP("nonum.abc", "nonum", ".abc"); @@ -678,7 +678,7 @@ TEST(path_util, PathFrameStrip) /** \name Tests for: #BLI_path_extension * \{ */ -TEST(path_util, PathExtension) +TEST(path_util, Extension) { EXPECT_EQ(BLI_path_extension("some.def/file"), nullptr); EXPECT_EQ(BLI_path_extension("Text"), nullptr); @@ -721,7 +721,7 @@ TEST(path_util, PathExtension) } \ ((void)0) -TEST(path_util, PathExtensionCheck) +TEST(path_util, ExtensionCheck) { PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe"); PATH_EXTENSION_CHECK("correct/path/to/file.h", ".h", ".h"); @@ -767,7 +767,7 @@ TEST(path_util, PathExtensionCheck) } \ ((void)0) -TEST(path_util, PathExtensionReplace) +TEST(path_util, ExtensionReplace) { PATH_EXTENSION_REPLACE("test", ".txt", true, "test.txt"); PATH_EXTENSION_REPLACE("test.", ".txt", true, "test.txt"); @@ -818,7 +818,7 @@ TEST(path_util, PathExtensionReplace) } \ ((void)0) -TEST(path_util, PathExtensionEnsure) +TEST(path_util, ExtensionEnsure) { PATH_EXTENSION_ENSURE("test", ".txt", true, "test.txt"); PATH_EXTENSION_ENSURE("test.", ".txt", true, "test.txt"); @@ -863,7 +863,7 @@ TEST(path_util, PathExtensionEnsure) } \ ((void)0) -TEST(path_util, PathFrameCheckChars) +TEST(path_util, FrameCheckChars) { PATH_FRAME_CHECK_CHARS("a#", true); PATH_FRAME_CHECK_CHARS("aaaaa#", true); @@ -904,7 +904,7 @@ TEST(path_util, PathFrameCheckChars) } \ ((void)0) -TEST(path_util, PathFrameRange) +TEST(path_util, FrameRange) { int dummy = -1; PATH_FRAME_RANGE("#", 1, 2, dummy, "1-2"); @@ -942,7 +942,7 @@ TEST(path_util, PathFrameRange) } \ ((void)0) -TEST(path_util, PathFrameGet) +TEST(path_util, FrameGet) { PATH_FRAME_GET("001.avi", 1, 3, true); PATH_FRAME_GET("0000299.ext", 299, 7, true); @@ -973,7 +973,7 @@ TEST(path_util, PathFrameGet) } \ (void)0; -TEST(path_util, PathSequenceDecode) +TEST(path_util, SequenceDecode) { /* Basic use. */ PATH_SEQ_DECODE("file_123.txt", 123, "file_", ".txt", 3); @@ -1004,7 +1004,7 @@ TEST(path_util, PathSequenceDecode) } \ (void)0; -TEST(path_util, PathSuffix) +TEST(path_util, Suffix) { /* Extension. */ PATH_SUFFIX("file.txt", FILE_MAX, "_", "123", true, "file_123.txt"); @@ -1061,17 +1061,17 @@ TEST(path_util, PathSuffix) # define ABS_PREFIX "" #endif -TEST(path_util, PathRelPath_Simple) +TEST(path_util, RelPath_Simple) { PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar/", "//blender.blend"); } -TEST(path_util, PathRelPath_SimpleSubdir) +TEST(path_util, RelPath_SimpleSubdir) { PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar", "//bar/blender.blend"); } -TEST(path_util, PathRelPath_BufferOverflowRoot) +TEST(path_util, RelPath_BufferOverflowRoot) { char abs_path_in[FILE_MAX]; const char *abs_prefix = ABS_PREFIX "/"; @@ -1087,7 +1087,7 @@ TEST(path_util, PathRelPath_BufferOverflowRoot) PATH_REL(abs_path_in, abs_prefix, abs_path_out); } -TEST(path_util, PathRelPath_BufferOverflowSubdir) +TEST(path_util, RelPath_BufferOverflowSubdir) { char abs_path_in[FILE_MAX]; const char *ref_path_in = ABS_PREFIX "/foo/bar/"; @@ -1113,7 +1113,7 @@ TEST(path_util, PathRelPath_BufferOverflowSubdir) /** \name Tests for: #BLI_path_contains * \{ */ -TEST(path_util, PathContains) +TEST(path_util, Contains) { EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself"; EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/inside")) @@ -1136,7 +1136,7 @@ TEST(path_util, PathContains) } #ifdef WIN32 -TEST(path_util, PathContains_Windows_case_insensitive) +TEST(path_util, Contains_Windows_case_insensitive) { EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "c:\\SOME\\path\\inside")) << "On Windows path comparison should ignore case"; -- 2.30.2 From 7884de02f301b91e0141e9e12db7e7db2a528815 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:29 +1000 Subject: [PATCH 29/61] Tests: add BLI_path_extension replace/ensure tests for overflow handling --- .../blenlib/tests/BLI_path_util_test.cc | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 4c17b3138f9..85907889616 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -752,11 +752,13 @@ TEST(path_util, ExtensionCheck) /** \name Tests for: #BLI_path_extension_replace * \{ */ -#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path) \ +#define PATH_EXTENSION_REPLACE_WITH_MAXLEN( \ + input_path, input_ext, expect_result, expect_path, maxlen) \ { \ + BLI_assert(maxlen <= FILE_MAX); \ char path[FILE_MAX]; \ - BLI_strncpy(path, input_path, FILE_MAX); \ - const bool ret = BLI_path_extension_replace(path, sizeof(path), input_ext); \ + BLI_strncpy(path, input_path, sizeof(path)); \ + const bool ret = BLI_path_extension_replace(path, maxlen, input_ext); \ if (expect_result) { \ EXPECT_TRUE(ret); \ } \ @@ -767,6 +769,9 @@ TEST(path_util, ExtensionCheck) } \ ((void)0) +#define PATH_EXTENSION_REPLACE(input_path, input_ext, expect_result, expect_path) \ + PATH_EXTENSION_REPLACE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX) + TEST(path_util, ExtensionReplace) { PATH_EXTENSION_REPLACE("test", ".txt", true, "test.txt"); @@ -795,7 +800,22 @@ TEST(path_util, ExtensionReplace) PATH_EXTENSION_REPLACE("..hidden", ".hidden", true, "..hidden.hidden"); PATH_EXTENSION_REPLACE("._.hidden", ".hidden", true, "._.hidden"); } + +TEST(path_util, ExtensionReplace_Overflow) +{ + /* Small values. */ + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 0); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 1); + /* One under fails, and exactly enough space succeeds. */ + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", false, "test", 8); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9); + + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", false, "test.xx", 8); + PATH_EXTENSION_REPLACE_WITH_MAXLEN("test.xx", ".txt", true, "test.txt", 9); +} + #undef PATH_EXTENSION_REPLACE +#undef PATH_EXTENSION_REPLACE_WITH_MAXLEN /** \} */ @@ -803,11 +823,13 @@ TEST(path_util, ExtensionReplace) /** \name Tests for: #BLI_path_extension_ensure * \{ */ -#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path) \ +#define PATH_EXTENSION_ENSURE_WITH_MAXLEN( \ + input_path, input_ext, expect_result, expect_path, maxlen) \ { \ + BLI_assert(maxlen <= FILE_MAX); \ char path[FILE_MAX]; \ - BLI_strncpy(path, input_path, FILE_MAX); \ - const bool ret = BLI_path_extension_ensure(path, sizeof(path), input_ext); \ + BLI_strncpy(path, input_path, sizeof(path)); \ + const bool ret = BLI_path_extension_ensure(path, maxlen, input_ext); \ if (expect_result) { \ EXPECT_TRUE(ret); \ } \ @@ -818,6 +840,9 @@ TEST(path_util, ExtensionReplace) } \ ((void)0) +#define PATH_EXTENSION_ENSURE(input_path, input_ext, expect_result, expect_path) \ + PATH_EXTENSION_ENSURE_WITH_MAXLEN(input_path, input_ext, expect_result, expect_path, FILE_MAX) + TEST(path_util, ExtensionEnsure) { PATH_EXTENSION_ENSURE("test", ".txt", true, "test.txt"); @@ -843,7 +868,19 @@ TEST(path_util, ExtensionEnsure) PATH_EXTENSION_ENSURE("..hidden", ".hidden", true, "..hidden.hidden"); PATH_EXTENSION_ENSURE("._.hidden", ".hidden", true, "._.hidden"); } + +TEST(path_util, ExtensionEnsure_Overflow) +{ + /* Small values. */ + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 0); + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 1); + /* One under fails, and exactly enough space succeeds. */ + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", false, "test", 8); + PATH_EXTENSION_ENSURE_WITH_MAXLEN("test", ".txt", true, "test.txt", 9); +} + #undef PATH_EXTENSION_ENSURE +#undef PATH_EXTENSION_ENSURE_WITH_MAXLEN /** \} */ -- 2.30.2 From b778e094923b085e0a1b04050d757fd0a2c220bc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:30 +1000 Subject: [PATCH 30/61] Cleanup: use memmove instead of a string copy for BLI_path_suffix --- source/blender/blenlib/intern/path_util.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 5069bd40ca6..9d1fc90ef52 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -590,14 +590,27 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char const size_t string_len = strlen(string); const size_t suffix_len = strlen(suffix); const size_t sep_len = strlen(sep); - const char *const extension = BLI_path_extension(string); + char *extension = (char *)BLI_path_extension(string); + const size_t extension_len = extension ? (((string + string_len) - extension)) : 0; const size_t string_end = extension != NULL ? (int)((extension - string)) : string_len; - char extension_copy[FILE_MAX]; if (string_len + sep_len + suffix_len >= maxlen) { return false; } - BLI_strncpy(extension_copy, string + string_end, sizeof(extension_copy)); - BLI_sprintf(string + string_end, "%s%s%s", sep, suffix, extension_copy); + + if (extension) { + memmove(extension + (sep_len + suffix_len), extension, extension_len); + } + char *c = string + string_end; + if (sep_len) { + memcpy(c, sep, sep_len); + c += sep_len; + } + if (suffix_len) { + memcpy(c, suffix, suffix_len); + c += suffix_len; + } + c += extension_len; + *c = '\0'; return true; } -- 2.30.2 From 639ec2e5a948e820e307c11fe662f5fa97134204 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 11:58:32 +1000 Subject: [PATCH 31/61] BLI_path: add BLI_path_extension_or_end Some callers that access the extension operated on the end of the path even when there was no extension. Using this avoids having to assign the end of the string using a separate check. --- source/blender/blenlib/BLI_path_util.h | 6 +++ source/blender/blenlib/intern/path_util.c | 59 ++++++++++++----------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 177be777031..4e3564eaa0a 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -60,6 +60,12 @@ void BLI_split_dir_part(const char *string, char *dir, size_t dirlen); * Copies the leaf filename part of string into `file`, max length `filelen`. */ void BLI_split_file_part(const char *string, char *file, size_t filelen); +/** + * Returns a pointer to the last extension (e.g. the position of the last period). + * Returns a pointer to the nil byte when no extension is found. + */ +const char *BLI_path_extension_or_end(const char *filepath) + ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL; /** * Returns a pointer to the last extension (e.g. the position of the last period). * Returns NULL if there is no extension. diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 9d1fc90ef52..96d24812063 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -59,9 +59,9 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort int i; bool found_digit = false; const char *const lslash = BLI_path_slash_rfind(string); - const char *const extension = BLI_path_extension(lslash ? lslash : string); + const char *const extension = BLI_path_extension_or_end(lslash ? lslash : string); const uint lslash_len = lslash != NULL ? (int)(lslash - string) : 0; - const uint name_end = extension != NULL ? (int)((extension - string)) : strlen(string); + const uint name_end = (uint)(extension - string); for (i = name_end - 1; i >= (int)lslash_len; i--) { if (isdigit(string[i])) { @@ -587,17 +587,17 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char #ifdef DEBUG_STRSIZE memset(string, 0xff, sizeof(*string) * maxlen); #endif - const size_t string_len = strlen(string); const size_t suffix_len = strlen(suffix); const size_t sep_len = strlen(sep); - char *extension = (char *)BLI_path_extension(string); - const size_t extension_len = extension ? (((string + string_len) - extension)) : 0; - const size_t string_end = extension != NULL ? (int)((extension - string)) : string_len; + char *extension = (char *)BLI_path_extension_or_end(string); + const size_t extension_len = strlen(extension); + const size_t string_end = extension - string; + const size_t string_len = string_end + extension_len; if (string_len + sep_len + suffix_len >= maxlen) { return false; } - if (extension) { + if (extension_len) { memmove(extension + (sep_len + suffix_len), extension, extension_len); } char *c = string + string_end; @@ -763,9 +763,8 @@ bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) *r_digits_len = 0; const char *file = BLI_path_basename(path); - const char *file_ext = BLI_path_extension(file); - const int file_len = strlen(file); - const char *c = file_ext ? file_ext : file + file_len; + const char *file_ext = BLI_path_extension_or_end(file); + const char *c = file_ext; /* Find start of number (if there is one). */ int digits_len = 0; @@ -792,10 +791,8 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen) } char *file = (char *)BLI_path_basename(path); - char *file_ext = (char *)BLI_path_extension(file); - const int file_len = strlen(file); - char *c = file_ext ? file_ext : file + file_len; - char *suffix = c; + char *file_ext = (char *)BLI_path_extension_or_end(file); + char *c = file_ext; /* Find start of number (if there is one). */ int digits_len = 0; @@ -804,9 +801,9 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen) } c++; - BLI_strncpy(r_ext, suffix, ext_maxlen); + BLI_strncpy(r_ext, file_ext, ext_maxlen); - /* replace the number with the suffix and terminate the string */ + /* Replace the number with the suffix and terminate the string. */ while (digits_len--) { *c++ = '#'; } @@ -1276,11 +1273,7 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) #ifdef DEBUG_STRSIZE memset(path, 0xff, sizeof(*path) * maxlen); #endif - char *path_ext = (char *)BLI_path_extension(path); - if (path_ext == NULL) { - path_ext = path + strlen(path); - } - + char *path_ext = (char *)BLI_path_extension_or_end(path); const size_t ext_len = strlen(ext); if ((path_ext - path) + ext_len >= maxlen) { return false; @@ -1305,9 +1298,10 @@ bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) #ifdef DEBUG_STRSIZE memset(path, 0xff, sizeof(*path) * maxlen); #endif - /* First check the extension is already there. */ - char *path_ext = (char *)BLI_path_extension(path); - if (path_ext && STREQ(path_ext, ext)) { + /* First check the extension is already there. + * If `path_ext` is the end of the string this is simply checking if `ext` is also empty. */ + const char *path_ext = BLI_path_extension_or_end(path); + if (STREQ(path_ext, ext)) { return true; } @@ -1381,7 +1375,7 @@ void BLI_split_file_part(const char *string, char *file, const size_t filelen) BLI_split_dirfile(string, NULL, file, 0, filelen); } -const char *BLI_path_extension(const char *filepath) +const char *BLI_path_extension_or_end(const char *filepath) { /* NOTE(@ideasman42): Skip the extension when there are no preceding non-extension characters in * the file name. This ignores extensions at the beginning of a string or directly after a slash. @@ -1390,7 +1384,8 @@ const char *BLI_path_extension(const char *filepath) * Matches Python's `os.path.splitext`. */ const char *ext = NULL; bool has_non_ext = false; - for (const char *c = filepath; *c; c++) { + const char *c = filepath; + for (; *c; c++) { switch (*c) { case '.': { if (has_non_ext) { @@ -1410,7 +1405,17 @@ const char *BLI_path_extension(const char *filepath) } } } - return ext; + if (ext) { + return ext; + } + BLI_assert(*c == '\0'); + return c; +} + +const char *BLI_path_extension(const char *filepath) +{ + const char *ext = BLI_path_extension_or_end(filepath); + return *ext ? ext : NULL; } size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) -- 2.30.2 From b633b460b849a41885d95ff11150cd890089f03c Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 16:47:42 -0400 Subject: [PATCH 32/61] Cleanup: STL Import: Use utility to copy corner verts data --- source/blender/io/stl/importer/stl_import_mesh.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index 799fd3bdf6a..34104348c7d 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -10,6 +10,7 @@ #include "BKE_mesh.hh" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "BLI_math_vector.h" #include "BLI_math_vector.hh" #include "BLI_task.hh" @@ -82,14 +83,7 @@ Mesh *STLMeshHelper::to_mesh() } }); - MutableSpan corner_verts = mesh->corner_verts_for_write(); - threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { - for (const int i : tris_range) { - corner_verts[3 * i] = tris_[i].v1; - corner_verts[3 * i + 1] = tris_[i].v2; - corner_verts[3 * i + 2] = tris_[i].v3; - } - }); + array_utils::copy(tris_.as_span().cast(), mesh->corner_verts_for_write()); /* NOTE: edges must be calculated first before setting custom normals. */ BKE_mesh_calc_edges(mesh, false, false); -- 2.30.2 From 3e41b982959a7fe86b92398d8741d31615f0c444 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 17:09:41 -0400 Subject: [PATCH 33/61] Cleanup: Use utility to create mesh in metaball tessellation Avoid the need to add each data array manually. --- .../blenkernel/intern/mball_tessellate.cc | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index 8c936cead41..96cb2cc7e52 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1451,18 +1451,17 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) freepolygonize(&process); - Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); + int corners_num = 0; + for (uint i = 0; i < process.curindex; i++) { + const int *indices = process.indices[i]; + const int count = indices[2] != indices[3] ? 4 : 3; + corners_num += count; + } - mesh->totvert = int(process.co.size()); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); + Mesh *mesh = BKE_mesh_new_nomain(int(process.co.size()), 0, int(process.curindex), corners_num); mesh->vert_positions_for_write().copy_from(process.co); - - mesh->totpoly = int(process.curindex); - BKE_mesh_poly_offsets_ensure_alloc(mesh); blender::MutableSpan poly_offsets = mesh->poly_offsets_for_write(); - int *corner_verts = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, mesh->totpoly * 4, ".corner_vert")); + blender::MutableSpan corner_verts = mesh->corner_verts_for_write(); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { @@ -1490,9 +1489,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) sizeof(float[3]) * size_t(mesh->totvert)); BKE_mesh_vert_normals_clear_dirty(mesh); - mesh->totloop = loop_offset; - poly_offsets.last() = loop_offset; - BKE_mesh_calc_edges(mesh, false, false); return mesh; -- 2.30.2 From a32fb963110030f3990e071337af04668baa7d42 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 17:31:06 -0400 Subject: [PATCH 34/61] Cleanup: Use more specific arguments to calc edges function --- .../blenkernel/intern/mesh_calc_edges.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index ddb587ea993..203f41863bd 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -151,14 +151,13 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan edg }); } -static void update_edge_indices_in_poly_loops(Mesh *mesh, - Span edge_maps, - uint32_t parallel_mask) +static void update_edge_indices_in_poly_loops(const OffsetIndices polys, + const Span corner_verts, + const Span edge_maps, + const uint32_t parallel_mask, + MutableSpan corner_edges) { - const OffsetIndices polys = mesh->polys(); - const Span corner_verts = mesh->corner_verts(); - MutableSpan corner_edges = mesh->corner_edges_for_write(); - threading::parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) { + threading::parallel_for(polys.index_range(), 100, [&](IndexRange range) { for (const int poly_index : range) { const IndexRange poly = polys[poly_index]; int prev_corner = poly.last(); @@ -239,7 +238,11 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select MutableSpan new_edges{ static_cast(MEM_calloc_arrayN(new_totedge, sizeof(int2), __func__)), new_totedge}; calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges); - calc_edges::update_edge_indices_in_poly_loops(mesh, edge_maps, parallel_mask); + calc_edges::update_edge_indices_in_poly_loops(mesh->polys(), + mesh->corner_verts(), + edge_maps, + parallel_mask, + mesh->corner_edges_for_write()); /* Free old CustomData and assign new one. */ CustomData_free(&mesh->edata, mesh->totedge); -- 2.30.2 From 5ca7e1301f798fc2d1dbc5eea2cb25338ae471c2 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 22:10:53 -0400 Subject: [PATCH 35/61] Cleanup: Remove redundant custom data initialization The comment didn't really make sense, since the removed code did the same thing as the CustomData function anyway, and that's already done in `mesh_init_data`. --- source/blender/blenkernel/intern/mesh.cc | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index e14fa192c8a..f7c032e2867 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1037,17 +1037,10 @@ Mesh *BKE_mesh_new_nomain(const int verts_num, const int polys_num, const int loops_num) { - Mesh *mesh = (Mesh *)BKE_libblock_alloc( - nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); + Mesh *mesh = static_cast(BKE_libblock_alloc( + nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE)); BKE_libblock_init_empty(&mesh->id); - /* Don't use #CustomData_reset because we don't want to touch custom-data. */ - copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); - copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); - mesh->totvert = verts_num; mesh->totedge = edges_num; mesh->totpoly = polys_num; -- 2.30.2 From 716b9cff23f070c559fcbdd0d3258c038874d4d5 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 19 Apr 2023 23:19:45 -0400 Subject: [PATCH 36/61] Fix: Search in node editors missing items Mistake in d6abd2ce727cb5c97322. --- source/blender/editors/space_node/add_node_search.cc | 4 ++-- source/blender/editors/space_node/link_drag_search.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc index 8cf72e19652..56cfb2480e9 100644 --- a/source/blender/editors/space_node/add_node_search.cc +++ b/source/blender/editors/space_node/add_node_search.cc @@ -158,10 +158,10 @@ static void gather_add_node_operations(const bContext &C, { NODE_TYPES_BEGIN (node_type) { const char *disabled_hint; - if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { + if (node_type->poll && !node_type->poll(node_type, &node_tree, &disabled_hint)) { continue; } - if (!(node_type->add_ui_poll && node_type->add_ui_poll(&C))) { + if (node_type->add_ui_poll && !node_type->add_ui_poll(&C)) { continue; } if (!node_type->gather_add_node_search_ops) { diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index 124fca9ee56..e656a709cfb 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -285,10 +285,10 @@ static void gather_socket_link_operations(const bContext &C, { NODE_TYPES_BEGIN (node_type) { const char *disabled_hint; - if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { + if (node_type->poll && !node_type->poll(node_type, &node_tree, &disabled_hint)) { continue; } - if (!(node_type->add_ui_poll && node_type->add_ui_poll(&C))) { + if (node_type->add_ui_poll && !node_type->add_ui_poll(&C)) { continue; } if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) { -- 2.30.2 From 3f0d2cf9e1c14226df50eeaa17b8057ab4f1210c Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Thu, 20 Apr 2023 05:30:34 +0200 Subject: [PATCH 37/61] Add scripts dir to the make format paths for Python `make format` uses autopep8 to format Python, using a list of paths specified in `tools/utils_maintenance/autopep8_format_paths.py`. The scripts folder used to be a submodule inside release, but it is now at the root of the blender repo. This commit adds `scripts` to the list of paths to format. Ref !107143 --- tools/utils_maintenance/autopep8_format_paths.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/utils_maintenance/autopep8_format_paths.py b/tools/utils_maintenance/autopep8_format_paths.py index 2412aad2bfd..7b8c9c036c7 100755 --- a/tools/utils_maintenance/autopep8_format_paths.py +++ b/tools/utils_maintenance/autopep8_format_paths.py @@ -48,6 +48,7 @@ def compute_paths(paths: List[str], use_default_paths: bool) -> List[str]: "build_files", "intern", "release", + "scripts", "doc", "source", "tests", -- 2.30.2 From 92f79e002e51e450d8e29820f2abcf556866c93c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 13:35:35 +1000 Subject: [PATCH 38/61] Cleanup: format --- scripts/startup/bl_ui/properties_data_curve.py | 16 ++++++++++++---- scripts/startup/bl_ui/space_node.py | 5 ++++- .../blender/geometry/intern/realize_instances.cc | 4 ++-- source/blender/io/collada/MeshImporter.h | 5 +---- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/scripts/startup/bl_ui/properties_data_curve.py b/scripts/startup/bl_ui/properties_data_curve.py index a46e849b775..3f93210ea8f 100644 --- a/scripts/startup/bl_ui/properties_data_curve.py +++ b/scripts/startup/bl_ui/properties_data_curve.py @@ -371,10 +371,18 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): row.prop(char, "use_small_caps", toggle=True) else: row = layout.row(align=True) - row.operator("font.style_toggle", text="Bold", icon='BOLD' , depress = text.is_select_bold).style = 'BOLD' - row.operator("font.style_toggle", text="Italic", icon='ITALIC' , depress = text.is_select_italic).style = 'ITALIC' - row.operator("font.style_toggle", text="Underline", icon='UNDERLINE' , depress = text.is_select_underline).style = 'UNDERLINE' - row.operator("font.style_toggle", text="Small Caps", icon='SMALL_CAPS' , depress = text.is_select_smallcaps).style = 'SMALL_CAPS' + row.operator( + "font.style_toggle", text="Bold", icon='BOLD', depress=text.is_select_bold, + ).style = 'BOLD' + row.operator( + "font.style_toggle", text="Italic", icon='ITALIC', depress=text.is_select_italic, + ).style = 'ITALIC' + row.operator( + "font.style_toggle", text="Underline", icon='UNDERLINE', depress=text.is_select_underline, + ).style = 'UNDERLINE' + row.operator( + "font.style_toggle", text="Small Caps", icon='SMALL_CAPS', depress=text.is_select_smallcaps, + ).style = 'SMALL_CAPS' class DATA_PT_font_transform(CurveButtonsPanelText, Panel): diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 564c53ca815..4b40d203c6d 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -903,7 +903,10 @@ class NodeTreeInterfacePanel(Panel): props = property_row.operator_menu_enum( "node.tree_socket_change_subtype", "socket_subtype", - text=active_socket.bl_subtype_label if active_socket.bl_subtype_label else active_socket.bl_idname + text=( + active_socket.bl_subtype_label if active_socket.bl_subtype_label else + active_socket.bl_idname + ), ) layout.use_property_split = True diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index ecf7951e149..9bf0823aa35 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -939,8 +939,8 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed(); } } - mesh_info.material_indices =* - attributes.lookup_or_default("material_index", ATTR_DOMAIN_FACE, 0); + mesh_info.material_indices = *attributes.lookup_or_default( + "material_index", ATTR_DOMAIN_FACE, 0); } info.no_loose_edges_hint = std::all_of( diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h index 7b4188785fd..c10997637e0 100644 --- a/source/blender/io/collada/MeshImporter.h +++ b/source/blender/io/collada/MeshImporter.h @@ -92,10 +92,7 @@ class MeshImporter : public MeshImporterBase { * A pair/of geom UID and mat UID, one geometry can have several materials. */ std::multimap materials_mapped_to_geom; - bool set_poly_indices(int *poly_verts, - int loop_index, - const uint *indices, - int loop_count); + bool set_poly_indices(int *poly_verts, int loop_index, const uint *indices, int loop_count); void set_face_uv(blender::float2 *mloopuv, UVDataWrapper &uvs, -- 2.30.2 From 62cc09f267af03775f8ff5673e5e5fb2c7719ee0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 13:52:58 +1000 Subject: [PATCH 39/61] Cleanup: match argument names between functions & declarations --- intern/ghost/GHOST_Path-api.hh | 2 +- intern/ghost/intern/GHOST_IXrGraphicsBinding.hh | 2 +- intern/ghost/intern/GHOST_SystemWayland.hh | 14 +++++++------- intern/ghost/intern/GHOST_SystemX11.cc | 6 +++--- intern/ghost/intern/GHOST_SystemX11.hh | 2 +- intern/ghost/intern/GHOST_Window.hh | 2 +- intern/ghost/intern/GHOST_XrAction.hh | 6 ++++-- source/blender/imbuf/intern/IMB_filetype.h | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/intern/ghost/GHOST_Path-api.hh b/intern/ghost/GHOST_Path-api.hh index 3bc9ca14165..82dbff04ad2 100644 --- a/intern/ghost/GHOST_Path-api.hh +++ b/intern/ghost/GHOST_Path-api.hh @@ -61,7 +61,7 @@ extern const char *GHOST_getBinaryDir(void); /** * Add the file to the operating system most recently used files */ -extern void GHOST_addToSystemRecentFiles(const char *filename); +extern void GHOST_addToSystemRecentFiles(const char *filepath); #ifdef __cplusplus } diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh b/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh index ee92f90ca5d..d7cd28270e0 100644 --- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh +++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.hh @@ -57,4 +57,4 @@ class GHOST_IXrGraphicsBinding { }; std::unique_ptr GHOST_XrGraphicsBindingCreateFromType( - GHOST_TXrGraphicsBinding type, GHOST_Context &ghost_ctx); + GHOST_TXrGraphicsBinding type, GHOST_Context &context); diff --git a/intern/ghost/intern/GHOST_SystemWayland.hh b/intern/ghost/intern/GHOST_SystemWayland.hh index faaaa03f46f..0b5984b026d 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.hh +++ b/intern/ghost/intern/GHOST_SystemWayland.hh @@ -37,15 +37,15 @@ bool ghost_wl_output_own(const struct wl_output *wl_output); void ghost_wl_output_tag(struct wl_output *wl_output); struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output); -bool ghost_wl_surface_own(const struct wl_surface *surface); -void ghost_wl_surface_tag(struct wl_surface *surface); -GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface); +bool ghost_wl_surface_own(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag(struct wl_surface *wl_surface); +GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface); -bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface); -void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface); +bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *wl_surface); -bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface); -void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface); +bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *wl_surface); +void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *wl_surface); /* Scaling to: translates from WAYLAND into GHOST (viewport local) coordinates. * Scaling from: performs the reverse translation. diff --git a/intern/ghost/intern/GHOST_SystemX11.cc b/intern/ghost/intern/GHOST_SystemX11.cc index d5a33b028be..c204cf78c6c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cc +++ b/intern/ghost/intern/GHOST_SystemX11.cc @@ -85,7 +85,7 @@ static uchar bit_is_on(const uchar *ptr, int bit) static GHOST_TKey ghost_key_from_keysym(const KeySym key); static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode); -static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key, +static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym, const XkbDescPtr xkb_descr, const KeyCode keycode); @@ -1776,11 +1776,11 @@ bool GHOST_SystemX11::generateWindowExposeEvents() return anyProcessed; } -static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym keysym, +static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym, XkbDescPtr xkb_descr, const KeyCode keycode) { - GHOST_TKey type = ghost_key_from_keysym(keysym); + GHOST_TKey type = ghost_key_from_keysym(key_sym); if (type == GHOST_kKeyUnknown) { if (xkb_descr) { type = ghost_key_from_keycode(xkb_descr, keycode); diff --git a/intern/ghost/intern/GHOST_SystemX11.hh b/intern/ghost/intern/GHOST_SystemX11.hh index 4314063f2ba..4e8dc4d610a 100644 --- a/intern/ghost/intern/GHOST_SystemX11.hh +++ b/intern/ghost/intern/GHOST_SystemX11.hh @@ -31,7 +31,7 @@ #endif /* generic error handlers */ -int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); +int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *event); int GHOST_X11_ApplicationIOErrorHandler(Display *display); #define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \ diff --git a/intern/ghost/intern/GHOST_Window.hh b/intern/ghost/intern/GHOST_Window.hh index d9d65832dfe..c079e71cc21 100644 --- a/intern/ghost/intern/GHOST_Window.hh +++ b/intern/ghost/intern/GHOST_Window.hh @@ -155,7 +155,7 @@ class GHOST_Window : public GHOST_IWindow { GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override; void getCursorGrabState(GHOST_TGrabCursorMode &mode, - GHOST_TAxisFlag &axis_flag, + GHOST_TAxisFlag &wrap_axis, GHOST_Rect &bounds, bool &use_software_cursor) override; /** diff --git a/intern/ghost/intern/GHOST_XrAction.hh b/intern/ghost/intern/GHOST_XrAction.hh index 0b1e9760026..41afce9fada 100644 --- a/intern/ghost/intern/GHOST_XrAction.hh +++ b/intern/ghost/intern/GHOST_XrAction.hh @@ -89,11 +89,13 @@ class GHOST_XrAction { const XrTime &predicted_display_time); void applyHapticFeedback(XrSession session, const char *action_name, - const char *subaction_path, + const char *subaction_path_str, const int64_t &duration, const float &frequency, const float &litude); - void stopHapticFeedback(XrSession session, const char *action_name, const char *subaction_path); + void stopHapticFeedback(XrSession session, + const char *action_name, + const char *subaction_path_str); void *getCustomdata(); void getBindings(std::map> &r_bindings) const; diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 005b56ba7b4..d713b978eda 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -184,7 +184,7 @@ struct ImBuf *imb_load_cineon(const unsigned char *mem, * \{ */ bool imb_is_a_dpx(const unsigned char *buf, size_t size); -bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags); +bool imb_save_dpx(struct ImBuf *ibuf, const char *filepath, int flags); struct ImBuf *imb_load_dpx(const unsigned char *mem, size_t size, int flags, -- 2.30.2 From 335d32153eb6396d862623d1df516a80b3036920 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 13:57:31 +1000 Subject: [PATCH 40/61] Cleanup: remove dead code, reduce variable scope --- intern/ghost/intern/GHOST_SystemWayland.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index 4806dc2e5c8..a90bc4e0d68 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -5586,8 +5586,6 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background) # endif display_destroy_and_free_all(); throw std::runtime_error("Wayland: unable to find libdecor!"); - - use_libdecor = true; } } else { @@ -5610,7 +5608,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background) (void)background; #endif { - GWL_XDG_Decor_System &decor = *display_->xdg_decor; + const GWL_XDG_Decor_System &decor = *display_->xdg_decor; if (!decor.shell) { display_destroy_and_free_all(); throw std::runtime_error("Wayland: unable to access xdg_shell!"); @@ -6071,10 +6069,8 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl( /* As the cursor is restored at the warped location, * apply warping when requesting the cursor location. */ GHOST_Rect wrap_bounds{}; - if (win->getCursorGrabModeIsWarp()) { - if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) { - win->getClientBounds(wrap_bounds); - } + if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) { + win->getClientBounds(wrap_bounds); } int xy_wrap[2] = { seat_state_pointer->xy[0], @@ -6680,10 +6676,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_custom_set(uint8_t *bitmap, static constexpr uint32_t transparent = 0x00000000; uint8_t datab = 0, maskb = 0; - uint32_t *pixel; for (int y = 0; y < sizey; ++y) { - pixel = &static_cast(cursor->custom_data)[y * sizex]; + uint32_t *pixel = &static_cast(cursor->custom_data)[y * sizex]; for (int x = 0; x < sizex; ++x) { if ((x % 8) == 0) { datab = *bitmap++; -- 2.30.2 From 3d6117994c3aa62b0b21c142b32b185859ddd35b Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Thu, 20 Apr 2023 07:20:58 +0200 Subject: [PATCH 41/61] Realtime Compositor: Implement ID Mask node This patch implements the ID Mask node for the realtime compositor. The node can be implemented as a GPU shader operation when the anti-aliasing option is disabled, which is something we should do when the evaluator allows nodes be executed as both standard and GPU shader operations. Pull Request: https://projects.blender.org/blender/blender/pulls/106593 --- .../realtime_compositor/CMakeLists.txt | 2 + .../shaders/compositor_id_mask.glsl | 11 ++++ .../shaders/infos/compositor_id_mask_info.hh | 11 ++++ .../composite/nodes/node_composite_id_mask.cc | 65 +++++++++++++++++-- 4 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl create mode 100644 source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index df9440ef414..ab584423dd1 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -118,6 +118,7 @@ set(GLSL_SRC shaders/compositor_glare_simple_star_vertical_pass.glsl shaders/compositor_glare_streaks_accumulate.glsl shaders/compositor_glare_streaks_filter.glsl + shaders/compositor_id_mask.glsl shaders/compositor_image_crop.glsl shaders/compositor_map_uv.glsl shaders/compositor_morphological_distance.glsl @@ -215,6 +216,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/compositor_filter_info.hh shaders/infos/compositor_flip_info.hh shaders/infos/compositor_glare_info.hh + shaders/infos/compositor_id_mask_info.hh shaders/infos/compositor_image_crop_info.hh shaders/infos/compositor_map_uv_info.hh shaders/infos/compositor_morphological_distance_feather_info.hh diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl new file mode 100644 index 00000000000..d7411586b5e --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_id_mask.glsl @@ -0,0 +1,11 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + float input_mask_value = texture_load(input_mask_tx, texel).x; + float mask = int(round(input_mask_value)) == index ? 1.0 : 0.0; + + imageStore(output_mask_img, texel, vec4(mask)); +} diff --git a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh new file mode 100644 index 00000000000..ce4fb8f6325 --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_id_mask_info.hh @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_id_mask) + .local_group_size(16, 16) + .push_constant(Type::INT, "index") + .sampler(0, ImageType::FLOAT_2D, "input_mask_tx") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img") + .compute_source("compositor_id_mask.glsl") + .do_static_compilation(true); diff --git a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc index 1a0a200062d..3e536f056f4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc @@ -5,11 +5,16 @@ * \ingroup cmpnodes */ +#include + #include "BLT_translation.h" #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + +#include "COM_algorithm_smaa.hh" #include "COM_node_operation.hh" #include "node_composite_util.hh" @@ -20,7 +25,11 @@ namespace blender::nodes::node_composite_id_mask_cc { static void cmp_node_idmask_declare(NodeDeclarationBuilder &b) { - b.add_input(N_("ID value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input(N_("ID value")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .compositor_domain_priority(0); b.add_output(N_("Alpha")); } @@ -38,8 +47,56 @@ class IDMaskOperation : public NodeOperation { void execute() override { - get_input("ID value").pass_through(get_result("Alpha")); - context().set_info_message("Viewport compositor setup not fully supported"); + const Result &input_mask = get_input("ID value"); + if (input_mask.is_single_value()) { + execute_single_value(); + return; + } + + GPUShader *shader = shader_manager().get("compositor_id_mask"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1i(shader, "index", get_index()); + + input_mask.bind_as_texture(shader, "input_mask_tx"); + + /* If anti-aliasing is disabled, write to the output directly, otherwise, write to a temporary + * result to later perform anti-aliasing. */ + Result non_anti_aliased_mask = Result::Temporary(ResultType::Float, texture_pool()); + Result &output_mask = use_anti_aliasing() ? non_anti_aliased_mask : get_result("Alpha"); + + const Domain domain = compute_domain(); + output_mask.allocate_texture(domain); + output_mask.bind_as_image(shader, "output_mask_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + input_mask.unbind_as_texture(); + output_mask.unbind_as_image(); + GPU_shader_unbind(); + + if (use_anti_aliasing()) { + smaa(context(), non_anti_aliased_mask, get_result("Alpha")); + non_anti_aliased_mask.release(); + } + } + + void execute_single_value() + { + const float input_mask_value = get_input("ID value").get_float_value(); + const float mask = int(round(input_mask_value)) == get_index() ? 1.0f : 0.0f; + get_result("Alpha").allocate_single_value(); + get_result("Alpha").set_float_value(mask); + } + + int get_index() + { + return bnode().custom1; + } + + bool use_anti_aliasing() + { + return bnode().custom2 != 0; } }; @@ -60,8 +117,6 @@ void register_node_type_cmp_idmask() ntype.declare = file_ns::cmp_node_idmask_declare; ntype.draw_buttons = file_ns::node_composit_buts_id_mask; ntype.get_compositor_operation = file_ns::get_compositor_operation; - ntype.realtime_compositor_unsupported_message = N_( - "Node not supported in the Viewport compositor"); nodeRegisterType(&ntype); } -- 2.30.2 From 397a14deff2d72b0e5614069c6de29b1e9efb084 Mon Sep 17 00:00:00 2001 From: Sietse Brouwer Date: Thu, 20 Apr 2023 07:55:24 +0200 Subject: [PATCH 42/61] GPencil: Several Weight Paint additions This patch adds several tools and options to the weight paint mode of Grease Pencil. * Blur tool: smooths out vertex weights, by calculating a gaussian blur of adjacent vertices. * Average tool: painting the average weight from all weights under the brush. * Smear tool: smudges weights by grabbing the weights under the brush and 'dragging' them. * With the + and - icons in the toolbar, the user can easily switch between adding and subtracting weight while drawing weights. * With shortcut `D` you can toggle between these two. * The auto-normalize options ensures that all bone-deforming vertex groups add up to 1.0 while weight painting. * With `Ctrl-F` a radial control for weight is invoked (in addition to the radial controls for brush size and strength). * With `Ctrl-RMB` the user can sample the weight. This sets the brush Weight from the weight under the cursor. * When painting weights in vertex groups for bones, the user can quickly switch to another vertex group by clicking on a bone with `Ctrl-LMB`. For this to work, follow these steps: * Select the armature and switch to Pose Mode. * Select your Grease Pencil object and switch immediately to Weight Paint Mode. * Select a bone in the armature with `Ctrl-LMB`. The corresponding vertex group is automatically activated. Pull Request: https://projects.blender.org/blender/blender/pulls/106663 --- .../icons/ops.gpencil.sculpt_average.dat | Bin 0 -> 3284 bytes .../icons/ops.gpencil.sculpt_blur.dat | Bin 0 -> 1304 bytes .../icons/ops.gpencil.sculpt_smear.dat | Bin 0 -> 1700 bytes .../bl_keymap_utils/keymap_hierarchy.py | 3 + .../keyconfig/keymap_data/blender_default.py | 63 + .../keymap_data/industry_compatible_data.py | 53 + .../startup/bl_ui/properties_paint_common.py | 8 +- .../startup/bl_ui/space_toolsystem_toolbar.py | 1 + scripts/startup/bl_ui/space_view3d.py | 19 +- scripts/startup/bl_ui/space_view3d_toolbar.py | 28 +- source/blender/blenkernel/intern/brush.cc | 72 +- .../blenloader/intern/versioning_300.cc | 3 + .../blender/editors/datafiles/CMakeLists.txt | 3 + .../editors/gpencil_legacy/gpencil_data.c | 73 +- .../editors/gpencil_legacy/gpencil_intern.h | 2 + .../editors/gpencil_legacy/gpencil_ops.c | 41 + .../gpencil_legacy/gpencil_weight_paint.c | 1083 +++++++++++++++-- .../editors/interface/interface_icons.cc | 9 + source/blender/editors/screen/area.cc | 12 + .../blender/editors/sculpt_paint/paint_ops.cc | 14 +- .../editors/space_view3d/view3d_select.cc | 3 +- source/blender/makesdna/DNA_brush_enums.h | 11 +- source/blender/makesrna/intern/rna_brush.c | 16 +- 23 files changed, 1324 insertions(+), 193 deletions(-) create mode 100644 release/datafiles/icons/ops.gpencil.sculpt_average.dat create mode 100644 release/datafiles/icons/ops.gpencil.sculpt_blur.dat create mode 100644 release/datafiles/icons/ops.gpencil.sculpt_smear.dat diff --git a/release/datafiles/icons/ops.gpencil.sculpt_average.dat b/release/datafiles/icons/ops.gpencil.sculpt_average.dat new file mode 100644 index 0000000000000000000000000000000000000000..f082d7ed1148e0474ec59e1f1761cff5a003f364 GIT binary patch literal 3284 zcmeH_L5uP_6o%(d*`dX*ZUb2aZXo4b3U0>I4$WAp-%^)OiIQR@t_Iv%$)M8F_FLJZ z9sMEmJLabMU)+m@bNZeq?#+bSul$g5-Eb-CZL68GQRGibo zQ%RmEsdlPV$ASp728{S5LgPXl))_0J!#MLR-mn|5!p6Ua2Dg~ajnMM#Ftz7q+M#w} z(oTAv*Xe~`gPLBD3kkpgI|x7kAt1VtLm+an)&#nUV1hA0E^+}TPWn}PWB41zIL0GFU40YWo>HgfvDVyWB*6)up#&z70q$@|fCLI4^(^5UNi4A- z+|~ETEs?q(-FLFXJDi~%+`)HnbdJsm?BEHMdM@D~RN@k!$kEmBg2n83y>2{klLT*Qt$Bn zyvuiaw%_TUzGuhnaeK;k>XeoL?)cBX%**_AF4gILEZUuGw?bis&Ogj0?Ze&PIGLD_-%>MZ+3)UEKJMUzd$&M5R?T z{CugxD*Ox@zwxiZExd)-muA=uE3GW?xHP!I9~Tz0Sa)G_n|GI%u!NzNHGF(ALL+<( zEZ_3GfgRdm_r)4oLqn^Tx$LHPYA?ETb8aq-w3Bw0#>!lonsy>{*rhhLpSyt>n9m07 z(9Y0^%*fQVv#OV0={3DBzUKA3UR3ENy)3I$y{a|6MD_5CUg`DuE2x9|xuO?(8CFpp z)tX)=z0GvGnQlgJp7dm&O*ehkn@l&oNq^+&Z`7akCOy{QOj%!go2m5PM%q4o)6O?0 u<#Zz@du#okH|e$iNsn{>bFcdw+%s^`z&!)^4BRvD|H{Dk_xI0#q5c66UIf+v literal 0 HcmV?d00001 diff --git a/release/datafiles/icons/ops.gpencil.sculpt_blur.dat b/release/datafiles/icons/ops.gpencil.sculpt_blur.dat new file mode 100644 index 0000000000000000000000000000000000000000..2128de71dff2059784de3939f8d93e225f428d3f GIT binary patch literal 1304 zcmeH_(Q2zO0EYW$b28$bTg6eGlF}sDE{1N@&<>?NJ@(2gU12Dt6bcie7u(K-7iDj7 zUZl_Al6Tl;FaCVVmp>3fY_;2I+fD})TW9b%`hGry-_OUFLwI~?<{wcr|M%x}At^^` zEBJ-pAHUFXbOCTR$IT!GnXz&*%JF&ClK^F2*6O7sTTIQ7J{c9zgg&!73+~U zwc_sI+oid@UEVCrr4^fkJ#NL?6a=0)OU3;dENGp0d7W1!EUR+AL%aR%wV5=pP4a&t zDA#Bw_h2b{iI>0_am0sXMi~u##6v$Kh({#BDM?B07qp<;@t*H_6&JLM>!hHttdlzT jaxan1RP<9)P{h3)@q(_`>-L=U8~pYkIGs-IIj8mq$kRnf literal 0 HcmV?d00001 diff --git a/release/datafiles/icons/ops.gpencil.sculpt_smear.dat b/release/datafiles/icons/ops.gpencil.sculpt_smear.dat new file mode 100644 index 0000000000000000000000000000000000000000..36958641266c4f9c6b762373437a2fa2e271b826 GIT binary patch literal 1700 zcmeH_%Z{Qz6o!2*>=9eJ3ZileVv9Iluq81L3)86SWDL3)B+(e8BVp2w2@%sS`WaaC z!o|FW&*2m^4>5~zalZWL)T#QbPD(_|sp~bBs^Jo*KqOA!I0ga`$1s${F%&}p^LUO% z@f>~+cu&AIO28x_ir8Ig(7xJOQ96-Z_4#3R=OTKkjNi5jjz3_`+G zh6O&Qv;bTZ#Q;wU5>WvGjwRs9_;8R7b0HNJB}f6D8mB;R2FugnU7#B!Ve9;HTK&>v zZRwcS`E>X=HFkAZwd!td^RQ~{RI6`4tYo|H%68LIt)|ufp<1$?bZE==d^l;(Ti;vH zfX|(2d)}E2#)ENZssgIxzR}qAZ9VSW+ER~2ueOst*=y|dIN3KC^S%gjZ8@AQM(iu^ zb0P1`9v8BE_LU2Thzn)U_|#*^)MFu%z0<)uC-*cy9rHMQw;c1`IvpHy-#t8Sjl-&&sX*4lSBy%(SpCb{$VrMc;CjZJUgtx}88&{&KdQ(FpTl`8Oy(YMLas1O3l zkOEoYY05FT#&Jf2wE{y^f2(ArzzhvqtWvaC;H%Vny}sV!|Cqt$a=G5(HiLih2Yv$z CmwitF literal 0 HcmV?d00001 diff --git a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py index 6215bb9fa9e..21d80a1ed71 100644 --- a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py +++ b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py @@ -204,6 +204,9 @@ _km_hierarchy = [ ('Grease Pencil Stroke Sculpt (Clone)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Weight (Draw)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Blur)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Average)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight (Smear)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex Mode', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex (Draw)', 'EMPTY', 'WINDOW', []), ('Grease Pencil Stroke Vertex (Blur)', 'EMPTY', 'WINDOW', []), diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index eda3789e92d..fb2c549ecaf 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4178,6 +4178,9 @@ def km_grease_pencil_stroke_weight_mode(params): # Brush size ("wm.radial_control", {"type": 'F', "value": 'PRESS'}, {"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}), + # Brush weight + ("wm.radial_control", {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.weight')]}), # Increase/Decrease brush size ("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True}, {"properties": [("scalar", 0.9)]}), @@ -4197,6 +4200,10 @@ def km_grease_pencil_stroke_weight_mode(params): op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}), # Context menu *_template_items_context_panel("VIEW3D_PT_gpencil_weight_context_menu", params.context_menu_event), + # Toggle Add/Subtract for weight draw tool + ("gpencil.weight_toggle_direction", {"type": 'D', "value": 'PRESS'}, None), + # Weight sample + ("gpencil.weight_sample", {"type": params.action_mouse, "value": 'PRESS', "ctrl": True}, None), ]) if params.select_mouse == 'LEFTMOUSE': @@ -4220,6 +4227,59 @@ def km_grease_pencil_stroke_weight_draw(_params): # Draw ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("wait_for_input", False)]}), + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_blur(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Blur)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Blur + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_average(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Average)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Average + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_smear(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Smear)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + # Smear + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), ]) return keymap @@ -8115,6 +8175,9 @@ def generate_keymaps(params=None): km_grease_pencil_stroke_sculpt_clone(params), km_grease_pencil_stroke_weight_mode(params), km_grease_pencil_stroke_weight_draw(params), + km_grease_pencil_stroke_weight_blur(params), + km_grease_pencil_stroke_weight_average(params), + km_grease_pencil_stroke_weight_smear(params), km_grease_pencil_stroke_vertex_mode(params), km_grease_pencil_stroke_vertex_draw(params), km_grease_pencil_stroke_vertex_blur(params), diff --git a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index e6fabb886a9..1c6ac26c7e9 100644 --- a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -2777,6 +2777,56 @@ def km_grease_pencil_stroke_weight_draw(_params): {"items": items}, ) + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_blur(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Blur)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_average(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Average)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + + items.extend([ + ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": [("wait_for_input", False)]}), + ]) + + return keymap + + +def km_grease_pencil_stroke_weight_smear(_params): + items = [] + keymap = ( + "Grease Pencil Stroke Weight (Smear)", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": items}, + ) + items.extend([ ("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("wait_for_input", False)]}), @@ -4195,6 +4245,9 @@ def generate_keymaps_impl(params=None): km_grease_pencil_stroke_sculpt_clone(params), km_grease_pencil_stroke_weight_mode(params), km_grease_pencil_stroke_weight_draw(params), + km_grease_pencil_stroke_weight_blur(params), + km_grease_pencil_stroke_weight_average(params), + km_grease_pencil_stroke_weight_smear(params), km_grease_pencil_stroke_vertex_mode(params), km_grease_pencil_stroke_vertex_draw(params), km_grease_pencil_stroke_vertex_blur(params), diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index e99b5466f2b..5984b325ba6 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -1414,8 +1414,12 @@ def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=Fals row = layout.row(align=True) row.prop(brush, "strength", slider=True) row.prop(brush, "use_pressure_strength", text="") - - layout.prop(brush, "weight", slider=True) + + if brush.gpencil_weight_tool in {'WEIGHT'}: + layout.prop(brush, "weight", slider=True) + + gp_settings = brush.gpencil_settings + layout.prop(gp_settings, "direction", expand=True, text="" if compact else "Direction") def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=False): diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index e341f39261a..dcc0d4e7efe 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -68,6 +68,7 @@ def generate_from_enum_ex( dict( idname=idname_prefix + name, label=name, + description=enum.description, icon=icon, cursor=cursor, data_block=idname, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 74c7bd84112..36827670145 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -8,6 +8,7 @@ from bpy.types import ( from bl_ui.properties_paint_common import ( UnifiedPaintPanel, brush_basic_texpaint_settings, + brush_basic_gpencil_weight_settings, ) from bl_ui.properties_grease_pencil_common import ( AnnotationDataPanel, @@ -413,11 +414,13 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.gpencil_weight_paint brush = paint.brush - - from bl_ui.properties_paint_common import ( - brush_basic_gpencil_weight_settings, - ) + + layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) + brush_basic_gpencil_weight_settings(layout, context, brush, compact=True) + + layout.popover("VIEW3D_PT_tools_grease_pencil_weight_options", text="Options") + layout.popover("VIEW3D_PT_tools_grease_pencil_brush_weight_falloff", text="Falloff") return True @@ -7662,12 +7665,10 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel): tool_settings = context.tool_settings settings = tool_settings.gpencil_weight_paint brush = settings.brush - layout = self.layout - - layout.prop(brush, "size", slider=True) - layout.prop(brush, "strength") - layout.prop(brush, "weight") + + # Weight settings + brush_basic_gpencil_weight_settings(layout, context, brush) # Layers draw_gpencil_layer_active(context, layout) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index fa8d7b928ba..442a6ee952d 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -2021,6 +2021,9 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr bl_label = "Brush Settings" def draw(self, context): + if self.is_popover: + return + layout = self.layout layout.use_property_split = True layout.use_property_decorate = False @@ -2029,15 +2032,15 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr settings = tool_settings.gpencil_weight_paint brush = settings.brush - if not self.is_popover: - from bl_ui.properties_paint_common import ( - brush_basic_gpencil_weight_settings, - ) - brush_basic_gpencil_weight_settings(layout, context, brush) + from bl_ui.properties_paint_common import ( + brush_basic_gpencil_weight_settings, + ) + brush_basic_gpencil_weight_settings(layout, context, brush) class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel): bl_context = ".greasepencil_weight" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_weight_paint_settings' bl_label = "Falloff" bl_options = {'DEFAULT_CLOSED'} @@ -2049,6 +2052,20 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof return (brush and brush.curve) +class VIEW3D_PT_tools_grease_pencil_weight_options(Panel, View3DPanel, GreasePencilWeightPanel): + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + tool_settings = context.scene.tool_settings + + col = layout.column() + col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize") + + # Grease Pencil vertex painting tools class GreasePencilVertexPanel: bl_context = ".greasepencil_vertex" @@ -2425,6 +2442,7 @@ classes = ( VIEW3D_PT_tools_grease_pencil_sculpt_appearance, VIEW3D_PT_tools_grease_pencil_weight_paint_select, VIEW3D_PT_tools_grease_pencil_weight_paint_settings, + VIEW3D_PT_tools_grease_pencil_weight_options, VIEW3D_PT_tools_grease_pencil_weight_appearance, VIEW3D_PT_tools_grease_pencil_vertex_paint_select, VIEW3D_PT_tools_grease_pencil_vertex_paint_settings, diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 01652c7e2c3..7159c7a6633 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -1276,14 +1276,57 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) break; } - case GP_BRUSH_PRESET_DRAW_WEIGHT: { + case GP_BRUSH_PRESET_WEIGHT_DRAW: { brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_WEIGHT; brush->gpencil_weight_tool = GPWEIGHT_TOOL_DRAW; brush->size = 25.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_strength = 0.8f; + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_BLUR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_BLUR; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_AVERAGE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_AVERAGE; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_WEIGHT_SMEAR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_SMEAR; + + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->alpha = 0.3f; + brush->gpencil_settings->draw_strength = 0.3f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE; brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; @@ -1569,13 +1612,32 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool Paint *weightpaint = &ts->gp_weightpaint->paint; Brush *brush_prev = weightpaint->brush; Brush *brush, *deft_weight; - /* Vertex Draw brush. */ - brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new); + + /* Weight Draw brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Draw", OB_MODE_WEIGHT_GPENCIL, &r_new); if ((reset) || (r_new)) { - BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_DRAW); } deft_weight = brush; /* save default brush. */ + /* Weight Blur brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Blur", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_BLUR); + } + + /* Weight Average brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Average", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_AVERAGE); + } + + /* Weight Smear brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Weight Smear", OB_MODE_WEIGHT_GPENCIL, &r_new); + if ((reset) || (r_new)) { + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_SMEAR); + } + /* Set default brush. */ if (reset || brush_prev == nullptr) { BKE_paint_brush_set(weightpaint, deft_weight); diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index 9429c21b56e..f2667f66c09 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -4305,6 +4305,9 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) ARRAY_SIZE(tool_replace_table)); } } + + /* Rename Grease Pencil weight draw brush. */ + do_versions_rename_id(bmain, ID_BR, "Draw Weight", "Weight Draw"); } /** diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 982f3585b33..fb775fde717 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -808,11 +808,14 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.gpencil.primitive_line ops.gpencil.primitive_polyline ops.gpencil.radius + ops.gpencil.sculpt_average + ops.gpencil.sculpt_blur ops.gpencil.sculpt_clone ops.gpencil.sculpt_grab ops.gpencil.sculpt_pinch ops.gpencil.sculpt_push ops.gpencil.sculpt_randomize + ops.gpencil.sculpt_smear ops.gpencil.sculpt_smooth ops.gpencil.sculpt_strength ops.gpencil.sculpt_thickness diff --git a/source/blender/editors/gpencil_legacy/gpencil_data.c b/source/blender/editors/gpencil_legacy/gpencil_data.c index 846e2f3893f..25d424b92cb 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_data.c +++ b/source/blender/editors/gpencil_legacy/gpencil_data.c @@ -2079,7 +2079,7 @@ static void gpencil_brush_delete_mode_brushes(Main *bmain, } if (mode == CTX_MODE_WEIGHT_GPENCIL) { - if (preset != GP_BRUSH_PRESET_DRAW_WEIGHT) { + if ((preset < GP_BRUSH_PRESET_WEIGHT_DRAW) || (preset > GP_BRUSH_PRESET_WEIGHT_SMEAR)) { continue; } if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) { @@ -2666,58 +2666,67 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op) continue; } - /* look for tot value */ - float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__); - + /* Loop all points in stroke. */ for (int i = 0; i < gps->totpoints; i++) { + int v; + float sum = 0.0f; + float sum_lock = 0.0f; + float sum_unlock = 0.0f; + + /* Get vertex groups and weights. */ dvert = &gps->dvert[i]; - for (int v = 0; v < defbase_tot; v++) { + + /* Sum weights. */ + for (v = 0; v < defbase_tot; v++) { + /* Get vertex group. */ defgroup = BLI_findlink(&gpd->vertex_group_names, v); - /* skip NULL or locked groups */ - if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { - continue; - } - - /* skip current */ - if ((lock_active) && (v == def_nr)) { + if (defgroup == NULL) { continue; } + /* Get weight in vertex group. */ dw = BKE_defvert_find_index(dvert, v); - if (dw != NULL) { - tot_values[i] += dw->weight; + if (dw == NULL) { + continue; + } + sum += dw->weight; + + /* Vertex group locked or unlocked? */ + if ((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr))) { + sum_lock += dw->weight; + } + else { + sum_unlock += dw->weight; } } - } - /* normalize weights */ - for (int i = 0; i < gps->totpoints; i++) { - if (tot_values[i] == 0.0f) { + if ((sum == 1.0f) || (sum_unlock == 0.0f)) { continue; } - dvert = &gps->dvert[i]; - for (int v = 0; v < defbase_tot; v++) { + /* Normalize weights. */ + float fac = MAX2(0, (1.0f - sum_lock) / sum_unlock); + + for (v = 0; v < defbase_tot; v++) { + /* Get vertex group. */ defgroup = BLI_findlink(&gpd->vertex_group_names, v); - /* skip NULL or locked groups */ - if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { - continue; - } - - /* skip current */ - if ((lock_active) && (v == def_nr)) { + if (defgroup == NULL) { continue; } + /* Get weight in vertex group. */ dw = BKE_defvert_find_index(dvert, v); - if (dw != NULL) { - dw->weight = dw->weight / tot_values[i]; + if (dw == NULL) { + continue; + } + + /* Normalize in unlocked vertex groups only. */ + if (!((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr)))) { + dw->weight *= fac; + CLAMP(dw->weight, 0.0f, 1.0f); } } } - - /* free temp array */ - MEM_SAFE_FREE(tot_values); } CTX_DATA_END; diff --git a/source/blender/editors/gpencil_legacy/gpencil_intern.h b/source/blender/editors/gpencil_legacy/gpencil_intern.h index fdfc7a51b4a..d03322c98bb 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_intern.h +++ b/source/blender/editors/gpencil_legacy/gpencil_intern.h @@ -518,6 +518,8 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot); */ void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot); void GPENCIL_OT_weight_paint(struct wmOperatorType *ot); +void GPENCIL_OT_weight_toggle_direction(struct wmOperatorType *ot); +void GPENCIL_OT_weight_sample(struct wmOperatorType *ot); /* buttons editing --- */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_ops.c b/source/blender/editors/gpencil_legacy/gpencil_ops.c index b534928999d..2db2cab7d0b 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_ops.c +++ b/source/blender/editors/gpencil_legacy/gpencil_ops.c @@ -292,6 +292,24 @@ static bool gpencil_stroke_weightmode_draw_poll(bContext *C) return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW); } +/* Poll callback for weight paint (Blur) */ +static bool gpencil_stroke_weightmode_blur_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_BLUR); +} + +/* Poll callback for weight paint (Average) */ +static bool gpencil_stroke_weightmode_average_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_AVERAGE); +} + +/* Poll callback for weight paint (Smear) */ +static bool gpencil_stroke_weightmode_smear_poll(bContext *C) +{ + return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_SMEAR); +} + /* Stroke Editing Keymap - Only when editmode is enabled */ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) { @@ -460,6 +478,24 @@ static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf) wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Draw)", 0, 0); keymap->poll = gpencil_stroke_weightmode_draw_poll; } +/* keys for weight with a blur brush */ +static void ed_keymap_gpencil_weightpainting_blur(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Blur)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_blur_poll; +} +/* keys for weight with a average brush */ +static void ed_keymap_gpencil_weightpainting_average(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Average)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_average_poll; +} +/* keys for weight with a smear brush */ +static void ed_keymap_gpencil_weightpainting_smear(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Smear)", 0, 0); + keymap->poll = gpencil_stroke_weightmode_smear_poll; +} /* ==================== */ @@ -485,6 +521,9 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf) ed_keymap_gpencil_sculptpainting_clone(keyconf); ed_keymap_gpencil_weightpainting(keyconf); ed_keymap_gpencil_weightpainting_draw(keyconf); + ed_keymap_gpencil_weightpainting_blur(keyconf); + ed_keymap_gpencil_weightpainting_average(keyconf); + ed_keymap_gpencil_weightpainting_smear(keyconf); ed_keymap_gpencil_vertexpainting(keyconf); ed_keymap_gpencil_vertexpainting_draw(keyconf); ed_keymap_gpencil_vertexpainting_blur(keyconf); @@ -564,6 +603,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_sculpt_paint); WM_operatortype_append(GPENCIL_OT_weight_paint); + WM_operatortype_append(GPENCIL_OT_weight_toggle_direction); + WM_operatortype_append(GPENCIL_OT_weight_sample); /* Edit stroke editcurve */ diff --git a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c index da3706ed34b..da6cdcdde14 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c @@ -9,6 +9,9 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_kdtree.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -16,6 +19,7 @@ #include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_gpencil_legacy_types.h" +#include "DNA_gpencil_modifier_types.h" #include "BKE_action.h" #include "BKE_brush.h" @@ -50,6 +54,9 @@ /* ************************************************ */ /* General Brush Editing Context */ #define GP_SELECT_BUFFER_CHUNK 256 +#define GP_FIND_NEAREST_BUFFER_CHUNK 1024 +#define GP_FIND_NEAREST_EPSILON 1e-6f +#define GP_STROKE_HASH_BITSHIFT 16 /* Grid of Colors for Smear. */ typedef struct tGP_Grid { @@ -70,10 +77,12 @@ typedef struct tGP_Selected { bGPDstroke *gps; /** Point index in points array. */ int pt_index; - /** Position */ + /** Position. */ int pc[2]; - /** Color */ + /** Color. */ float color[4]; + /** Weight. */ + float weight; } tGP_Selected; /* Context for brush operators */ @@ -102,23 +111,30 @@ typedef struct tGP_BrushWeightpaintData { bool is_multiframe; bool use_multiframe_falloff; - /* active vertex group */ + /* Draw tool: add or subtract? */ + bool subtract; + + /* Auto-normalize weights of bone-deformed vertices? */ + bool auto_normalize; + + /* Active vertex group */ int vrgroup; /* Brush Runtime Data: */ /* - position and pressure * - the *_prev variants are the previous values */ - float mval[2], mval_prev[2]; - float pressure, pressure_prev; + float mouse[2], mouse_prev[2]; + float pressure; - /* - Effect 2D vector */ - float dvec[2]; + /* - Brush direction. */ + float brush_dir[2]; + bool brush_dir_is_set; - /* - multi-frame falloff factor. */ + /* - Multi-frame falloff factor. */ float mf_falloff; - /* brush geometry (bounding box). */ + /* Brush geometry (bounding box). */ rcti brush_rect; /* Temp data to save selected points */ @@ -128,45 +144,364 @@ typedef struct tGP_BrushWeightpaintData { int pbuffer_used; /** Number of total elements available in cache. */ int pbuffer_size; + /** Average weight of elements in cache (used for average tool). */ + float pbuffer_avg_weight; + + /* Temp data for find-nearest-points, used by blur and smear tool. */ + bool use_find_nearest; + /** Buffer of stroke points during one mouse swipe. */ + tGP_Selected *fn_pbuffer; + /** Hash table of added points (to avoid duplicate entries). */ + GHash *fn_added; + /** KDtree for finding nearest points. */ + KDTree_2d *fn_kdtree; + /** Number of points used in find-nearest set. */ + uint fn_used; + /** Number of points available in find-nearest set. */ + uint fn_size; + /** Flag for balancing kdtree. */ + bool fn_do_balance; + + /* Temp data for auto-normalize weights used by deforming bones. */ + /** Boolean array of locked vertex groups. */ + bool *vgroup_locked; + /** Boolean array of vertex groups deformed by bones. */ + bool *vgroup_bone_deformed; + /** Number of vertex groups in object. */ + int vgroup_tot; + } tGP_BrushWeightpaintData; /* Ensure the buffer to hold temp selected point size is enough to save all points selected. */ -static tGP_Selected *gpencil_select_buffer_ensure(tGP_Selected *buffer_array, - int *buffer_size, - int *buffer_used, - const bool clear) +static void gpencil_select_buffer_ensure(tGP_BrushWeightpaintData *gso, const bool clear) { - tGP_Selected *p = NULL; - /* By default a buffer is created with one block with a predefined number of free slots, * if the size is not enough, the cache is reallocated adding a new block of free slots. * This is done in order to keep cache small and improve speed. */ - if (*buffer_used + 1 > *buffer_size) { - if ((*buffer_size == 0) || (buffer_array == NULL)) { - p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__); - *buffer_size = GP_SELECT_BUFFER_CHUNK; + if ((gso->pbuffer_used + 1) > gso->pbuffer_size) { + if ((gso->pbuffer_size == 0) || (gso->pbuffer == NULL)) { + gso->pbuffer = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__); + gso->pbuffer_size = GP_SELECT_BUFFER_CHUNK; } else { - *buffer_size += GP_SELECT_BUFFER_CHUNK; - p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size); + gso->pbuffer_size += GP_SELECT_BUFFER_CHUNK; + gso->pbuffer = MEM_recallocN(gso->pbuffer, sizeof(struct tGP_Selected) * gso->pbuffer_size); } - - if (p == NULL) { - *buffer_size = *buffer_used = 0; - } - - buffer_array = p; } - /* clear old data */ + /* Clear old data. */ if (clear) { - *buffer_used = 0; - if (buffer_array != NULL) { - memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size); + gso->pbuffer_used = 0; + if (gso->pbuffer != NULL) { + memset(gso->pbuffer, 0, sizeof(tGP_Selected) * gso->pbuffer_size); } } - return buffer_array; + /* Create or enlarge buffer for find-nearest-points. */ + if (gso->use_find_nearest && ((gso->fn_used + 1) > gso->fn_size)) { + gso->fn_size += GP_FIND_NEAREST_BUFFER_CHUNK; + + /* Stroke point buffer. */ + if (gso->fn_pbuffer == NULL) { + gso->fn_pbuffer = MEM_callocN(sizeof(struct tGP_Selected) * gso->fn_size, __func__); + } + else { + gso->fn_pbuffer = MEM_recallocN(gso->fn_pbuffer, sizeof(struct tGP_Selected) * gso->fn_size); + } + + /* Stroke point hash table (for duplicate checking.) */ + if (gso->fn_added == NULL) { + gso->fn_added = BLI_ghash_int_new("GP weight paint find nearest"); + } + + /* KDtree of stroke points. */ + bool do_tree_rebuild = false; + if (gso->fn_kdtree != NULL) { + BLI_kdtree_2d_free(gso->fn_kdtree); + do_tree_rebuild = true; + } + gso->fn_kdtree = BLI_kdtree_2d_new(gso->fn_size); + + if (do_tree_rebuild) { + for (int i = 0; i < gso->fn_used; i++) { + float pc_f[2]; + copy_v2fl_v2i(pc_f, gso->fn_pbuffer[i].pc); + BLI_kdtree_2d_insert(gso->fn_kdtree, i, pc_f); + } + } + } +} + +/* Ensure a vertex group for the weight paint brush. */ +static void gpencil_vertex_group_ensure(tGP_BrushWeightpaintData *gso) +{ + if (gso->vrgroup >= 0) { + return; + } + if (gso->object == NULL) { + return; + } + + DEG_relations_tag_update(gso->bmain); + gso->vrgroup = 0; + + Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object); + if (ob_armature == NULL) { + BKE_object_defgroup_add(gso->object); + return; + } + Bone *actbone = ((bArmature *)ob_armature->data)->act_bone; + if (actbone == NULL) { + return; + } + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name); + if (pchan == NULL) { + return; + } + bDeformGroup *dg = BKE_object_defgroup_find_name(gso->object, pchan->name); + if (dg == NULL) { + BKE_object_defgroup_add_name(gso->object, pchan->name); + } +} + +static void gpencil_select_buffer_avg_weight_set(tGP_BrushWeightpaintData *gso) +{ + if (gso->pbuffer_used == 0) { + gso->pbuffer_avg_weight = 0.0f; + return; + } + float sum = 0; + for (int i = 0; i < gso->pbuffer_used; i++) { + tGP_Selected *selected = &gso->pbuffer[i]; + sum += selected->weight; + } + gso->pbuffer_avg_weight = sum / gso->pbuffer_used; + CLAMP(gso->pbuffer_avg_weight, 0.0f, 1.0f); +} + +/* Get boolean array of vertex groups deformed by GP armature modifiers. + * GP equivalent of `BKE_object_defgroup_validmap_get`. + */ +static bool *gpencil_vgroup_bone_deformed_map_get(Object *ob, const int defbase_tot) +{ + bDeformGroup *dg; + bool *vgroup_bone_deformed; + GHash *gh; + int i; + const ListBase *defbase = BKE_object_defgroup_list(ob); + + if (BLI_listbase_is_empty(defbase)) { + return NULL; + } + + /* Add all vertex group names to a hash table. */ + gh = BLI_ghash_str_new_ex(__func__, defbase_tot); + for (dg = defbase->first; dg; dg = dg->next) { + BLI_ghash_insert(gh, dg->name, NULL); + } + BLI_assert(BLI_ghash_len(gh) == defbase_tot); + + /* Now loop through the armature modifiers and identify deform bones. */ + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { + if (md->type != eGpencilModifierType_Armature) { + continue; + } + + ArmatureGpencilModifierData *amd = (ArmatureGpencilModifierData *)md; + + if (amd->object && amd->object->pose) { + bPose *pose = amd->object->pose; + bPoseChannel *chan; + + for (chan = pose->chanbase.first; chan; chan = chan->next) { + void **val_p; + if (chan->bone->flag & BONE_NO_DEFORM) { + continue; + } + + val_p = BLI_ghash_lookup_p(gh, chan->name); + if (val_p) { + *val_p = POINTER_FROM_INT(1); + } + } + } + } + + /* Mark vertex groups with reference in the bone hash table. */ + vgroup_bone_deformed = MEM_mallocN(sizeof(*vgroup_bone_deformed) * defbase_tot, __func__); + for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) { + vgroup_bone_deformed[i] = (BLI_ghash_lookup(gh, dg->name) != NULL); + } + + BLI_assert(i == BLI_ghash_len(gh)); + + BLI_ghash_free(gh, NULL, NULL); + + return vgroup_bone_deformed; +} + +/* ************************************************ */ +/* Auto-normalize Operations + * This section defines the functions for auto-normalizing the sum of weights to 1.0 + * for points in vertex groups deformed by bones. + * The logic is copied from `editors/sculpt_paint/paint_vertex.cc`. */ + +/** + * Normalize weights of a stroke point deformed by bones. + */ +static void do_weight_paint_normalize_all(MDeformVert *dvert, + const int defbase_tot, + const bool *vgroup_bone_deformed) +{ + float sum = 0.0f, fac; + uint tot = 0; + MDeformWeight *dw; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + tot++; + sum += dw->weight; + } + } + + if ((tot == 0) || (sum == 1.0f)) { + return; + } + + if (sum != 0.0f) { + fac = 1.0f / sum; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + dw->weight *= fac; + } + } + } + else { + fac = 1.0f / tot; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + dw->weight = fac; + } + } + } +} + +/** + * A version of #do_weight_paint_normalize_all that only changes unlocked weights. + */ +static bool do_weight_paint_normalize_all_unlocked(MDeformVert *dvert, + const int defbase_tot, + const bool *vgroup_bone_deformed, + const bool *vgroup_locked, + const bool lock_active_vgroup, + const int active_vgroup) +{ + float sum = 0.0f, fac; + float sum_unlock = 0.0f; + float sum_lock = 0.0f; + uint tot = 0; + MDeformWeight *dw; + + if (vgroup_locked == NULL) { + do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_bone_deformed); + return true; + } + + if (dvert->totweight <= 1) { + return true; + } + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + sum += dw->weight; + + if (vgroup_locked[dw->def_nr] || (lock_active_vgroup && active_vgroup == dw->def_nr)) { + sum_lock += dw->weight; + } + else { + tot++; + sum_unlock += dw->weight; + } + } + } + + if (sum == 1.0f) { + return true; + } + + if (tot == 0) { + return false; + } + + if (sum_lock >= 1.0f - VERTEX_WEIGHT_LOCK_EPSILON) { + /* Locked groups make it impossible to fully normalize, + * zero out what we can and return false. */ + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + *dw = dvert->dw[i]; + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight = 0.0f; + } + } + } + + return (sum_lock == 1.0f); + } + if (sum_unlock != 0.0f) { + fac = (1.0f - sum_lock) / sum_unlock; + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight *= fac; + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } + } + else { + fac = (1.0f - sum_lock) / tot; + CLAMP(fac, 0.0f, 1.0f); + + dw = dvert->dw; + for (int i = dvert->totweight; i != 0; i--, dw++) { + if (dw->def_nr < defbase_tot && vgroup_bone_deformed[dw->def_nr]) { + if ((vgroup_locked[dw->def_nr] == false) && + !(lock_active_vgroup && active_vgroup == dw->def_nr)) { + dw->weight = fac; + } + } + } + } + + return true; +} + +/** + * A version of #do_weight_paint_normalize_all that only changes unlocked weights + * and does a second pass without the active vertex group locked when the first pass fails. + */ +static void do_weight_paint_normalize_all_try(MDeformVert *dvert, tGP_BrushWeightpaintData *gso) +{ + /* First pass with both active and explicitly locked vertex groups restricted from change. */ + bool succes = do_weight_paint_normalize_all_unlocked( + dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, true, gso->vrgroup); + + if (!succes) { + /* Second pass with active vertex group unlocked. */ + do_weight_paint_normalize_all_unlocked( + dvert, gso->vgroup_tot, gso->vgroup_bone_deformed, gso->vgroup_locked, false, -1); + } } /* Brush Operations ------------------------------- */ @@ -185,10 +520,9 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu } /* distance fading */ - int mval_i[2]; - round_v2i_v2fl(mval_i, gso->mval); - float distance = (float)len_v2v2_int(mval_i, co); - influence *= 1.0f - (distance / max_ff(radius, 1e-8)); + int mouse_i[2]; + round_v2i_v2fl(mouse_i, gso->mouse); + float distance = (float)len_v2v2_int(mouse_i, co); /* Apply Brush curve. */ float brush_falloff = BKE_brush_curve_strength(brush, distance, (float)radius); @@ -202,12 +536,19 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu } /* Compute effect vector for directional brushes. */ -static void brush_calc_dvec_2d(tGP_BrushWeightpaintData *gso) +static void brush_calc_brush_dir_2d(tGP_BrushWeightpaintData *gso) { - gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]); - gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]); + sub_v2_v2v2(gso->brush_dir, gso->mouse, gso->mouse_prev); - normalize_v2(gso->dvec); + /* Skip tiny changes in direction, we want the bigger movements only. */ + if (len_squared_v2(gso->brush_dir) < 9.0f) { + return; + } + + normalize_v2(gso->brush_dir); + + gso->brush_dir_is_set = true; + copy_v2_v2(gso->mouse_prev, gso->mouse); } /* ************************************************ */ @@ -222,58 +563,213 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso, const int radius, const int co[2]) { - /* create dvert */ - BKE_gpencil_dvert_ensure(gps); - MDeformVert *dvert = gps->dvert + pt_index; - float inf; - /* Compute strength of effect */ - inf = brush_influence_calc(gso, radius, co); + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); - /* need a vertex group */ - if (gso->vrgroup == -1) { - if (gso->object) { - Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object); - if (ob_armature != NULL) { - Bone *actbone = ((bArmature *)ob_armature->data)->act_bone; - if (actbone != NULL) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name); - if (pchan != NULL) { - bDeformGroup *dg = BKE_object_defgroup_find_name(gso->object, pchan->name); - if (dg == NULL) { - dg = BKE_object_defgroup_add_name(gso->object, pchan->name); - } - } + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Apply brush weight. */ + float bweight = (gso->subtract) ? -gso->brush->weight : gso->brush->weight; + dw->weight = interpf(bweight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Average Brush */ +static bool brush_average_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Blend weight with average weight under the brush. */ + dw->weight = interpf(gso->pbuffer_avg_weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Blur Brush */ +static bool brush_blur_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Find the 5 nearest points (this includes the to-be-blurred point itself). */ + KDTreeNearest_2d nearest[5]; + float pc_f[2]; + copy_v2fl_v2i(pc_f, co); + const int tot = BLI_kdtree_2d_find_nearest_n(gso->fn_kdtree, pc_f, nearest, 5); + + /* Calculate the average (=blurred) weight. */ + float blur_weight = 0.0f, dist_sum = 0.0f; + int count = 0; + for (int i = 0; i < tot; i++) { + dist_sum += nearest[i].dist; + count++; + } + if (count <= 1) { + return false; + } + for (int i = 0; i < tot; i++) { + /* Weighted average, based on distance to point. */ + blur_weight += (1.0f - nearest[i].dist / dist_sum) * gso->fn_pbuffer[nearest[i].index].weight; + } + blur_weight /= (count - 1); + + /* Blend weight with blurred weight. */ + dw->weight = interpf(blur_weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); + } + + return true; +} + +/* Smear Brush */ +static bool brush_smear_apply(tGP_BrushWeightpaintData *gso, + bGPDstroke *gps, + int pt_index, + const int radius, + const int co[2]) +{ + MDeformVert *dvert = gps->dvert + pt_index; + + /* Get current weight. */ + MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); + if (dw == NULL) { + return false; + } + + /* Find the 8 nearest points (this includes the to-be-blurred point itself). */ + KDTreeNearest_2d nearest[8]; + float pc_f[2]; + copy_v2fl_v2i(pc_f, co); + const int tot = BLI_kdtree_2d_find_nearest_n(gso->fn_kdtree, pc_f, nearest, 8); + + /* For smearing a weight from point A to point B, we look for a point A 'behind' the brush, + * matching the brush angle best and with the shortest distance to B. */ + float point_dot[8] = {0}; + float point_dir[2]; + float score_max = 0.0f, dist_min = FLT_MAX, dist_max = 0.0f; + int i_max = -1, count = 0; + + for (int i = 0; i < tot; i++) { + /* Skip the point we are about to smear. */ + if (nearest[i].dist > GP_FIND_NEAREST_EPSILON) { + sub_v2_v2v2(point_dir, pc_f, nearest[i].co); + normalize_v2(point_dir); + + /* Match A-B direction with brush direction. */ + point_dot[i] = dot_v2v2(point_dir, gso->brush_dir); + if (point_dot[i] > 0.0f) { + count++; + float dist = nearest[i].dist; + if (dist < dist_min) { + dist_min = dist; + } + if (dist > dist_max) { + dist_max = dist; } } - else { - BKE_object_defgroup_add(gso->object); + } + } + if (count == 0) { + return false; + } + + /* Find best match in angle and distance. */ + float dist_f = (dist_min == dist_max) ? 1.0f : 0.95f / (dist_max - dist_min); + for (int i = 0; i < tot; i++) { + if (point_dot[i] > 0.0f) { + float score = point_dot[i] * (1.0f - (nearest[i].dist - dist_min) * dist_f); + if (score > score_max) { + score_max = score; + i_max = i; } - DEG_relations_tag_update(gso->bmain); - gso->vrgroup = 0; } } - else { - bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup); - if (defgroup->flag & DG_LOCK_WEIGHT) { - return false; - } + if (i_max == -1) { + return false; } - /* Get current weight and blend. */ - MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup); - if (dw) { - dw->weight = interpf(gso->brush->weight, dw->weight, inf); - CLAMP(dw->weight, 0.0f, 1.0f); + + /* Compute strength of effect. */ + float inf = brush_influence_calc(gso, radius, co); + + /* Smear the weight. */ + dw->weight = interpf(gso->fn_pbuffer[nearest[i_max].index].weight, dw->weight, inf); + CLAMP(dw->weight, 0.0f, 1.0f); + + /* Perform auto-normalize. */ + if (gso->auto_normalize) { + do_weight_paint_normalize_all_try(dvert, gso); } + return true; } /* ************************************************ */ /* Header Info */ -static void gpencil_weightpaint_brush_header_set(bContext *C) +static void gpencil_weightpaint_brush_header_set(bContext *C, tGP_BrushWeightpaintData *gso) { - ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit")); + switch (gso->brush->gpencil_weight_tool) { + case GPWEIGHT_TOOL_DRAW: + ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_BLUR: + ED_workspace_status_text(C, TIP_("GPencil Weight Blur: LMB to blur | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_AVERAGE: + ED_workspace_status_text( + C, TIP_("GPencil Weight Average: LMB to set average | RMB/Escape to Exit")); + break; + case GPWEIGHT_TOOL_SMEAR: + ED_workspace_status_text(C, TIP_("GPencil Weight Smear: LMB to smear | RMB/Escape to Exit")); + break; + } } /* ************************************************ */ @@ -307,6 +803,14 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) gso->pbuffer_size = 0; gso->pbuffer_used = 0; + gso->fn_pbuffer = NULL; + gso->fn_added = NULL; + gso->fn_kdtree = NULL; + gso->fn_used = 0; + gso->fn_size = 0; + gso->use_find_nearest = ((gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_BLUR) || + (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_SMEAR)); + gso->gpd = ED_gpencil_data_get_active(C); gso->scene = scene; gso->object = ob; @@ -332,11 +836,32 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) BKE_curvemapping_init(ts->gp_sculpt.cur_falloff); } + /* Draw tool: add or subtract weight? */ + gso->subtract = (gso->brush->gpencil_settings->sculpt_flag & BRUSH_DIR_IN); + + /* Setup auto-normalize. */ + gso->auto_normalize = (ts->auto_normalize && gso->vrgroup != -1); + if (gso->auto_normalize) { + gso->vgroup_tot = BLI_listbase_count(&gso->gpd->vertex_group_names); + /* Get boolean array of vertex groups deformed by bones. */ + gso->vgroup_bone_deformed = gpencil_vgroup_bone_deformed_map_get(ob, gso->vgroup_tot); + if (gso->vgroup_bone_deformed != NULL) { + /* Get boolean array of locked vertext groups. */ + gso->vgroup_locked = BKE_object_defgroup_lock_flags_get(ob, gso->vgroup_tot); + if (gso->vgroup_locked == NULL) { + gso->vgroup_locked = (bool *)MEM_callocN(sizeof(bool) * gso->vgroup_tot, __func__); + } + } + else { + gso->auto_normalize = false; + } + } + /* Setup space conversions. */ gpencil_point_conversion_init(C, &gso->gsc); /* Update header. */ - gpencil_weightpaint_brush_header_set(C); + gpencil_weightpaint_brush_header_set(C, gso); return true; } @@ -349,6 +874,15 @@ static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op) ED_workspace_status_text(C, NULL); /* Free operator data */ + MEM_SAFE_FREE(gso->vgroup_bone_deformed); + MEM_SAFE_FREE(gso->vgroup_locked); + if (gso->fn_kdtree != NULL) { + BLI_kdtree_2d_free(gso->fn_kdtree); + } + if (gso->fn_added != NULL) { + BLI_ghash_free(gso->fn_added, NULL, NULL); + } + MEM_SAFE_FREE(gso->fn_pbuffer); MEM_SAFE_FREE(gso->pbuffer); MEM_SAFE_FREE(gso); op->customdata = NULL; @@ -357,6 +891,27 @@ static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op) /* Poll callback for stroke weight paint operator. */ static bool gpencil_weightpaint_brush_poll(bContext *C) { + if (!ED_operator_regionactive(C)) { + CTX_wm_operator_poll_msg_set(C, "Active region not set"); + return false; + } + + ScrArea *area = CTX_wm_area(C); + if (area->spacetype != SPACE_VIEW3D) { + return false; + } + + bGPdata *gpd = ED_gpencil_data_get_active(C); + if ((gpd == NULL) || (!GPENCIL_WEIGHT_MODE(gpd))) { + return false; + } + + ToolSettings *ts = CTX_data_scene(C)->toolsettings; + if (!&ts->gp_weightpaint->paint.brush) { + CTX_wm_operator_poll_msg_set(C, "Grease Pencil has no active paint tool"); + return false; + } + /* NOTE: this is a bit slower, but is the most accurate... */ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } @@ -364,36 +919,88 @@ static bool gpencil_weightpaint_brush_poll(bContext *C) /* Helper to save the points selected by the brush. */ static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, - int index, - int pc[2]) + const int gps_index, + const int index, + const int pc[2], + const bool within_brush) { tGP_Selected *selected; bGPDspoint *pt = &gps->points[index]; /* Ensure the array to save the list of selected points is big enough. */ - gso->pbuffer = gpencil_select_buffer_ensure( - gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false); + gpencil_select_buffer_ensure(gso, false); - selected = &gso->pbuffer[gso->pbuffer_used]; - selected->gps = gps; - selected->pt_index = index; - copy_v2_v2_int(selected->pc, pc); - copy_v4_v4(selected->color, pt->vert_color); + /* Copy point data. */ + if (within_brush) { + selected = &gso->pbuffer[gso->pbuffer_used]; + selected->gps = gps; + selected->pt_index = index; + copy_v2_v2_int(selected->pc, pc); + copy_v4_v4(selected->color, pt->vert_color); + gso->pbuffer_used++; + } - gso->pbuffer_used++; + /* Ensure vertex group and dvert. */ + gpencil_vertex_group_ensure(gso); + BKE_gpencil_dvert_ensure(gps); + + /* Copy current weight. */ + MDeformVert *dvert = gps->dvert + index; + MDeformWeight *dw = BKE_defvert_find_index(dvert, gso->vrgroup); + if (within_brush && (dw != NULL)) { + selected->weight = dw->weight; + } + + /* Store point for finding nearest points (blur, smear). */ + if (gso->use_find_nearest) { + /* Create hash key, assuming there are no more than 65536 strokes in a frame + * and 65536 points in a stroke. */ + const int point_hash = (gps_index << GP_STROKE_HASH_BITSHIFT) + index; + + /* Prevent duplicate points in buffer. */ + if (!BLI_ghash_haskey(gso->fn_added, POINTER_FROM_INT(point_hash))) { + /* Add stroke point to find-nearest buffer. */ + selected = &gso->fn_pbuffer[gso->fn_used]; + copy_v2_v2_int(selected->pc, pc); + selected->weight = (dw == NULL) ? 0.0f : dw->weight; + + BLI_ghash_insert( + gso->fn_added, POINTER_FROM_INT(point_hash), POINTER_FROM_INT(gso->fn_used)); + + float pc_f[2]; + copy_v2_fl2(pc_f, (float)pc[0], (float)pc[1]); + BLI_kdtree_2d_insert(gso->fn_kdtree, gso->fn_used, pc_f); + + gso->fn_do_balance = true; + gso->fn_used++; + } + else { + /* Update weight of point in buffer. */ + int *idx = BLI_ghash_lookup(gso->fn_added, POINTER_FROM_INT(point_hash)); + selected = &gso->fn_pbuffer[POINTER_AS_INT(idx)]; + selected->weight = (dw == NULL) ? 0.0f : dw->weight; + } + } } /* Select points in this stroke and add to an array to be used later. */ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, + const int gps_index, const float diff_mat[4][4], const float bound_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; Brush *brush = gso->brush; - const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : + /* For the blur tool, look a bit wider than the brush itself, + * because we need the weight of surrounding points to perform the blur. */ + const bool widen_brush = (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_BLUR); + int radius_brush = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; + int radius_wide = (widen_brush) ? radius_brush * 1.3f : radius_brush; + bool within_brush = true; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; @@ -405,8 +1012,8 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, int index; bool include_last = false; - /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { + /* Check if the stroke collides with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mouse, radius_wide, bound_mat)) { return; } @@ -420,12 +1027,16 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, /* Do bound-box check first. */ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ - int mval_i[2]; - round_v2i_v2fl(mval_i, gso->mval); - if (len_v2v2_int(mval_i, pc1) <= radius) { + int mouse_i[2]; + round_v2i_v2fl(mouse_i, gso->mouse); + int mlen = len_v2v2_int(mouse_i, pc1); + if (mlen <= radius_wide) { /* apply operation to this point */ if (pt_active != NULL) { - gpencil_save_selected_point(gso, gps_active, 0, pc1); + if (widen_brush) { + within_brush = (mlen <= radius_brush); + } + gpencil_save_selected_point(gso, gps_active, gps_index, 0, pc1, within_brush); } } } @@ -453,14 +1064,19 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, * brush region (either within stroke painted, or on its lines) * - this assumes that line-width is irrelevant. */ - if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (gpencil_stroke_inside_circle( + gso->mouse, radius_wide, pc1[0], pc1[1], pc2[0], pc2[1])) { + if (widen_brush) { + within_brush = (gpencil_stroke_inside_circle( + gso->mouse, radius_brush, pc1[0], pc1[1], pc2[0], pc2[1])); + } /* To each point individually... */ pt = &gps->points[i]; pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; - gpencil_save_selected_point(gso, gps_active, index, pc1); + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc1, within_brush); } /* Only do the second point if this is the last segment, @@ -476,7 +1092,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; - gpencil_save_selected_point(gso, gps_active, index, pc2); + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc2, within_brush); include_last = false; } } @@ -494,8 +1110,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt_active = pt->runtime.pt_orig; if (pt_active != NULL) { index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; - gpencil_save_selected_point(gso, gps_active, index, pc1); - + gpencil_save_selected_point(gso, gps_active, gps_index, index, pc1, true); include_last = false; } } @@ -507,7 +1122,6 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, /* Apply weight paint brushes to strokes in the given frame. */ static bool gpencil_weightpaint_brush_do_frame(bContext *C, tGP_BrushWeightpaintData *gso, - bGPDlayer *gpl, bGPDframe *gpf, const float diff_mat[4][4], const float bound_mat[4][4]) @@ -518,39 +1132,68 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, gso->brush->size * gso->pressure : gso->brush->size; tGP_Selected *selected = NULL; - int i; + gso->fn_do_balance = false; /*--------------------------------------------------------------------- * First step: select the points affected. This step is required to have * all selected points before apply the effect, because it could be * required to do some step. Now is not used, but the operator is ready. *--------------------------------------------------------------------- */ - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + int gps_index; + LISTBASE_FOREACH_INDEX (bGPDstroke *, gps, &gpf->strokes, gps_index) { /* Skip strokes that are invalid for current view. */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - /* Check if the color is editable. */ - if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + /* Check if the color is visible. */ + if (ED_gpencil_stroke_material_visible(ob, gps) == false) { continue; } /* Check points below the brush. */ - gpencil_weightpaint_select_stroke(gso, gps, diff_mat, bound_mat); + gpencil_weightpaint_select_stroke(gso, gps, gps_index, diff_mat, bound_mat); + } + + bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup); + if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) { + return false; } /*--------------------------------------------------------------------- - * Second step: Apply effect. + * Second step: Calculations on selected points. + *--------------------------------------------------------------------- */ + /* For average tool, get average weight of affected points. */ + if (tool == GPWEIGHT_TOOL_AVERAGE) { + gpencil_select_buffer_avg_weight_set(gso); + } + /* Balance find-nearest kdtree. */ + if (gso->use_find_nearest && gso->fn_do_balance) { + BLI_kdtree_2d_balance(gso->fn_kdtree); + } + + /*--------------------------------------------------------------------- + * Third step: Apply effect. *--------------------------------------------------------------------- */ bool changed = false; - for (i = 0; i < gso->pbuffer_used; i++) { - changed = true; + for (int i = 0; i < gso->pbuffer_used; i++) { selected = &gso->pbuffer[i]; switch (tool) { case GPWEIGHT_TOOL_DRAW: { - brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); - changed |= true; + changed |= brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_AVERAGE: { + changed |= brush_average_apply( + gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_BLUR: { + changed |= brush_blur_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); + break; + } + case GPWEIGHT_TOOL_SMEAR: { + changed |= brush_smear_apply(gso, selected->gps, selected->pt_index, radius, selected->pc); break; } default: @@ -558,9 +1201,9 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, break; } } + /* Clear the selected array, but keep the memory allocation. */ - gso->pbuffer = gpencil_select_buffer_ensure( - gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true); + gpencil_select_buffer_ensure(gso, true); return changed; } @@ -615,17 +1258,14 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig } /* affect strokes in this frame */ - changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat); + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpf, diff_mat, bound_mat); } } } else { - if (gpl->actframe != NULL) { - /* Apply to active frame's strokes */ - gso->mf_falloff = 1.0f; - changed |= gpencil_weightpaint_brush_do_frame( - C, gso, gpl, gpl->actframe, diff_mat, bound_mat); - } + /* Apply to active frame's strokes */ + gso->mf_falloff = 1.0f; + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl->actframe, diff_mat, bound_mat); } } @@ -645,17 +1285,18 @@ static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, Pointer /* Get latest mouse coordinates */ RNA_float_get_array(itemptr, "mouse", mousef); - gso->mval[0] = mouse[0] = (int)(mousef[0]); - gso->mval[1] = mouse[1] = (int)(mousef[1]); + gso->mouse[0] = mouse[0] = (int)(mousef[0]); + gso->mouse[1] = mouse[1] = (int)(mousef[1]); gso->pressure = RNA_float_get(itemptr, "pressure"); /* Store coordinates as reference, if operator just started running */ if (gso->first) { - gso->mval_prev[0] = gso->mval[0]; - gso->mval_prev[1] = gso->mval[1]; - gso->pressure_prev = gso->pressure; + gso->mouse_prev[0] = gso->mouse[0]; + gso->mouse_prev[1] = gso->mouse[1]; + gso->brush_dir_is_set = false; } + gso->first = false; /* Update brush_rect, so that it represents the bounding rectangle of brush. */ gso->brush_rect.xmin = mouse[0] - radius; @@ -663,22 +1304,23 @@ static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, Pointer gso->brush_rect.xmax = mouse[0] + radius; gso->brush_rect.ymax = mouse[1] + radius; - /* Calculate 2D direction vector and relative angle. */ - brush_calc_dvec_2d(gso); + /* Calculate brush direction. */ + if (gso->brush->gpencil_weight_tool == GPWEIGHT_TOOL_SMEAR) { + brush_calc_brush_dir_2d(gso); + if (!gso->brush_dir_is_set) { + return; + } + } + + /* Apply brush to layers. */ changed = gpencil_weightpaint_brush_apply_to_layers(C, gso); - /* Updates */ + /* Updates. */ if (changed) { DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } - - /* Store values for next step */ - gso->mval_prev[0] = gso->mval[0]; - gso->mval_prev[1] = gso->mval[1]; - gso->pressure_prev = gso->pressure; - gso->first = false; } /* Running --------------------------------------------- */ @@ -699,7 +1341,6 @@ static void gpencil_weightpaint_brush_apply_event(bContext *C, RNA_collection_add(op->ptr, "stroke", &itemptr); RNA_float_set_array(&itemptr, "mouse", mouse); - RNA_boolean_set(&itemptr, "pen_flip", event->modifier & KM_CTRL); RNA_boolean_set(&itemptr, "is_start", gso->first); /* Handle pressure sensitivity (which is supplied by tablets). */ @@ -888,7 +1529,7 @@ void GPENCIL_OT_weight_paint(wmOperatorType *ot) /* identifiers */ ot->name = "Stroke Weight Paint"; ot->idname = "GPENCIL_OT_weight_paint"; - ot->description = "Paint stroke points with a color"; + ot->description = "Draw weight on stroke points"; /* api callbacks */ ot->exec = gpencil_weightpaint_brush_exec; @@ -908,3 +1549,175 @@ void GPENCIL_OT_weight_paint(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } + +/* -------------------------------------------------------------------- */ +/* Weight Toggle Add/Subtract Operator */ +static int gpencil_weight_toggle_direction_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + Paint *paint = &ts->gp_weightpaint->paint; + + /* Toggle Add/Subtract flag. */ + paint->brush->gpencil_settings->sculpt_flag ^= BRUSH_DIR_IN; + + /* Update tool settings. */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_weight_toggle_direction(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Toggle Direction"; + ot->idname = "GPENCIL_OT_weight_toggle_direction"; + ot->description = "Toggle Add/Subtract for the weight paint draw tool"; + + /* api callbacks */ + ot->invoke = gpencil_weight_toggle_direction_invoke; + ot->poll = gpencil_weightpaint_brush_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ +/* Weight Sample Operator */ +static int gpencil_weight_sample_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + /* Get mouse position. */ + int mouse[2]; + mouse[0] = event->mval[0] + 1; + mouse[1] = event->mval[1] + 1; + float mouse_f[2]; + copy_v2fl_v2i(mouse_f, mouse); + + /* Get active GP object. */ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if ((ob == NULL) || (gpd == NULL)) { + return OPERATOR_CANCELLED; + } + + /* Get active vertex group. */ + int vgroup = gpd->vertex_group_active_index - 1; + bDeformGroup *defgroup = BLI_findlink(&gpd->vertex_group_names, vgroup); + if (!defgroup) { + return OPERATOR_CANCELLED; + } + + /* Init space conversion. */ + GP_SpaceConversion gsc = {NULL}; + gpencil_point_conversion_init(C, &gsc); + + /* Get evaluated GP object. */ + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + + /* Get brush radius. */ + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = ts->gp_weightpaint->paint.brush; + const int radius = brush->size; + + /* Init closest points. */ + float closest_dist[2] = {FLT_MAX, FLT_MAX}; + float closest_weight[2] = {0.0f, 0.0f}; + int closest_count = 0; + int pc[2] = {0}; + + /* Inspect all layers. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_eval->layers) { + /* If no active frame, don't do anything. */ + if (gpl->actframe == NULL) { + continue; + } + + /* Calculate transform matrix. */ + float diff_mat[4][4], bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); + copy_m4_m4(bound_mat, diff_mat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat); + + /* Inspect all strokes in active frame. */ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { + /* Look for strokes that collide with the brush. */ + if (!ED_gpencil_stroke_check_collision(&gsc, gps, mouse_f, radius, bound_mat)) { + continue; + } + if (gps->dvert == NULL) { + continue; + } + + /* Look for two closest points. */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + bGPDspoint npt; + + gpencil_point_to_world_space(pt, diff_mat, &npt); + gpencil_point_to_xy(&gsc, gps, &npt, &pc[0], &pc[1]); + + float dist = len_v2v2_int(pc, mouse); + + if ((dist < closest_dist[0]) || (dist < closest_dist[1])) { + /* Get weight. */ + MDeformVert *dvert = &gps->dvert[i]; + MDeformWeight *dw = BKE_defvert_find_index(dvert, vgroup); + if (dw == NULL) { + continue; + } + if (dist < closest_dist[0]) { + closest_dist[1] = closest_dist[0]; + closest_weight[1] = closest_weight[0]; + closest_dist[0] = dist; + closest_weight[0] = dw->weight; + closest_count++; + } + else if (dist < closest_dist[1]) { + closest_dist[1] = dist; + closest_weight[1] = dw->weight; + closest_count++; + } + } + } + } + } + + /* Set brush weight, based on points found.*/ + if (closest_count > 0) { + if (closest_count == 1) { + brush->weight = closest_weight[0]; + } + else { + CLAMP_MIN(closest_dist[1], 1e-6f); + float dist_sum = closest_dist[0] + closest_dist[1]; + brush->weight = (1.0f - closest_dist[0] / dist_sum) * closest_weight[0] + + (1.0f - closest_dist[1] / dist_sum) * closest_weight[1]; + } + + /* Update tool settings. */ + WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void GPENCIL_OT_weight_sample(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Weight Paint Sample Weight"; + ot->idname = "GPENCIL_OT_weight_sample"; + ot->description = "Use the mouse to sample a weight in the 3D view"; + + /* api callbacks */ + ot->invoke = gpencil_weight_sample_invoke; + ot->poll = gpencil_weightpaint_brush_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index b5b190f7957..772f45ceb02 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -2215,6 +2215,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) case GP_BRUSH_ICON_GPBRUSH_WEIGHT: br->id.icon_id = ICON_GPBRUSH_WEIGHT; break; + case GP_BRUSH_ICON_GPBRUSH_BLUR: + br->id.icon_id = ICON_BRUSH_BLUR; + break; + case GP_BRUSH_ICON_GPBRUSH_AVERAGE: + br->id.icon_id = ICON_BRUSH_BLUR; + break; + case GP_BRUSH_ICON_GPBRUSH_SMEAR: + br->id.icon_id = ICON_BRUSH_BLUR; + break; default: br->id.icon_id = ICON_GPBRUSH_PEN; break; diff --git a/source/blender/editors/screen/area.cc b/source/blender/editors/screen/area.cc index 1b6cb2a80de..3bb43bcb975 100644 --- a/source/blender/editors/screen/area.cc +++ b/source/blender/editors/screen/area.cc @@ -1845,6 +1845,18 @@ static void ed_default_handlers( wmKeyMap *keymap_weight_draw = WM_keymap_ensure( wm->defaultconf, "Grease Pencil Stroke Weight (Draw)", 0, 0); WM_event_add_keymap_handler(handlers, keymap_weight_draw); + + wmKeyMap *keymap_weight_blur = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Blur)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_blur); + + wmKeyMap *keymap_weight_average = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Average)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_average); + + wmKeyMap *keymap_weight_smear = WM_keymap_ensure( + wm->defaultconf, "Grease Pencil Stroke Weight (Smear)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_weight_smear); } } diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index c68930fd43a..124250c44c9 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -132,7 +132,19 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool, break; } case CTX_MODE_WEIGHT_GPENCIL: { - return GP_BRUSH_PRESET_DRAW_WEIGHT; + if (STREQ(tool->runtime->data_block, "DRAW")) { + return GP_BRUSH_PRESET_WEIGHT_DRAW; + } + if (STREQ(tool->runtime->data_block, "BLUR")) { + return GP_BRUSH_PRESET_WEIGHT_BLUR; + } + if (STREQ(tool->runtime->data_block, "AVERAGE")) { + return GP_BRUSH_PRESET_WEIGHT_AVERAGE; + } + if (STREQ(tool->runtime->data_block, "SMEAR")) { + return GP_BRUSH_PRESET_WEIGHT_SMEAR; + } + break; } case CTX_MODE_VERTEX_GPENCIL: { if (STREQ(tool->runtime->data_block, "DRAW")) { diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 4828ef03679..3e64fdcdea5 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -3665,8 +3665,7 @@ static bool do_mesh_box_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ - struct BoxSelectUserData_ForMeshEdge cb_data { - }; + struct BoxSelectUserData_ForMeshEdge cb_data {}; cb_data.data = &data; cb_data.esel = use_zbuf ? esel : nullptr; cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 9a0ad3b6d99..34ba89e8e7e 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -50,7 +50,10 @@ typedef enum eGPBrush_Presets { GP_BRUSH_PRESET_CLONE_STROKE = 208, /* Weight Paint 300-399. */ - GP_BRUSH_PRESET_DRAW_WEIGHT = 300, + GP_BRUSH_PRESET_WEIGHT_DRAW = 300, + GP_BRUSH_PRESET_WEIGHT_BLUR = 301, + GP_BRUSH_PRESET_WEIGHT_AVERAGE = 302, + GP_BRUSH_PRESET_WEIGHT_SMEAR = 303, } eGPBrush_Presets; /* BrushGpencilSettings->flag */ @@ -187,6 +190,9 @@ typedef enum eGP_BrushIcons { GP_BRUSH_ICON_GPBRUSH_PINCH = 26, GP_BRUSH_ICON_GPBRUSH_CLONE = 27, GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28, + GP_BRUSH_ICON_GPBRUSH_BLUR = 29, + GP_BRUSH_ICON_GPBRUSH_AVERAGE = 30, + GP_BRUSH_ICON_GPBRUSH_SMEAR = 31, } eGP_BrushIcons; typedef enum eBrushCurvePreset { @@ -607,6 +613,9 @@ typedef enum eBrushGPSculptTool { /* BrushGpencilSettings->brush type */ typedef enum eBrushGPWeightTool { GPWEIGHT_TOOL_DRAW = 0, + GPWEIGHT_TOOL_BLUR = 1, + GPWEIGHT_TOOL_AVERAGE = 2, + GPWEIGHT_TOOL_SMEAR = 3, } eBrushGPWeightTool; /* direction that the brush displaces along */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 4fda642e2e2..9505031bb76 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -293,7 +293,18 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = { "WEIGHT", ICON_GPBRUSH_WEIGHT, "Weight", - "Weight Paint for Vertex Groups"}, + "Paint weight in active vertex group"}, + {GPWEIGHT_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur weight in active vertex group"}, + {GPWEIGHT_TOOL_AVERAGE, + "AVERAGE", + ICON_BRUSH_BLUR, + "Average", + "Average weight in active vertex group"}, + {GPWEIGHT_TOOL_SMEAR, + "SMEAR", + ICON_BRUSH_SMEAR, + "Smear", + "Smear weight in active vertex group"}, {0, NULL, 0, NULL, NULL}, }; @@ -401,6 +412,9 @@ static EnumPropertyItem rna_enum_gpencil_brush_sculpt_icons_items[] = { static EnumPropertyItem rna_enum_gpencil_brush_weight_icons_items[] = { {GP_BRUSH_ICON_GPBRUSH_WEIGHT, "DRAW", ICON_GPBRUSH_WEIGHT, "Draw", ""}, + {GP_BRUSH_ICON_GPBRUSH_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""}, + {GP_BRUSH_ICON_GPBRUSH_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""}, + {GP_BRUSH_ICON_GPBRUSH_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = { -- 2.30.2 From dda4c0721cba2d7ea243ad20f0018e1b7288c719 Mon Sep 17 00:00:00 2001 From: Jason Fielder Date: Thu, 20 Apr 2023 08:03:31 +0200 Subject: [PATCH 43/61] EEVEE-Next: Resolve compilation errors in Metal Shader source requires explicit conversions and shader address space qualifers in certain places in order to compile for Metal. We also require constructors for a number of default struct types. Authored by Apple: Michael Parkin-White Pull Request: https://projects.blender.org/blender/blender/pulls/106219 --- .../eevee_depth_of_field_accumulator_lib.glsl | 2 +- .../shaders/eevee_hiz_update_comp.glsl | 6 +- .../eevee_light_culling_tile_comp.glsl | 4 +- .../eevee_motion_blur_dilate_comp.glsl | 21 ++++-- .../eevee_motion_blur_gather_comp.glsl | 4 +- .../shaders/eevee_nodetree_lib.glsl | 4 +- .../shaders/eevee_shadow_tag_update_comp.glsl | 4 +- .../shaders/eevee_shadow_tag_usage_lib.glsl | 2 +- .../workbench_shadow_visibility_comp.glsl | 2 +- .../blender/draw/intern/draw_shader_shared.h | 22 +++++- source/blender/draw/intern/draw_view.cc | 20 +++--- .../draw/intern/shaders/common_aabb_lib.glsl | 8 +++ .../intern/shaders/common_intersect_lib.glsl | 17 +++-- .../draw/intern/shaders/common_shape_lib.glsl | 18 ++++- .../shaders/draw_view_finalize_comp.glsl | 72 +++++++++---------- .../intern/shaders/draw_visibility_comp.glsl | 5 +- .../gpu/shaders/metal/mtl_shader_defines.msl | 59 +++++++++++++-- .../shaders/opengl/glsl_shader_defines.glsl | 6 ++ 18 files changed, 191 insertions(+), 85 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl index 1da741d7609..957c9b01a2a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl @@ -590,7 +590,7 @@ void dof_gather_accumulator(sampler2D color_tx, * The full pixel neighborhood is gathered. * \{ */ -void dof_slight_focus_gather(sampler2D depth_tx, +void dof_slight_focus_gather(depth2D depth_tx, sampler2D color_tx, sampler2D bkh_lut_tx, /* Renamed because of ugly macro job. */ float radius, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl index 479a6b590b0..cea25ef7ce0 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_hiz_update_comp.glsl @@ -62,7 +62,7 @@ void main() int mask_shift = 1; #define downsample_level(out_mip__, lod_) \ - active_thread = all(lessThan(local_px, gl_WorkGroupSize.xy >> uint(mask_shift))); \ + active_thread = all(lessThan(uvec2(local_px), gl_WorkGroupSize.xy >> uint(mask_shift))); \ barrier(); /* Wait for previous writes to finish. */ \ if (active_thread) { \ max_depth = max_v4(load_local_depths(local_px)); \ @@ -89,12 +89,12 @@ void main() } finished_tile_counter = 0u; - ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize * 2u)); + ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize.xy * 2u)); ivec2 image_border = imageSize(out_mip_5) - 1; for (int y = 0; y < iter.y; y++) { for (int x = 0; x < iter.x; x++) { /* Load result of the other work groups. */ - kernel_origin = ivec2(gl_WorkGroupSize) * ivec2(x, y); + kernel_origin = ivec2(gl_WorkGroupSize.xy) * ivec2(x, y); src_px = ivec2(kernel_origin + local_px) * 2; vec4 samp; samp.x = imageLoad(out_mip_5, min(src_px + ivec2(0, 1), image_border)).x; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl index 37705e22b22..1f012a44acf 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_culling_tile_comp.glsl @@ -168,13 +168,15 @@ void main() } /* Fallthrough to the hemispheric case. */ case LIGHT_RECT: - case LIGHT_ELLIPSE: + case LIGHT_ELLIPSE: { vec3 v000 = vP - v_right * radius - v_up * radius; vec3 v100 = v000 + v_right * (radius * 2.0); vec3 v010 = v000 + v_up * (radius * 2.0); vec3 v001 = v000 - v_back * radius; Box bbox = shape_box(v000, v100, v010, v001); intersect_tile = intersect_tile && intersect(tile, bbox); + break; + } default: break; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl index 07139ea6a09..e365da53d2b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl @@ -74,8 +74,10 @@ void main() vec4 max_motion = imageLoad(in_tiles_img, src_tile); - MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile); - MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, + uvec2(src_tile)); + MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, + uvec2(src_tile)); if (true) { /* Rectangular area (in tiles) where the motion vector spreads. */ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy); @@ -85,17 +87,20 @@ void main() for (int y = 0; y < motion_rect.extent.y; y++) { ivec2 tile = motion_rect.bottom_left + ivec2(x, y); if (is_inside_motion_line(tile, motion_line)) { - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv); /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in * the motion next so that weighting in gather pass is better. */ - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt); } } } } if (true) { - MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, + uvec2(src_tile)); /* Rectangular area (in tiles) where the motion vector spreads. */ MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw); MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw); @@ -104,10 +109,12 @@ void main() for (int y = 0; y < motion_rect.extent.y; y++) { ivec2 tile = motion_rect.bottom_left + ivec2(x, y); if (is_inside_motion_line(tile, motion_line)) { - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt); /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in * the motion next so that weighting in gather pass is better. */ - motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + motion_blur_tile_indirection_store( + tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv); } } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl index 5249e6637b6..1408f28e585 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl @@ -178,10 +178,10 @@ void main() vec4 max_motion; /* Load dilation result from the indirection table. */ ivec2 tile_prev; - motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev); + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, uvec2(tile), tile_prev); max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy; ivec2 tile_next; - motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next); + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, uvec2(tile), tile_next); max_motion.zw = imageLoad(in_tiles_img, tile_next).zw; Accumulator accum; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index db38baab6a4..6d802a6d79a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -242,13 +242,13 @@ void output_aov(vec4 color, float value, uint hash) #if defined(MAT_AOV_SUPPORT) && defined(GPU_FRAGMENT_SHADER) for (int i = 0; i < AOV_MAX && i < aov_buf.color_len; i++) { if (aov_buf.hash_color[i] == hash) { - imageStore(aov_color_img, ivec3(gl_FragCoord.xy, i), color); + imageStore(aov_color_img, ivec3(ivec2(gl_FragCoord.xy), i), color); return; } } for (int i = 0; i < AOV_MAX && i < aov_buf.value_len; i++) { if (aov_buf.hash_value[i] == hash) { - imageStore(aov_value_img, ivec3(gl_FragCoord.xy, i), vec4(value)); + imageStore(aov_value_img, ivec3(ivec2(gl_FragCoord.xy), i), vec4(value)); return; } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl index 475d456db7a..9f9a4c88f9c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl @@ -65,7 +65,7 @@ void main() } AABB aabb_tag; - AABB aabb_map = AABB(vec3(-0.99999), vec3(0.99999)); + AABB aabb_map = shape_aabb(vec3(-0.99999), vec3(0.99999)); /* Directionnal winmat have no correct near/far in the Z dimension at this point. * Do not clip in this dimension. */ @@ -87,7 +87,7 @@ void main() for (int y = box_min.y; y <= box_max.y; y++) { for (int x = box_min.x; x <= box_max.x; x++) { int tile_index = shadow_tile_offset(ivec2(x, y), tilemap.tiles_index, lod); - atomicOr(tiles_buf[tile_index], SHADOW_DO_UPDATE); + atomicOr(tiles_buf[tile_index], uint(SHADOW_DO_UPDATE)); } } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl index bb18f56ec74..172fe9488f4 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl @@ -21,7 +21,7 @@ void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_ tile_co >>= lod; int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod); - atomicOr(tiles_buf[tile_index], SHADOW_IS_USED); + atomicOr(tiles_buf[tile_index], uint(SHADOW_IS_USED)); } void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius) diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl index aef73672a8a..346e10d7083 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_visibility_comp.glsl @@ -44,7 +44,7 @@ bool is_visible(IsectBox box) bool intersects_near_plane(IsectBox box) { - vec4 near_plane = drw_view_culling.planes[4]; + vec4 near_plane = drw_view_culling.frustum_planes.planes[4]; bool on_positive_side = false; bool on_negative_side = false; diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 28090ef2b46..3ad1e11df28 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -21,6 +21,8 @@ typedef struct DispatchCommand DispatchCommand; typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer; typedef struct DRWDebugVert DRWDebugVert; typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer; +typedef struct FrustumCorners FrustumCorners; +typedef struct FrustumPlanes FrustumPlanes; /* __cplusplus is true when compiling with MSL. */ # if defined(__cplusplus) && !defined(GPU_SHADER) @@ -94,11 +96,27 @@ uint drw_view_id = 0; # define DRW_VIEW_FROM_RESOURCE_ID drw_view_id = (drw_ResourceID & DRW_VIEW_MASK) #endif +struct FrustumCorners { + float4 corners[8]; +}; +BLI_STATIC_ASSERT_ALIGN(FrustumCorners, 16) + +struct FrustumPlanes { + /* [0] left + * [1] right + * [2] bottom + * [3] top + * [4] near + * [5] far */ + float4 planes[6]; +}; +BLI_STATIC_ASSERT_ALIGN(FrustumPlanes, 16) + struct ViewCullingData { /** \note vec3 array padded to vec4. */ /** Frustum corners. */ - float4 corners[8]; - float4 planes[6]; + FrustumCorners frustum_corners; + FrustumPlanes frustum_planes; float4 bound_sphere; }; BLI_STATIC_ASSERT_ALIGN(ViewCullingData, 16) diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index 30417ff6420..c6b7ac11017 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -50,7 +50,8 @@ void View::frustum_boundbox_calc(int view_id) } #endif - MutableSpan corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)}; + MutableSpan corners = {culling_[view_id].frustum_corners.corners, + ARRAY_SIZE(culling_[view_id].frustum_corners.corners)}; float left, right, bottom, top, near, far; bool is_persp = data_[view_id].winmat[3][3] == 0.0f; @@ -89,15 +90,15 @@ void View::frustum_culling_planes_calc(int view_id) { float4x4 persmat = data_[view_id].winmat * data_[view_id].viewmat; planes_from_projmat(persmat.ptr(), - culling_[view_id].planes[0], - culling_[view_id].planes[5], - culling_[view_id].planes[1], - culling_[view_id].planes[3], - culling_[view_id].planes[4], - culling_[view_id].planes[2]); + culling_[view_id].frustum_planes.planes[0], + culling_[view_id].frustum_planes.planes[5], + culling_[view_id].frustum_planes.planes[1], + culling_[view_id].frustum_planes.planes[3], + culling_[view_id].frustum_planes.planes[4], + culling_[view_id].frustum_planes.planes[2]); /* Normalize. */ - for (float4 &plane : culling_[view_id].planes) { + for (float4 &plane : culling_[view_id].frustum_planes.planes) { plane.w /= normalize_v3(plane); } } @@ -105,7 +106,8 @@ void View::frustum_culling_planes_calc(int view_id) void View::frustum_culling_sphere_calc(int view_id) { BoundSphere &bsphere = *reinterpret_cast(&culling_[view_id].bound_sphere); - Span corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)}; + Span corners = {culling_[view_id].frustum_corners.corners, + ARRAY_SIZE(culling_[view_id].frustum_corners.corners)}; /* Extract Bounding Sphere */ if (data_[view_id].winmat[3][3] != 0.0f) { diff --git a/source/blender/draw/intern/shaders/common_aabb_lib.glsl b/source/blender/draw/intern/shaders/common_aabb_lib.glsl index b5f664a6779..5adcdec4a3e 100644 --- a/source/blender/draw/intern/shaders/common_aabb_lib.glsl +++ b/source/blender/draw/intern/shaders/common_aabb_lib.glsl @@ -9,6 +9,14 @@ struct AABB { vec3 min, max; }; +AABB shape_aabb(vec3 min, vec3 max) +{ + AABB aabb; + aabb.min = min; + aabb.max = max; + return aabb; +} + AABB aabb_init_min_max() { AABB aabb; diff --git a/source/blender/draw/intern/shaders/common_intersect_lib.glsl b/source/blender/draw/intern/shaders/common_intersect_lib.glsl index e23216ec2e2..252298022e3 100644 --- a/source/blender/draw/intern/shaders/common_intersect_lib.glsl +++ b/source/blender/draw/intern/shaders/common_intersect_lib.glsl @@ -136,7 +136,7 @@ bool intersect_view(Pyramid pyramid) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 5; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(pyramid.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(pyramid.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -158,7 +158,8 @@ bool intersect_view(Pyramid pyramid) for (int p = 0; p < 5; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_pyramid.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_pyramid.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -181,7 +182,7 @@ bool intersect_view(Box box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(box.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(box.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -203,7 +204,8 @@ bool intersect_view(Box box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_box.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -227,7 +229,7 @@ bool intersect_view(IsectBox i_box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(drw_view_culling.planes[p], vec4(i_box.corners[v], 1.0)); + float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(i_box.corners[v], 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -247,7 +249,8 @@ bool intersect_view(IsectBox i_box) for (int p = 0; p < 6; ++p) { bool is_any_vertex_on_positive_side = false; for (int v = 0; v < 8; ++v) { - float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0)); + float test = dot(i_box.planes[p], + vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0)); if (test > 0.0) { is_any_vertex_on_positive_side = true; break; @@ -268,7 +271,7 @@ bool intersect_view(Sphere sphere) bool intersects = true; for (int p = 0; p < 6 && intersects; ++p) { - float dist_to_plane = dot(drw_view_culling.planes[p], vec4(sphere.center, 1.0)); + float dist_to_plane = dot(drw_view_culling.frustum_planes.planes[p], vec4(sphere.center, 1.0)); if (dist_to_plane < -sphere.radius) { intersects = false; } diff --git a/source/blender/draw/intern/shaders/common_shape_lib.glsl b/source/blender/draw/intern/shaders/common_shape_lib.glsl index 56722c417aa..25a2781d729 100644 --- a/source/blender/draw/intern/shaders/common_shape_lib.glsl +++ b/source/blender/draw/intern/shaders/common_shape_lib.glsl @@ -18,7 +18,10 @@ struct Circle { Circle shape_circle(vec2 center, float radius) { - return Circle(center, radius); + Circle circle; + circle.center = center; + circle.radius = radius; + return circle; } /** \} */ @@ -34,7 +37,10 @@ struct Sphere { Sphere shape_sphere(vec3 center, float radius) { - return Sphere(center, radius); + Sphere sphere; + sphere.center = center; + sphere.radius = radius; + return sphere; } /** \} */ @@ -192,6 +198,14 @@ Frustum shape_frustum(vec3 corners[8]) struct Cone { vec3 direction; float angle_cos; + +#ifdef GPU_METAL + inline Cone() = default; + inline Cone(vec3 in_direction, float in_angle_cos) + : direction(in_direction), angle_cos(in_angle_cos) + { + } +#endif }; Cone shape_cone(vec3 direction, float angle_cosine) diff --git a/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl b/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl index f3af010a47c..6fc34af815d 100644 --- a/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl @@ -33,18 +33,19 @@ void projmat_dimensions(mat4 winmat, } } -void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8]) +void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out FrustumCorners frustum_corners) { float left, right, bottom, top, near, far; bool is_persp = winmat[3][3] == 0.0; projmat_dimensions(winmat, left, right, bottom, top, near, far); - corners[0][2] = corners[3][2] = corners[7][2] = corners[4][2] = -near; - corners[0][0] = corners[3][0] = left; - corners[4][0] = corners[7][0] = right; - corners[0][1] = corners[4][1] = bottom; - corners[7][1] = corners[3][1] = top; + frustum_corners.corners[0][2] = frustum_corners.corners[3][2] = frustum_corners.corners[7][2] = + frustum_corners.corners[4][2] = -near; + frustum_corners.corners[0][0] = frustum_corners.corners[3][0] = left; + frustum_corners.corners[4][0] = frustum_corners.corners[7][0] = right; + frustum_corners.corners[0][1] = frustum_corners.corners[4][1] = bottom; + frustum_corners.corners[7][1] = frustum_corners.corners[3][1] = top; /* Get the coordinates of the far plane. */ if (is_persp) { @@ -55,25 +56,20 @@ void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8]) top *= sca_far; } - corners[1][2] = corners[2][2] = corners[6][2] = corners[5][2] = -far; - corners[1][0] = corners[2][0] = left; - corners[6][0] = corners[5][0] = right; - corners[1][1] = corners[5][1] = bottom; - corners[2][1] = corners[6][1] = top; + frustum_corners.corners[1][2] = frustum_corners.corners[2][2] = frustum_corners.corners[6][2] = + frustum_corners.corners[5][2] = -far; + frustum_corners.corners[1][0] = frustum_corners.corners[2][0] = left; + frustum_corners.corners[6][0] = frustum_corners.corners[5][0] = right; + frustum_corners.corners[1][1] = frustum_corners.corners[5][1] = bottom; + frustum_corners.corners[2][1] = frustum_corners.corners[6][1] = top; /* Transform into world space. */ for (int i = 0; i < 8; i++) { - corners[i].xyz = transform_point(viewinv, corners[i].xyz); + frustum_corners.corners[i].xyz = transform_point(viewinv, frustum_corners.corners[i].xyz); } } -void planes_from_projmat(mat4 mat, - out vec4 left, - out vec4 right, - out vec4 bottom, - out vec4 top, - out vec4 near, - out vec4 far) +void planes_from_projmat(mat4 mat, out FrustumPlanes frustum_planes) { /* References: * @@ -81,35 +77,35 @@ void planes_from_projmat(mat4 mat, * http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf */ mat = transpose(mat); - left = mat[3] + mat[0]; - right = mat[3] - mat[0]; - bottom = mat[3] + mat[1]; - top = mat[3] - mat[1]; - near = mat[3] + mat[2]; - far = mat[3] - mat[2]; + frustum_planes.planes[0] = mat[3] + mat[0]; + frustum_planes.planes[1] = mat[3] - mat[0]; + frustum_planes.planes[2] = mat[3] + mat[1]; + frustum_planes.planes[3] = mat[3] - mat[1]; + frustum_planes.planes[4] = mat[3] + mat[2]; + frustum_planes.planes[5] = mat[3] - mat[2]; } -void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out vec4 planes[6]) +void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out FrustumPlanes frustum_planes) { mat4 persmat = winmat * viewmat; - planes_from_projmat(persmat, planes[0], planes[5], planes[1], planes[3], planes[4], planes[2]); + planes_from_projmat(persmat, frustum_planes); /* Normalize. */ for (int p = 0; p < 6; p++) { - planes[p] /= length(planes[p].xyz); + frustum_planes.planes[p] /= length(frustum_planes.planes[p].xyz); } } -vec4 frustum_culling_sphere_calc(vec4 corners[8]) +vec4 frustum_culling_sphere_calc(FrustumCorners frustum_corners) { /* Extract Bounding Sphere */ /* TODO(fclem): This is significantly less precise than CPU, but it isn't used in most cases. */ vec4 bsphere; - bsphere.xyz = (corners[0].xyz + corners[6].xyz) * 0.5; + bsphere.xyz = (frustum_corners.corners[0].xyz + frustum_corners.corners[6].xyz) * 0.5; bsphere.w = 0.0; for (int i = 0; i < 8; i++) { - bsphere.w = max(bsphere.w, distance(bsphere.xyz, corners[i].xyz)); + bsphere.w = max(bsphere.w, distance(bsphere.xyz, frustum_corners.corners[i].xyz)); } return bsphere; } @@ -125,11 +121,15 @@ void main() return; } - frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, view_culling_buf[drw_view_id].corners); + /* Read frustom_corners from device memory, update, and write back. */ + FrustumCorners frustum_corners = view_culling_buf[drw_view_id].frustum_corners; + frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, frustum_corners); + view_culling_buf[drw_view_id].frustum_corners = frustum_corners; - frustum_culling_planes_calc( - drw_view.winmat, drw_view.viewmat, view_culling_buf[drw_view_id].planes); + /* Read frustum_planes from device memory, update, and write back. */ + FrustumPlanes frustum_planes = view_culling_buf[drw_view_id].frustum_planes; + frustum_culling_planes_calc(drw_view.winmat, drw_view.viewmat, frustum_planes); - view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc( - view_culling_buf[drw_view_id].corners); + view_culling_buf[drw_view_id].frustum_planes = frustum_planes; + view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc(frustum_corners); } diff --git a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl index f3ca51dbf6b..0d2717aea64 100644 --- a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl @@ -34,8 +34,9 @@ void main() bounds.bounding_corners[1].xyz, bounds.bounding_corners[2].xyz, bounds.bounding_corners[3].xyz); - Sphere bounding_sphere = Sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); - Sphere inscribed_sphere = Sphere(bounds.bounding_sphere.xyz, bounds._inner_sphere_radius); + Sphere bounding_sphere = shape_sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); + Sphere inscribed_sphere = shape_sphere(bounds.bounding_sphere.xyz, + bounds._inner_sphere_radius); for (drw_view_id = 0; drw_view_id < view_len; drw_view_id++) { if (drw_view_culling.bound_sphere.w == -1.0) { diff --git a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl index a192e51a0ec..dfb74a3e76b 100644 --- a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl +++ b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl @@ -101,10 +101,18 @@ struct constexp_uvec3 { return 0; } } - inline operator uint3() const + constexpr inline operator uint3() const { return xyz; } + constexpr inline operator uint2() const + { + return xy; + } + constexpr inline operator uint() const + { + return x; + } }; constexpr constexp_uvec3 __internal_workgroupsize_get() @@ -140,6 +148,10 @@ template T atomicSub(threadgroup T &mem, T data) { return atomic_fetch_sub_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); } +template T atomicAnd(threadgroup T &mem, T data) +{ + return atomic_fetch_and_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); +} template T atomicOr(threadgroup T &mem, T data) { return atomic_fetch_or_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); @@ -152,29 +164,41 @@ template T atomicXor(threadgroup T &mem, T data) /* Device memory. */ template T atomicMax(device T &mem, T data) { - return atomic_fetch_max_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_max_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicMin(device T &mem, T data) { - return atomic_fetch_min_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_min_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicAdd(device T &mem, T data) { - return atomic_fetch_add_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_add_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicSub(device T &mem, T data) { - return atomic_fetch_sub_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_sub_explicit((device _atomic *)&mem, data, memory_order_relaxed); +} +template T atomicAnd(device T &mem, T data) +{ + return atomic_fetch_and_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicOr(device T &mem, T data) { - return atomic_fetch_or_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_or_explicit((device _atomic *)&mem, data, memory_order_relaxed); } template T atomicXor(device T &mem, T data) { - return atomic_fetch_xor_explicit((threadgroup _atomic *)&mem, data, memory_order_relaxed); + return atomic_fetch_xor_explicit((device _atomic *)&mem, data, memory_order_relaxed); } +/* Unblock texture atomic compilation. + * TODO(Metal): This is not correct for global atomic behaviour, but will be safe within a single thread. + * We need to re-visit the solution for this use-case and use a 2D texture buffer instead. */ +#define imageAtomicMin(tex, coord, data) \ + uint val = _texelFetch_internal(tex, coord, 0).r;\ + _texture_write_internal(tex, coord, uint4((val < data) ? val : data));\ + tex.texture->fence(); + /* Used to replace 'out' in function parameters with threadlocal reference * shortened to avoid expanding the glsl source string. */ #define THD thread @@ -1126,6 +1150,27 @@ inline float4 uintBitsToFloat(uint4 f) return as_type(f); } +#define bitfieldReverse reverse_bits +#define bitfieldExtract extract_bits +#define bitfieldInsert insert_bits +#define bitCount popcount + +template T findLSB(T x) +{ + /* ctz returns the number of trailing zeroes. To fetch the index of the LSB, we can also use this + * value as index, however need to filter out the case where the input value is zero to match + * GLSL functionality. */ + return (x == T(0)) ? T(-1) : T(ctz(x)); +} + +template T findMSB(T x) +{ + /* clz returns the number of leading zeroes. To fetch the index of the LSB, we can also use this + * value as index when offset by 1. however need to filter out the case where the input value is + * zero to match GLSL functionality. 000000010*/ + return (x == T(0)) ? T(-1) : (clz(T(0)) - clz(x) - T(1)); +} + /* Texture size functions. Add texture types as needed. */ #define imageSize(image) textureSize(image, 0) diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl index f2d972ea574..eb09f580391 100644 --- a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl +++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl @@ -15,6 +15,12 @@ #define depthCubeArray samplerCubeArray #define depth2DArrayShadow sampler2DArrayShadow +/* Memory scope and pass by reference types. + * NOTE: These are required by Metal, but are not required in all cases by GLSL. */ +#define device +#define threadgroup +#define OUT(type, name, array_len) out type name[array_len] + /* Backend Functions. */ #define select(A, B, mask) mix(A, B, mask) -- 2.30.2 From b69f8de5b562ac0830e0d41882ed8c442e796eae Mon Sep 17 00:00:00 2001 From: Jason Fielder Date: Thu, 20 Apr 2023 08:47:56 +0200 Subject: [PATCH 44/61] Fix #105450: Resolve box selection issue in Metal Occlusion query buffers not being cleared to zero resulted in erroneoues selection in certain situations. Authored by Apple: Michael Parkin-White Pull Request: https://projects.blender.org/blender/blender/pulls/107135 --- source/blender/gpu/metal/mtl_query.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/gpu/metal/mtl_query.mm b/source/blender/gpu/metal/mtl_query.mm index f2c05ce9afd..897f9cb202e 100644 --- a/source/blender/gpu/metal/mtl_query.mm +++ b/source/blender/gpu/metal/mtl_query.mm @@ -33,6 +33,11 @@ void MTLQueryPool::allocate() gpu::MTLBuffer *buffer = MTLContext::get_global_memory_manager()->allocate(buffer_size_in_bytes, true); BLI_assert(buffer); + + /* We must zero-initialize the query buffer as visibility queries with no draws between + * begin and end will not write any result to the buffer. */ + memset(buffer->get_host_ptr(), 0, buffer_size_in_bytes); + buffer->flush(); buffer_.append(buffer); } -- 2.30.2 From 88b125e75d6e82926d30b8a7f70ef5c3812ea2de Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 20 Apr 2023 08:56:55 +0200 Subject: [PATCH 45/61] Fix regression tests failure on the latest Xcode When using Xcode version 14.3 on Apple Silicon hardware a number of regression tests fails. This change fixes this problem. The root cause comes to the floating point contraction. It was already disabled for GCC on Linux, but not for Clang on neither of Linux or macOS. Also corrected the comment about Clang default, as it as set to on somewhere in 2021. Pull Request: https://projects.blender.org/blender/blender/pulls/107136 --- build_files/cmake/platform/platform_apple.cmake | 2 +- build_files/cmake/platform/platform_unix.cmake | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 20114191c52..33e817da449 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -174,7 +174,7 @@ if(SYSTEMSTUBS_LIBRARY) list(APPEND PLATFORM_LINKLIBS SystemStubs) endif() -string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing") +string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing -ffp-contract=off") set(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework Metal -framework QuartzCore" ) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 72de4c59203..a56363dbd43 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -803,8 +803,7 @@ if(CMAKE_COMPILER_IS_GNUCC) # Automatically turned on when building with "-march=native". This is # explicitly turned off here as it will make floating point math give a bit # different results. This will lead to automated test failures. So disable - # this until we support it. Seems to default to off in clang and the intel - # compiler. + # this until we support it. set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off") # `maybe-uninitialized` is unreliable in release builds, but fine in debug builds. @@ -892,7 +891,7 @@ if(CMAKE_COMPILER_IS_GNUCC) # CLang is the same as GCC for now. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") + set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off") if(WITH_LINKER_MOLD AND _IS_LINKER_DEFAULT) find_program(MOLD_BIN "mold") -- 2.30.2 From 4054d767497a03cbc2e8d7ed8b689dd1d106606d Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 20 Apr 2023 10:07:49 +0200 Subject: [PATCH 46/61] Fix: Normalization with baked curves and preview range Currently when a baked curve is in the Graph Editor and normalization is enabled, it doesn't work. It even throws a warning. This patch adds the missing logic to normalize baked FCurves within a preview range. Pull Request: https://projects.blender.org/blender/blender/pulls/106890 --- source/blender/editors/animation/anim_draw.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 810914dc6cb..0b6153ba925 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -343,12 +343,20 @@ static void fcurve_scene_coord_range_get(Scene *scene, int end = fcu->totvert; if (use_preview_only) { - /* Preview frame ranges need to be converted to bezt array indices. */ - bool replace = false; - start = BKE_fcurve_bezt_binarysearch_index( - fcu->bezt, scene->r.psfra, fcu->totvert, &replace); + if (fcu->bezt) { + /* Preview frame ranges need to be converted to bezt array indices. */ + bool replace = false; + start = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, scene->r.psfra, fcu->totvert, &replace); - end = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, scene->r.pefra, fcu->totvert, &replace); + end = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, scene->r.pefra + 1, fcu->totvert, &replace); + } + else if (fcu->fpt) { + const int unclamped_start = (int)(scene->r.psfra - fcu->fpt[0].vec[0]); + start = max_ii(unclamped_start, 0); + end = min_ii(unclamped_start + (scene->r.pefra - scene->r.psfra) + 1, fcu->totvert); + } } if (fcu->bezt) { -- 2.30.2 From 60ced5283a8caf17ad2517a58027a7890af4067b Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 20 Apr 2023 10:08:39 +0200 Subject: [PATCH 47/61] Animation: make properties from motion path library overrideable The following properties were not library overrideable, but now are * Line Thickness * Color * Custom Color Checkbox Pull Request: https://projects.blender.org/blender/blender/pulls/106959 --- source/blender/makesrna/intern/rna_animviz.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 887fa662e97..66c11f2fe57 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -157,6 +157,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Color", "Custom color for motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Line width */ prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE); @@ -164,6 +165,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_range(prop, 1, 6); RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Settings */ prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE); @@ -184,6 +186,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM); RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* Draw lines between keyframes */ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE); -- 2.30.2 From fe7815e1177c39b12dc2bc740118ba05f8eb8e64 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 20 Apr 2023 10:26:26 +0200 Subject: [PATCH 48/61] Fix #106771: Selection offset in timeline when NLA track is offset The selection (box select, click select...) had an offset when selecting keys in the timeline. That was because the function to get the NLA mapping ignored the timeline. Pull Request: https://projects.blender.org/blender/blender/pulls/106904 --- source/blender/editors/animation/anim_draw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 0b6153ba925..8fd3cbe2451 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -233,7 +233,8 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale) ANIMCONT_DOPESHEET, ANIMCONT_FCURVES, ANIMCONT_NLA, - ANIMCONT_CHANNEL)) { + ANIMCONT_CHANNEL, + ANIMCONT_TIMELINE)) { /* handling depends on the type of animation-context we've got */ if (ale) { /* NLA Control Curves occur on NLA strips, -- 2.30.2 From 6d35e1c23847f3bf3f40fcbdf8e67cadc82f8cf5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 18:26:37 +1000 Subject: [PATCH 49/61] Fix missing include causing build error & invalid NULL check --- source/blender/editors/gpencil_legacy/gpencil_weight_paint.c | 2 +- source/blender/nodes/composite/nodes/node_composite_id_mask.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c index da6cdcdde14..29ad3cfabb2 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c @@ -907,7 +907,7 @@ static bool gpencil_weightpaint_brush_poll(bContext *C) } ToolSettings *ts = CTX_data_scene(C)->toolsettings; - if (!&ts->gp_weightpaint->paint.brush) { + if (!ts->gp_weightpaint->paint.brush) { CTX_wm_operator_poll_msg_set(C, "Grease Pencil has no active paint tool"); return false; } diff --git a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc index 3e536f056f4..1cf97682b2f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_id_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc @@ -16,6 +16,7 @@ #include "COM_algorithm_smaa.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" -- 2.30.2 From 0fa68d1a01ae730e4a517b82037f5d8d0291a585 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 18:27:36 +1000 Subject: [PATCH 50/61] Cleanup: format --- scripts/startup/bl_ui/properties_paint_common.py | 4 ++-- scripts/startup/bl_ui/space_view3d.py | 8 ++++---- scripts/startup/bl_ui/space_view3d_toolbar.py | 6 +++--- source/blender/editors/space_view3d/view3d_select.cc | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index 5984b325ba6..982e09d7a57 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -1414,10 +1414,10 @@ def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=Fals row = layout.row(align=True) row.prop(brush, "strength", slider=True) row.prop(brush, "use_pressure_strength", text="") - + if brush.gpencil_weight_tool in {'WEIGHT'}: layout.prop(brush, "weight", slider=True) - + gp_settings = brush.gpencil_settings layout.prop(gp_settings, "direction", expand=True, text="" if compact else "Direction") diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 36827670145..81c1fe5f159 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -414,11 +414,11 @@ class _draw_tool_settings_context_mode: return False paint = context.tool_settings.gpencil_weight_paint brush = paint.brush - + layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True) - + brush_basic_gpencil_weight_settings(layout, context, brush, compact=True) - + layout.popover("VIEW3D_PT_tools_grease_pencil_weight_options", text="Options") layout.popover("VIEW3D_PT_tools_grease_pencil_brush_weight_falloff", text="Falloff") @@ -7666,7 +7666,7 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel): settings = tool_settings.gpencil_weight_paint brush = settings.brush layout = self.layout - + # Weight settings brush_basic_gpencil_weight_settings(layout, context, brush) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index 442a6ee952d..5a9dcf85e42 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -2023,7 +2023,7 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr def draw(self, context): if self.is_popover: return - + layout = self.layout layout.use_property_split = True layout.use_property_decorate = False @@ -2055,13 +2055,13 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof class VIEW3D_PT_tools_grease_pencil_weight_options(Panel, View3DPanel, GreasePencilWeightPanel): bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} - + def draw(self, context): layout = self.layout layout.use_property_split = True layout.use_property_decorate = False tool_settings = context.scene.tool_settings - + col = layout.column() col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize") diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 3e64fdcdea5..4828ef03679 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -3665,7 +3665,8 @@ static bool do_mesh_box_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ - struct BoxSelectUserData_ForMeshEdge cb_data {}; + struct BoxSelectUserData_ForMeshEdge cb_data { + }; cb_data.data = &data; cb_data.esel = use_zbuf ? esel : nullptr; cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( -- 2.30.2 From 770b1932536cc1f9aa36722087da144a99fbd899 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 20 Apr 2023 18:27:37 +1000 Subject: [PATCH 51/61] Cleanup: use function style casts & nullptr, spelling in comments --- source/blender/blenlib/intern/path_util.c | 2 +- .../blender/editors/gpencil_legacy/gpencil_weight_paint.c | 2 +- source/blender/editors/space_view3d/view3d_gizmo_ruler.cc | 4 ++-- source/blender/editors/transform/transform_gizmo_3d.cc | 4 ++-- source/blender/editors/undo/memfile_undo.cc | 6 +++--- source/blender/geometry/intern/uv_pack.cc | 2 +- source/blender/windowmanager/intern/wm_init_exit.cc | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 96d24812063..d6648e9011d 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1379,7 +1379,7 @@ const char *BLI_path_extension_or_end(const char *filepath) { /* NOTE(@ideasman42): Skip the extension when there are no preceding non-extension characters in * the file name. This ignores extensions at the beginning of a string or directly after a slash. - * Only using trailing extension characters has the advantage that stripping the extenion + * Only using trailing extension characters has the advantage that stripping the extension * never leads to a blank string (which can't be used as a file path). * Matches Python's `os.path.splitext`. */ const char *ext = NULL; diff --git a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c index 29ad3cfabb2..c27a6073b35 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil_legacy/gpencil_weight_paint.c @@ -846,7 +846,7 @@ static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op) /* Get boolean array of vertex groups deformed by bones. */ gso->vgroup_bone_deformed = gpencil_vgroup_bone_deformed_map_get(ob, gso->vgroup_tot); if (gso->vgroup_bone_deformed != NULL) { - /* Get boolean array of locked vertext groups. */ + /* Get boolean array of locked vertex groups. */ gso->vgroup_locked = BKE_object_defgroup_lock_flags_get(ob, gso->vgroup_tot); if (gso->vgroup_locked == NULL) { gso->vgroup_locked = (bool *)MEM_callocN(sizeof(bool) * gso->vgroup_tot, __func__); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc index d4e8d6e08cb..e08c6989266 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.cc @@ -208,7 +208,7 @@ static void ruler_item_as_string( } else { BKE_unit_value_as_string( - numstr, numstr_size, (double)ruler_angle, prec, B_UNIT_ROTATION, unit, false); + numstr, numstr_size, double(ruler_angle), prec, B_UNIT_ROTATION, unit, false); } } else { @@ -220,7 +220,7 @@ static void ruler_item_as_string( else { BKE_unit_value_as_string(numstr, numstr_size, - (double)(ruler_len * unit->scale_length), + double(ruler_len * unit->scale_length), prec, B_UNIT_LENGTH, unit, diff --git a/source/blender/editors/transform/transform_gizmo_3d.cc b/source/blender/editors/transform/transform_gizmo_3d.cc index e61990732ee..594b55992ad 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.cc +++ b/source/blender/editors/transform/transform_gizmo_3d.cc @@ -1464,7 +1464,7 @@ static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx, const i case MAN_AXIS_SCALE_Z: { float end, start_co[3] = {0.0f, 0.0f, 0.0f}; - gizmo_line_range(twtype, axis_type, NULL, &end); + gizmo_line_range(twtype, axis_type, nullptr, &end); RNA_float_set(axis->ptr, "length", end); RNA_enum_set(axis->ptr, "draw_options", @@ -1797,7 +1797,7 @@ static void gizmo_refresh_from_matrix(wmGizmo *axis, copy_m4_m4(axis->matrix_basis, twmat); if (scale) { float end; - gizmo_line_range(twtype, axis_type, NULL, &end); + gizmo_line_range(twtype, axis_type, nullptr, &end); RNA_float_set(axis->ptr, "length", end * scale[aidx_norm]); } diff --git a/source/blender/editors/undo/memfile_undo.cc b/source/blender/editors/undo/memfile_undo.cc index 33f75b00a7c..0df00e5050e 100644 --- a/source/blender/editors/undo/memfile_undo.cc +++ b/source/blender/editors/undo/memfile_undo.cc @@ -243,9 +243,9 @@ static void memfile_undosys_step_decode(struct bContext *C, * modified IDs should already have other depsgraph update tags anyway. * However, for the sake of consistency, it's better to effectively use it, * since content of that ID pointer does have been modified. */ - unsigned int recalc_flags = id->recalc | ((id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) ? - ID_RECALC_COPY_ON_WRITE : - IDRecalcFlag(0)); + uint recalc_flags = id->recalc | ((id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) ? + ID_RECALC_COPY_ON_WRITE : + IDRecalcFlag(0)); /* Tag depsgraph to update data-block for changes that happened between the * current and the target state, see direct_link_id_restore_recalc(). */ if (recalc_flags != 0) { diff --git a/source/blender/geometry/intern/uv_pack.cc b/source/blender/geometry/intern/uv_pack.cc index 1e56a4acce4..22ab4473734 100644 --- a/source/blender/geometry/intern/uv_pack.cc +++ b/source/blender/geometry/intern/uv_pack.cc @@ -198,7 +198,7 @@ void PackIsland::calculate_pre_rotation_(const UVPackIsland_Params ¶ms) } const float(*source)[2] = reinterpret_cast(coords.data()); - float angle = -BLI_convexhull_aabb_fit_points_2d(source, (int)coords.size()); + float angle = -BLI_convexhull_aabb_fit_points_2d(source, int(coords.size())); if (1) { /* "Stand-up" islands. */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index 7da2a8fb963..764177fcc18 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -375,7 +375,7 @@ static bool wm_init_splash_show_on_startup_check() else { /* A less common case, if there is no user preferences, show the splash screen * so the user has the opportunity to restore settings from a previous version. */ - const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); if (cfgdir) { char userpref[FILE_MAX]; BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE); -- 2.30.2 From 7ce10ebbbf58d24766765d8742317727bc6c1164 Mon Sep 17 00:00:00 2001 From: Nikita Sirgienko Date: Thu, 20 Apr 2023 11:09:16 +0200 Subject: [PATCH 52/61] Cycles: oneAPI: Remove excess quotes in a capabilities output --- intern/cycles/device/oneapi/device_impl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp index 8fca166e665..5cb6a6222ef 100644 --- a/intern/cycles/device/oneapi/device_impl.cpp +++ b/intern/cycles/device/oneapi/device_impl.cpp @@ -866,9 +866,9 @@ char *OneapiDevice::device_capabilities() sycl::id<3> max_work_item_sizes = device.get_info>(); - WRITE_ATTR("max_work_item_sizes_dim0", ((size_t)max_work_item_sizes.get(0))) - WRITE_ATTR("max_work_item_sizes_dim1", ((size_t)max_work_item_sizes.get(1))) - WRITE_ATTR("max_work_item_sizes_dim2", ((size_t)max_work_item_sizes.get(2))) + WRITE_ATTR(max_work_item_sizes_dim0, ((size_t)max_work_item_sizes.get(0))) + WRITE_ATTR(max_work_item_sizes_dim1, ((size_t)max_work_item_sizes.get(1))) + WRITE_ATTR(max_work_item_sizes_dim2, ((size_t)max_work_item_sizes.get(2))) GET_NUM_ATTR(max_work_group_size) GET_NUM_ATTR(max_num_sub_groups) @@ -891,7 +891,7 @@ char *OneapiDevice::device_capabilities() GET_NUM_ATTR(native_vector_width_half) size_t max_clock_frequency = device.get_info(); - WRITE_ATTR("max_clock_frequency", max_clock_frequency) + WRITE_ATTR(max_clock_frequency, max_clock_frequency) GET_NUM_ATTR(address_bits) GET_NUM_ATTR(max_mem_alloc_size) @@ -900,7 +900,7 @@ char *OneapiDevice::device_capabilities() * supported so we always return false, even if device supports HW texture usage acceleration. */ bool image_support = false; - WRITE_ATTR("image_support", (size_t)image_support) + WRITE_ATTR(image_support, (size_t)image_support) GET_NUM_ATTR(max_parameter_size) GET_NUM_ATTR(mem_base_addr_align) -- 2.30.2 From 100f37af4926db872d01b1a6db850685e0557290 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Thu, 20 Apr 2023 11:21:27 +0200 Subject: [PATCH 53/61] Fix #100053: Incorrect saving asset catalogs after renaming parent item When a parent item was renamed, the `TreeView` was doing everything as expected, however `AssetCatalogService::update_catalog_path` is supposed to also update the catalog paths of all sub-catalogs [which it does -- but it does not tag sub-catalogs as having unsaved changes, resulting in wrong saving of catalogs afterwards, meaning the parent item was saved with the old name and a new item with the new name was created]. Now also tag sub-catalogs for having unsaved changes. This should also go into 3.3 LTS Pull Request: https://projects.blender.org/blender/blender/pulls/107121 --- source/blender/asset_system/intern/asset_catalog.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/asset_system/intern/asset_catalog.cc b/source/blender/asset_system/intern/asset_catalog.cc index 6fd01ab14f7..b3e476cda3f 100644 --- a/source/blender/asset_system/intern/asset_catalog.cc +++ b/source/blender/asset_system/intern/asset_catalog.cc @@ -260,6 +260,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id, } cat->path = new_path; cat->simple_name_refresh(); + this->tag_has_unsaved_changes(cat); /* TODO(Sybren): go over all assets that are assigned to this catalog, defined in the current * blend file, and update the catalog simple name stored there. */ -- 2.30.2 From 475f9a3e23fcccfcac65a34537ddadd65fe4403f Mon Sep 17 00:00:00 2001 From: William Leeson Date: Thu, 20 Apr 2023 12:26:02 +0200 Subject: [PATCH 54/61] Cycles: Break up geometry.cpp and scene.cpp file into smaller pieces Scene.cpp and Geometry.cpp are large file it can be broken up into smaller easier to handle files. This change has been broken out from #105403 to make understanding the changes easier. geometry.cpp is broken up into: 1. geometry.cpp 2. geometry_attributes.cpp 3. geometry_bvh.cpp 4. geometry_mesh.cpp scene.h & scene.cpp is broken into: 1. scene.h 2. scene.cpp 3. devicescene.h 4. devicescene.cpp Pull Request: https://projects.blender.org/blender/blender/pulls/107079 --- intern/cycles/scene/CMakeLists.txt | 5 + intern/cycles/scene/devicescene.cpp | 64 ++ intern/cycles/scene/devicescene.h | 101 ++ intern/cycles/scene/geometry.cpp | 1151 +------------------ intern/cycles/scene/geometry.h | 32 + intern/cycles/scene/geometry_attributes.cpp | 722 ++++++++++++ intern/cycles/scene/geometry_bvh.cpp | 196 ++++ intern/cycles/scene/geometry_mesh.cpp | 223 ++++ intern/cycles/scene/scene.cpp | 55 +- intern/cycles/scene/scene.h | 92 +- 10 files changed, 1389 insertions(+), 1252 deletions(-) create mode 100644 intern/cycles/scene/devicescene.cpp create mode 100644 intern/cycles/scene/devicescene.h create mode 100644 intern/cycles/scene/geometry_attributes.cpp create mode 100644 intern/cycles/scene/geometry_bvh.cpp create mode 100644 intern/cycles/scene/geometry_mesh.cpp diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt index 759a25ab7cb..3fc972da75e 100644 --- a/intern/cycles/scene/CMakeLists.txt +++ b/intern/cycles/scene/CMakeLists.txt @@ -15,8 +15,12 @@ set(SRC camera.cpp colorspace.cpp constant_fold.cpp + devicescene.cpp film.cpp geometry.cpp + geometry_attributes.cpp + geometry_bvh.cpp + geometry_mesh.cpp hair.cpp image.cpp image_oiio.cpp @@ -55,6 +59,7 @@ set(SRC_HEADERS camera.h colorspace.h constant_fold.h + devicescene.h film.h geometry.h hair.h diff --git a/intern/cycles/scene/devicescene.cpp b/intern/cycles/scene/devicescene.cpp new file mode 100644 index 00000000000..8325c4855f5 --- /dev/null +++ b/intern/cycles/scene/devicescene.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "scene/devicescene.h" +#include "device/device.h" +#include "device/memory.h" + +CCL_NAMESPACE_BEGIN + +DeviceScene::DeviceScene(Device *device) + : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), + bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), + object_node(device, "object_node", MEM_GLOBAL), + prim_type(device, "prim_type", MEM_GLOBAL), + prim_visibility(device, "prim_visibility", MEM_GLOBAL), + prim_index(device, "prim_index", MEM_GLOBAL), + prim_object(device, "prim_object", MEM_GLOBAL), + prim_time(device, "prim_time", MEM_GLOBAL), + tri_verts(device, "tri_verts", MEM_GLOBAL), + tri_shader(device, "tri_shader", MEM_GLOBAL), + tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), + tri_vindex(device, "tri_vindex", MEM_GLOBAL), + tri_patch(device, "tri_patch", MEM_GLOBAL), + tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), + curves(device, "curves", MEM_GLOBAL), + curve_keys(device, "curve_keys", MEM_GLOBAL), + curve_segments(device, "curve_segments", MEM_GLOBAL), + patches(device, "patches", MEM_GLOBAL), + points(device, "points", MEM_GLOBAL), + points_shader(device, "points_shader", MEM_GLOBAL), + objects(device, "objects", MEM_GLOBAL), + object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), + object_motion(device, "object_motion", MEM_GLOBAL), + object_flag(device, "object_flag", MEM_GLOBAL), + object_volume_step(device, "object_volume_step", MEM_GLOBAL), + object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), + camera_motion(device, "camera_motion", MEM_GLOBAL), + attributes_map(device, "attributes_map", MEM_GLOBAL), + attributes_float(device, "attributes_float", MEM_GLOBAL), + attributes_float2(device, "attributes_float2", MEM_GLOBAL), + attributes_float3(device, "attributes_float3", MEM_GLOBAL), + attributes_float4(device, "attributes_float4", MEM_GLOBAL), + attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), + light_distribution(device, "light_distribution", MEM_GLOBAL), + lights(device, "lights", MEM_GLOBAL), + light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), + light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), + light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), + light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), + light_to_tree(device, "light_to_tree", MEM_GLOBAL), + object_to_tree(device, "object_to_tree", MEM_GLOBAL), + object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), + triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), + particles(device, "particles", MEM_GLOBAL), + svm_nodes(device, "svm_nodes", MEM_GLOBAL), + shaders(device, "shaders", MEM_GLOBAL), + lookup_table(device, "lookup_table", MEM_GLOBAL), + sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), + ies_lights(device, "ies", MEM_GLOBAL) +{ + memset((void *)&data, 0, sizeof(data)); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/devicescene.h b/intern/cycles/scene/devicescene.h new file mode 100644 index 00000000000..250b3b86516 --- /dev/null +++ b/intern/cycles/scene/devicescene.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#ifndef __DEVICESCENE_H__ +#define __DEVICESCENE_H__ + +#include "device/device.h" +#include "device/memory.h" + +#include "util/types.h" +#include "util/vector.h" + +CCL_NAMESPACE_BEGIN + +class DeviceScene { + public: + /* BVH */ + device_vector bvh_nodes; + device_vector bvh_leaf_nodes; + device_vector object_node; + device_vector prim_type; + device_vector prim_visibility; + device_vector prim_index; + device_vector prim_object; + device_vector prim_time; + + /* mesh */ + device_vector tri_verts; + device_vector tri_shader; + device_vector tri_vnormal; + device_vector tri_vindex; + device_vector tri_patch; + device_vector tri_patch_uv; + + device_vector curves; + device_vector curve_keys; + device_vector curve_segments; + + device_vector patches; + + /* point-cloud */ + device_vector points; + device_vector points_shader; + + /* objects */ + device_vector objects; + device_vector object_motion_pass; + device_vector object_motion; + device_vector object_flag; + device_vector object_volume_step; + device_vector object_prim_offset; + + /* cameras */ + device_vector camera_motion; + + /* attributes */ + device_vector attributes_map; + device_vector attributes_float; + device_vector attributes_float2; + device_vector attributes_float3; + device_vector attributes_float4; + device_vector attributes_uchar4; + + /* lights */ + device_vector light_distribution; + device_vector lights; + device_vector light_background_marginal_cdf; + device_vector light_background_conditional_cdf; + + /* light tree */ + device_vector light_tree_nodes; + device_vector light_tree_emitters; + device_vector light_to_tree; + device_vector object_to_tree; + device_vector object_lookup_offset; + device_vector triangle_to_tree; + + /* particles */ + device_vector particles; + + /* shaders */ + device_vector svm_nodes; + device_vector shaders; + + /* lookup tables */ + device_vector lookup_table; + + /* integrator */ + device_vector sample_pattern_lut; + + /* IES lights */ + device_vector ies_lights; + + KernelData data; + + DeviceScene(Device *device); +}; + +CCL_NAMESPACE_END + +#endif /* __DEVICESCENE_H__ */ diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 58a9a97bf32..21d3b6a52a6 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -84,49 +84,6 @@ void Geometry::clear(bool preserve_shaders) tag_modified(); } -bool Geometry::need_attribute(Scene *scene, AttributeStandard std) -{ - if (std == ATTR_STD_NONE) - return false; - - if (scene->need_global_attribute(std)) - return true; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - if (shader->attributes.find(std)) - return true; - } - - return false; -} - -bool Geometry::need_attribute(Scene * /*scene*/, ustring name) -{ - if (name == ustring()) - return false; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - if (shader->attributes.find(name)) - return true; - } - - return false; -} - -AttributeRequestSet Geometry::needed_attributes() -{ - AttributeRequestSet result; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - result.add(shader->attributes); - } - - return result; -} - float Geometry::motion_time(int step) const { return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; @@ -182,89 +139,11 @@ bool Geometry::has_true_displacement() const return false; } -void Geometry::compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - size_t n, - size_t total) -{ - if (progress->get_cancel()) - return; - - compute_bounds(); - - const BVHLayout bvh_layout = BVHParams::best_bvh_layout( - params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - if (need_build_bvh(bvh_layout)) { - string msg = "Updating Geometry BVH "; - if (name.empty()) - msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); - else - msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); - - Object object; - - /* Ensure all visibility bits are set at the geometry level BVH. In - * the object level BVH is where actual visibility is tested. */ - object.set_is_shadow_catcher(true); - object.set_visibility(~0); - - object.set_geometry(this); - - vector geometry; - geometry.push_back(this); - vector objects; - objects.push_back(&object); - - if (bvh && !need_update_rebuild) { - progress->set_status(msg, "Refitting BVH"); - - bvh->replace_geometry(geometry, objects); - - device->build_bvh(bvh, *progress, true); - } - else { - progress->set_status(msg, "Building BVH"); - - BVHParams bparams; - bparams.use_spatial_split = params->use_bvh_spatial_split; - bparams.use_compact_structure = params->use_bvh_compact_structure; - bparams.bvh_layout = bvh_layout; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = params->num_bvh_time_steps; - bparams.num_motion_curve_steps = params->num_bvh_time_steps; - bparams.num_motion_point_steps = params->num_bvh_time_steps; - bparams.bvh_type = params->bvh_type; - bparams.curve_subdivisions = params->curve_subdivisions(); - - delete bvh; - bvh = BVH::create(bparams, geometry, objects, device); - MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); - } - } - - need_update_rebuild = false; - need_update_bvh_for_offset = false; -} - bool Geometry::has_motion_blur() const { return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)); } -bool Geometry::has_voxel_attributes() const -{ - foreach (const Attribute &attr, attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - return true; - } - } - - return false; -} - void Geometry::tag_update(Scene *scene, bool rebuild) { if (rebuild) { @@ -328,637 +207,62 @@ void GeometryManager::update_osl_globals(Device *device, Scene *scene) #endif } -/* Generate a normal attribute map entry from an attribute descriptor. */ -static void emit_attribute_map_entry(AttributeMap *attr_map, - size_t index, - uint64_t id, - TypeDesc type, - const AttributeDescriptor &desc) +static void update_device_flags_attribute(uint32_t &device_update_flags, + const AttributeSet &attributes) { - attr_map[index].id = id; - attr_map[index].element = desc.element; - attr_map[index].offset = as_uint(desc.offset); + foreach (const Attribute &attr, attributes.attributes) { + if (!attr.modified) { + continue; + } - if (type == TypeDesc::TypeFloat) - attr_map[index].type = NODE_ATTR_FLOAT; - else if (type == TypeDesc::TypeMatrix) - attr_map[index].type = NODE_ATTR_MATRIX; - else if (type == TypeFloat2) - attr_map[index].type = NODE_ATTR_FLOAT2; - else if (type == TypeFloat4) - attr_map[index].type = NODE_ATTR_FLOAT4; - else if (type == TypeRGBA) - attr_map[index].type = NODE_ATTR_RGBA; - else - attr_map[index].type = NODE_ATTR_FLOAT3; + AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - attr_map[index].flags = desc.flags; -} - -/* Generate an attribute map end marker, optionally including a link to another map. - * Links are used to connect object attribute maps to mesh attribute maps. */ -static void emit_attribute_map_terminator(AttributeMap *attr_map, - size_t index, - bool chain, - uint chain_link) -{ - for (int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index + j].id = ATTR_STD_NONE; - attr_map[index + j].element = chain; /* link is valid flag */ - attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ - attr_map[index + j].type = 0; - attr_map[index + j].flags = 0; - } -} - -/* Generate all necessary attribute map entries from the attribute request. */ -static void emit_attribute_mapping( - AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) -{ - emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->get_num_subd_faces()) { - emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + switch (kernel_type) { + case AttrKernelDataType::FLOAT: { + device_update_flags |= ATTR_FLOAT_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT2: { + device_update_flags |= ATTR_FLOAT2_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT3: { + device_update_flags |= ATTR_FLOAT3_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT4: { + device_update_flags |= ATTR_FLOAT4_MODIFIED; + break; + } + case AttrKernelDataType::UCHAR4: { + device_update_flags |= ATTR_UCHAR4_MODIFIED; + break; + } + case AttrKernelDataType::NUM: { + break; + } } } } -void GeometryManager::update_svm_attributes(Device *, - DeviceScene *dscene, - Scene *scene, - vector &geom_attributes, - vector &object_attributes) +static void update_attribute_realloc_flags(uint32_t &device_update_flags, + const AttributeSet &attributes) { - /* for SVM, the attributes_map table is used to lookup the offset of an - * attribute, based on a unique shader attribute id. */ - - /* compute array stride */ - size_t attr_map_size = 0; - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - geom->attr_map_offset = attr_map_size; - -#ifdef WITH_OSL - size_t attr_count = 0; - foreach (AttributeRequest &req, geom_attributes[i].requests) { - if (req.std != ATTR_STD_NONE && - scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) - attr_count += 2; - else - attr_count += 1; - } -#else - const size_t attr_count = geom_attributes[i].size(); -#endif - - attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES; + if (attributes.modified(AttrKernelDataType::FLOAT)) { + device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - - /* only allocate a table for the object if it actually has attributes */ - if (object_attributes[i].size() == 0) { - object->attr_map_offset = 0; - } - else { - object->attr_map_offset = attr_map_size; - attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES; - } + if (attributes.modified(AttrKernelDataType::FLOAT2)) { + device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; } - - if (attr_map_size == 0) - return; - - if (!dscene->attributes_map.need_realloc()) { - return; + if (attributes.modified(AttrKernelDataType::FLOAT3)) { + device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; } - - /* create attribute map */ - AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); - memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* set geometry attributes */ - size_t index = geom->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t id; - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - emit_attribute_mapping(attr_map, index, id, req, geom); - index += ATTR_PRIM_TYPES; - -#ifdef WITH_OSL - /* Some standard attributes are explicitly referenced via their standard ID, so add those - * again in case they were added under a different attribute ID. */ - if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { - emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); - index += ATTR_PRIM_TYPES; - } -#endif - } - - emit_attribute_map_terminator(attr_map, index, false, 0); + if (attributes.modified(AttrKernelDataType::FLOAT4)) { + device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - AttributeRequestSet &attributes = object_attributes[i]; - - /* set object attributes */ - if (attributes.size() > 0) { - size_t index = object->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t id; - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - emit_attribute_mapping(attr_map, index, id, req, object->geometry); - index += ATTR_PRIM_TYPES; - } - - emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); - } + if (attributes.modified(AttrKernelDataType::UCHAR4)) { + device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; } - - /* copy to device */ - dscene->attributes_map.copy_to_device(); -} - -static void update_attribute_element_size(Geometry *geom, - Attribute *mattr, - AttributePrimitive prim, - size_t *attr_float_size, - size_t *attr_float2_size, - size_t *attr_float3_size, - size_t *attr_float4_size, - size_t *attr_uchar4_size) -{ - if (mattr) { - size_t size = mattr->element_size(geom, prim); - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* pass */ - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - *attr_uchar4_size += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - *attr_float_size += size; - } - else if (mattr->type == TypeFloat2) { - *attr_float2_size += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - *attr_float4_size += size * 4; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - *attr_float4_size += size; - } - else { - *attr_float3_size += size; - } - } -} - -void GeometryManager::update_attribute_element_offset(Geometry *geom, - device_vector &attr_float, - size_t &attr_float_offset, - device_vector &attr_float2, - size_t &attr_float2_offset, - device_vector &attr_float3, - size_t &attr_float3_offset, - device_vector &attr_float4, - size_t &attr_float4_offset, - device_vector &attr_uchar4, - size_t &attr_uchar4_offset, - Attribute *mattr, - AttributePrimitive prim, - TypeDesc &type, - AttributeDescriptor &desc) -{ - if (mattr) { - /* store element and type */ - desc.element = mattr->element; - desc.flags = mattr->flags; - type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(geom, prim); - - AttributeElement &element = desc.element; - int &offset = desc.offset; - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* store slot in offset value */ - ImageHandle &handle = mattr->data_voxel(); - offset = handle.svm_slot(); - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4_offset; - - assert(attr_uchar4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_uchar4[offset + k] = data[k]; - } - attr_uchar4.tag_modified(); - } - attr_uchar4_offset += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - offset = attr_float_offset; - - assert(attr_float.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float[offset + k] = data[k]; - } - attr_float.tag_modified(); - } - attr_float_offset += size; - } - else if (mattr->type == TypeFloat2) { - float2 *data = mattr->data_float2(); - offset = attr_float2_offset; - - assert(attr_float2.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float2[offset + k] = data[k]; - } - attr_float2.tag_modified(); - } - attr_float2_offset += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - Transform *tfm = mattr->data_transform(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size * 3); - if (mattr->modified) { - for (size_t k = 0; k < size * 3; k++) { - attr_float4[offset + k] = (&tfm->x)[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size * 3; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - float4 *data = mattr->data_float4(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float4[offset + k] = data[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size; - } - else { - float3 *data = mattr->data_float3(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float3[offset + k] = data[k]; - } - attr_float3.tag_modified(); - } - attr_float3_offset += size; - } - - /* mesh vertex/curve index is global, not per object, so we sneak - * a correction for that in here */ - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && - desc.flags & ATTR_SUBDIVIDED) { - /* Indices for subdivided attributes are retrieved - * from patch table so no need for correction here. */ - } - else if (element == ATTR_ELEMENT_VERTEX) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_FACE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= mesh->prim_offset; - else - offset -= mesh->face_offset; - } - else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= 3 * mesh->prim_offset; - else - offset -= mesh->corner_offset; - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - if (element == ATTR_ELEMENT_CURVE) - offset -= hair->prim_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY) - offset -= hair->curve_key_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) - offset -= hair->curve_key_offset; - } - else if (geom->is_pointcloud()) { - if (element == ATTR_ELEMENT_VERTEX) - offset -= geom->prim_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= geom->prim_offset; - } - } - else { - /* attribute not found */ - desc.element = ATTR_ELEMENT_NONE; - desc.offset = 0; - } -} - -void GeometryManager::device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - progress.set_status("Updating Mesh", "Computing attributes"); - - /* gather per mesh requested attributes. as meshes may have multiple - * shaders assigned, this merges the requested attributes that have - * been set per shader by the shader manager */ - vector geom_attributes(scene->geometry.size()); - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - - geom->index = i; - scene->need_global_attributes(geom_attributes[i]); - - foreach (Node *node, geom->get_used_shaders()) { - Shader *shader = static_cast(node); - geom_attributes[i].add(shader->attributes); - } - - if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { - geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); - } - } - - /* convert object attributes to use the same data structures as geometry ones */ - vector object_attributes(scene->objects.size()); - vector object_attribute_values; - - object_attribute_values.reserve(scene->objects.size()); - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - Geometry *geom = object->geometry; - size_t geom_idx = geom->index; - - assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom); - - object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY)); - - AttributeRequestSet &geom_requests = geom_attributes[geom_idx]; - AttributeRequestSet &attributes = object_attributes[i]; - AttributeSet &values = object_attribute_values[i]; - - for (size_t j = 0; j < object->attributes.size(); j++) { - ParamValue ¶m = object->attributes[j]; - - /* add attributes that are requested and not already handled by the mesh */ - if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) { - attributes.add(param.name()); - - Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT); - assert(param.datasize() == attr->buffer.size()); - memcpy(attr->buffer.data(), param.data(), param.datasize()); - } - } - } - - /* mesh attribute are stored in a single array per data type. here we fill - * those arrays, and set the offset and element type to create attribute - * maps next */ - - /* Pre-allocate attributes to avoid arrays re-allocation which would - * take 2x of overall attribute memory usage. - */ - size_t attr_float_size = 0; - size_t attr_float2_size = 0; - size_t attr_float3_size = 0; - size_t attr_float4_size = 0; - size_t attr_uchar4_size = 0; - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - update_attribute_element_size(geom, - attr, - ATTR_PRIM_GEOMETRY, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - update_attribute_element_size(mesh, - subd_attr, - ATTR_PRIM_SUBD, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - } - } - } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - - foreach (Attribute &attr, object_attribute_values[i].attributes) { - update_attribute_element_size(object->geometry, - &attr, - ATTR_PRIM_GEOMETRY, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - } - } - - dscene->attributes_float.alloc(attr_float_size); - dscene->attributes_float2.alloc(attr_float2_size); - dscene->attributes_float3.alloc(attr_float3_size); - dscene->attributes_float4.alloc(attr_float4_size); - dscene->attributes_uchar4.alloc(attr_uchar4_size); - - /* The order of those flags needs to match that of AttrKernelDataType. */ - const bool attributes_need_realloc[AttrKernelDataType::NUM] = { - dscene->attributes_float.need_realloc(), - dscene->attributes_float2.need_realloc(), - dscene->attributes_float3.need_realloc(), - dscene->attributes_float4.need_realloc(), - dscene->attributes_uchar4.need_realloc(), - }; - - size_t attr_float_offset = 0; - size_t attr_float2_offset = 0; - size_t attr_float3_offset = 0; - size_t attr_float4_offset = 0; - size_t attr_uchar4_offset = 0; - - /* Fill in attributes. */ - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - if (attr) { - /* force a copy if we need to reallocate all the data */ - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - update_attribute_element_offset(geom, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - attr, - ATTR_PRIM_GEOMETRY, - req.type, - req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - if (subd_attr) { - /* force a copy if we need to reallocate all the data */ - subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; - } - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - subd_attr, - ATTR_PRIM_SUBD, - req.subd_type, - req.subd_desc); - } - - if (progress.get_cancel()) - return; - } - } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - AttributeRequestSet &attributes = object_attributes[i]; - AttributeSet &values = object_attribute_values[i]; - - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = values.find(req); - - if (attr) { - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - update_attribute_element_offset(object->geometry, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - attr, - ATTR_PRIM_GEOMETRY, - req.type, - req.desc); - - /* object attributes don't care about subdivision */ - req.subd_type = req.type; - req.subd_desc = req.desc; - - if (progress.get_cancel()) - return; - } - } - - /* create attribute lookup maps */ - if (scene->shader_manager->use_osl()) - update_osl_globals(device, scene); - - update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); - - if (progress.get_cancel()) - return; - - /* copy to device */ - progress.set_status("Updating Mesh", "Copying Attributes to device"); - - dscene->attributes_float.copy_to_device_if_modified(); - dscene->attributes_float2.copy_to_device_if_modified(); - dscene->attributes_float3.copy_to_device_if_modified(); - dscene->attributes_float4.copy_to_device_if_modified(); - dscene->attributes_uchar4.copy_to_device_if_modified(); - - if (progress.get_cancel()) - return; - - /* After mesh attributes and patch tables have been copied to device memory, - * we need to update offsets in the objects. */ - scene->object_manager->device_update_geom_offsets(device, dscene, scene); } void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) @@ -1040,375 +344,6 @@ void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) } } -void GeometryManager::device_update_mesh(Device *, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* Count. */ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - size_t curve_segment_size = 0; - - size_t point_size = 0; - - size_t patch_size = 0; - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - if (mesh->get_num_subd_faces()) { - Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if (mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - curve_key_size += hair->get_curve_keys().size(); - curve_size += hair->num_curves(); - curve_segment_size += hair->num_segments(); - } - else if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - point_size += pointcloud->num_points(); - } - } - - /* Fill in all the arrays. */ - if (tri_size != 0) { - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); - - packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); - uint *tri_shader = dscene->tri_shader.alloc(tri_size); - packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); - packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); - uint *tri_patch = dscene->tri_patch.alloc(tri_size); - float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); - - const bool copy_all_data = dscene->tri_shader.need_realloc() || - dscene->tri_vindex.need_realloc() || - dscene->tri_vnormal.need_realloc() || - dscene->tri_patch.need_realloc() || - dscene->tri_patch_uv.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - if (mesh->shader_is_modified() || mesh->smooth_is_modified() || - mesh->triangles_is_modified() || copy_all_data) { - mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); - } - - if (mesh->verts_is_modified() || copy_all_data) { - mesh->pack_normals(&vnormal[mesh->vert_offset]); - } - - if (mesh->verts_is_modified() || mesh->triangles_is_modified() || - mesh->vert_patch_uv_is_modified() || copy_all_data) { - mesh->pack_verts(&tri_verts[mesh->vert_offset], - &tri_vindex[mesh->prim_offset], - &tri_patch[mesh->prim_offset], - &tri_patch_uv[mesh->vert_offset]); - } - - if (progress.get_cancel()) - return; - } - } - - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); - - dscene->tri_verts.copy_to_device_if_modified(); - dscene->tri_shader.copy_to_device_if_modified(); - dscene->tri_vnormal.copy_to_device_if_modified(); - dscene->tri_vindex.copy_to_device_if_modified(); - dscene->tri_patch.copy_to_device_if_modified(); - dscene->tri_patch_uv.copy_to_device_if_modified(); - } - - if (curve_segment_size != 0) { - progress.set_status("Updating Mesh", "Copying Curves to device"); - - float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); - KernelCurve *curves = dscene->curves.alloc(curve_size); - KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); - - const bool copy_all_data = dscene->curve_keys.need_realloc() || - dscene->curves.need_realloc() || - dscene->curve_segments.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - bool curve_keys_co_modified = hair->curve_radius_is_modified() || - hair->curve_keys_is_modified(); - bool curve_data_modified = hair->curve_shader_is_modified() || - hair->curve_first_key_is_modified(); - - if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { - continue; - } - - hair->pack_curves(scene, - &curve_keys[hair->curve_key_offset], - &curves[hair->prim_offset], - &curve_segments[hair->curve_segment_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->curve_keys.copy_to_device_if_modified(); - dscene->curves.copy_to_device_if_modified(); - dscene->curve_segments.copy_to_device_if_modified(); - } - - if (point_size != 0) { - progress.set_status("Updating Mesh", "Copying Point clouds to device"); - - float4 *points = dscene->points.alloc(point_size); - uint *points_shader = dscene->points_shader.alloc(point_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - pointcloud->pack( - scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->points.copy_to_device(); - dscene->points_shader.copy_to_device(); - } - - if (patch_size != 0 && dscene->patches.need_realloc()) { - progress.set_status("Updating Mesh", "Copying Patches to device"); - - uint *patch_data = dscene->patches.alloc(patch_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - mesh->pack_patches(&patch_data[mesh->patch_offset]); - - if (mesh->patch_table) { - mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], - mesh->patch_table_offset); - } - - if (progress.get_cancel()) - return; - } - } - - dscene->patches.copy_to_device(); - } -} - -void GeometryManager::device_update_bvh(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* bvh build */ - progress.set_status("Updating Scene BVH", "Building"); - - BVHParams bparams; - bparams.top_level = true; - bparams.bvh_layout = BVHParams::best_bvh_layout( - scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; - bparams.bvh_type = scene->params.bvh_type; - bparams.curve_subdivisions = scene->params.curve_subdivisions(); - - VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; - - const bool can_refit = scene->bvh != nullptr && - (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || - bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); - - BVH *bvh = scene->bvh; - if (!scene->bvh) { - bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); - } - - device->build_bvh(bvh, progress, can_refit); - - if (progress.get_cancel()) { - return; - } - - const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); - - PackedBVH pack; - if (has_bvh2_layout) { - pack = std::move(static_cast(bvh)->pack); - } - else { - pack.root_index = -1; - } - - /* copy to device */ - progress.set_status("Updating Scene BVH", "Copying BVH to device"); - - /* When using BVH2, we always have to copy/update the data as its layout is dependent on the - * BVH's leaf nodes which may be different when the objects or vertices move. */ - - if (pack.nodes.size()) { - dscene->bvh_nodes.steal_data(pack.nodes); - dscene->bvh_nodes.copy_to_device(); - } - if (pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); - dscene->bvh_leaf_nodes.copy_to_device(); - } - if (pack.object_node.size()) { - dscene->object_node.steal_data(pack.object_node); - dscene->object_node.copy_to_device(); - } - if (pack.prim_type.size()) { - dscene->prim_type.steal_data(pack.prim_type); - dscene->prim_type.copy_to_device(); - } - if (pack.prim_visibility.size()) { - dscene->prim_visibility.steal_data(pack.prim_visibility); - dscene->prim_visibility.copy_to_device(); - } - if (pack.prim_index.size()) { - dscene->prim_index.steal_data(pack.prim_index); - dscene->prim_index.copy_to_device(); - } - if (pack.prim_object.size()) { - dscene->prim_object.steal_data(pack.prim_object); - dscene->prim_object.copy_to_device(); - } - if (pack.prim_time.size()) { - dscene->prim_time.steal_data(pack.prim_time); - dscene->prim_time.copy_to_device(); - } - - dscene->data.bvh.root = pack.root_index; - dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); - dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); - /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ - dscene->data.device_bvh = 0; -} - -/* Set of flags used to help determining what data has been modified or needs reallocation, so we - * can decide which device data to free or update. */ -enum { - DEVICE_CURVE_DATA_MODIFIED = (1 << 0), - DEVICE_MESH_DATA_MODIFIED = (1 << 1), - DEVICE_POINT_DATA_MODIFIED = (1 << 2), - - ATTR_FLOAT_MODIFIED = (1 << 3), - ATTR_FLOAT2_MODIFIED = (1 << 4), - ATTR_FLOAT3_MODIFIED = (1 << 5), - ATTR_FLOAT4_MODIFIED = (1 << 6), - ATTR_UCHAR4_MODIFIED = (1 << 7), - - CURVE_DATA_NEED_REALLOC = (1 << 8), - MESH_DATA_NEED_REALLOC = (1 << 9), - POINT_DATA_NEED_REALLOC = (1 << 10), - - ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), - ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), - - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), - - ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | - ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | - ATTR_UCHAR4_NEEDS_REALLOC), - DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), -}; - -static void update_device_flags_attribute(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - foreach (const Attribute &attr, attributes.attributes) { - if (!attr.modified) { - continue; - } - - AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - - switch (kernel_type) { - case AttrKernelDataType::FLOAT: { - device_update_flags |= ATTR_FLOAT_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT2: { - device_update_flags |= ATTR_FLOAT2_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT3: { - device_update_flags |= ATTR_FLOAT3_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT4: { - device_update_flags |= ATTR_FLOAT4_MODIFIED; - break; - } - case AttrKernelDataType::UCHAR4: { - device_update_flags |= ATTR_UCHAR4_MODIFIED; - break; - } - case AttrKernelDataType::NUM: { - break; - } - } - } -} - -static void update_attribute_realloc_flags(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - if (attributes.modified(AttrKernelDataType::FLOAT)) { - device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT2)) { - device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT3)) { - device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT4)) { - device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::UCHAR4)) { - device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; - } -} - void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) { if (!need_update() && !need_flags_update) { diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 8a1bdc33a6f..335e0859965 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -30,6 +30,38 @@ class Shader; class Volume; struct PackedBVH; +/* Set of flags used to help determining what data has been modified or needs reallocation, so we + * can decide which device data to free or update. */ +enum { + DEVICE_CURVE_DATA_MODIFIED = (1 << 0), + DEVICE_MESH_DATA_MODIFIED = (1 << 1), + DEVICE_POINT_DATA_MODIFIED = (1 << 2), + + ATTR_FLOAT_MODIFIED = (1 << 3), + ATTR_FLOAT2_MODIFIED = (1 << 4), + ATTR_FLOAT3_MODIFIED = (1 << 5), + ATTR_FLOAT4_MODIFIED = (1 << 6), + ATTR_UCHAR4_MODIFIED = (1 << 7), + + CURVE_DATA_NEED_REALLOC = (1 << 8), + MESH_DATA_NEED_REALLOC = (1 << 9), + POINT_DATA_NEED_REALLOC = (1 << 10), + + ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), + + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), + + ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | + ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | + ATTR_UCHAR4_NEEDS_REALLOC), + DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), +}; + /* Geometry * * Base class for geometric types like Mesh and Hair. */ diff --git a/intern/cycles/scene/geometry_attributes.cpp b/intern/cycles/scene/geometry_attributes.cpp new file mode 100644 index 00000000000..c8f2d4a6e28 --- /dev/null +++ b/intern/cycles/scene/geometry_attributes.cpp @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +bool Geometry::need_attribute(Scene *scene, AttributeStandard std) +{ + if (std == ATTR_STD_NONE) + return false; + + if (scene->need_global_attribute(std)) + return true; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + if (shader->attributes.find(std)) + return true; + } + + return false; +} + +bool Geometry::need_attribute(Scene * /*scene*/, ustring name) +{ + if (name == ustring()) + return false; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + if (shader->attributes.find(name)) + return true; + } + + return false; +} + +AttributeRequestSet Geometry::needed_attributes() +{ + AttributeRequestSet result; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + result.add(shader->attributes); + } + + return result; +} + +bool Geometry::has_voxel_attributes() const +{ + foreach (const Attribute &attr, attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + return true; + } + } + + return false; +} + +/* Generate a normal attribute map entry from an attribute descriptor. */ +static void emit_attribute_map_entry(AttributeMap *attr_map, + size_t index, + uint64_t id, + TypeDesc type, + const AttributeDescriptor &desc) +{ + attr_map[index].id = id; + attr_map[index].element = desc.element; + attr_map[index].offset = as_uint(desc.offset); + + if (type == TypeDesc::TypeFloat) + attr_map[index].type = NODE_ATTR_FLOAT; + else if (type == TypeDesc::TypeMatrix) + attr_map[index].type = NODE_ATTR_MATRIX; + else if (type == TypeFloat2) + attr_map[index].type = NODE_ATTR_FLOAT2; + else if (type == TypeFloat4) + attr_map[index].type = NODE_ATTR_FLOAT4; + else if (type == TypeRGBA) + attr_map[index].type = NODE_ATTR_RGBA; + else + attr_map[index].type = NODE_ATTR_FLOAT3; + + attr_map[index].flags = desc.flags; +} + +/* Generate an attribute map end marker, optionally including a link to another map. + * Links are used to connect object attribute maps to mesh attribute maps. */ +static void emit_attribute_map_terminator(AttributeMap *attr_map, + size_t index, + bool chain, + uint chain_link) +{ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index + j].id = ATTR_STD_NONE; + attr_map[index + j].element = chain; /* link is valid flag */ + attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ + attr_map[index + j].type = 0; + attr_map[index + j].flags = 0; + } +} + +/* Generate all necessary attribute map entries from the attribute request. */ +static void emit_attribute_mapping( + AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) +{ + emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + if (mesh->get_num_subd_faces()) { + emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + } + } +} + +void GeometryManager::update_svm_attributes(Device *, + DeviceScene *dscene, + Scene *scene, + vector &geom_attributes, + vector &object_attributes) +{ + /* for SVM, the attributes_map table is used to lookup the offset of an + * attribute, based on a unique shader attribute id. */ + + /* compute array stride */ + size_t attr_map_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + geom->attr_map_offset = attr_map_size; + +#ifdef WITH_OSL + size_t attr_count = 0; + foreach (AttributeRequest &req, geom_attributes[i].requests) { + if (req.std != ATTR_STD_NONE && + scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) + attr_count += 2; + else + attr_count += 1; + } +#else + const size_t attr_count = geom_attributes[i].size(); +#endif + + attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES; + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + /* only allocate a table for the object if it actually has attributes */ + if (object_attributes[i].size() == 0) { + object->attr_map_offset = 0; + } + else { + object->attr_map_offset = attr_map_size; + attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES; + } + } + + if (attr_map_size == 0) + return; + + if (!dscene->attributes_map.need_realloc()) { + return; + } + + /* create attribute map */ + AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); + memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* set geometry attributes */ + size_t index = geom->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t id; + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + emit_attribute_mapping(attr_map, index, id, req, geom); + index += ATTR_PRIM_TYPES; + +#ifdef WITH_OSL + /* Some standard attributes are explicitly referenced via their standard ID, so add those + * again in case they were added under a different attribute ID. */ + if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { + emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); + index += ATTR_PRIM_TYPES; + } +#endif + } + + emit_attribute_map_terminator(attr_map, index, false, 0); + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + + /* set object attributes */ + if (attributes.size() > 0) { + size_t index = object->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t id; + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + emit_attribute_mapping(attr_map, index, id, req, object->geometry); + index += ATTR_PRIM_TYPES; + } + + emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); + } + } + + /* copy to device */ + dscene->attributes_map.copy_to_device(); +} + +void GeometryManager::update_attribute_element_offset(Geometry *geom, + device_vector &attr_float, + size_t &attr_float_offset, + device_vector &attr_float2, + size_t &attr_float2_offset, + device_vector &attr_float3, + size_t &attr_float3_offset, + device_vector &attr_float4, + size_t &attr_float4_offset, + device_vector &attr_uchar4, + size_t &attr_uchar4_offset, + Attribute *mattr, + AttributePrimitive prim, + TypeDesc &type, + AttributeDescriptor &desc) +{ + if (mattr) { + /* store element and type */ + desc.element = mattr->element; + desc.flags = mattr->flags; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size(geom, prim); + + AttributeElement &element = desc.element; + int &offset = desc.offset; + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + ImageHandle &handle = mattr->data_voxel(); + offset = handle.svm_slot(); + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + uchar4 *data = mattr->data_uchar4(); + offset = attr_uchar4_offset; + + assert(attr_uchar4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } + attr_uchar4.tag_modified(); + } + attr_uchar4_offset += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float_offset; + + assert(attr_float.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } + attr_float.tag_modified(); + } + attr_float_offset += size; + } + else if (mattr->type == TypeFloat2) { + float2 *data = mattr->data_float2(); + offset = attr_float2_offset; + + assert(attr_float2.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } + attr_float2.tag_modified(); + } + attr_float2_offset += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + Transform *tfm = mattr->data_transform(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size * 3); + if (mattr->modified) { + for (size_t k = 0; k < size * 3; k++) { + attr_float4[offset + k] = (&tfm->x)[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size * 3; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + float4 *data = mattr->data_float4(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float4[offset + k] = data[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size; + } + else { + float3 *data = mattr->data_float3(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } + attr_float3.tag_modified(); + } + attr_float3_offset += size; + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && + desc.flags & ATTR_SUBDIVIDED) { + /* Indices for subdivided attributes are retrieved + * from patch table so no need for correction here. */ + } + else if (element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_FACE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= mesh->prim_offset; + else + offset -= mesh->face_offset; + } + else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= 3 * mesh->prim_offset; + else + offset -= mesh->corner_offset; + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + if (element == ATTR_ELEMENT_CURVE) + offset -= hair->prim_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY) + offset -= hair->curve_key_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) + offset -= hair->curve_key_offset; + } + else if (geom->is_pointcloud()) { + if (element == ATTR_ELEMENT_VERTEX) + offset -= geom->prim_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= geom->prim_offset; + } + } + else { + /* attribute not found */ + desc.element = ATTR_ELEMENT_NONE; + desc.offset = 0; + } +} + +static void update_attribute_element_size(Geometry *geom, + Attribute *mattr, + AttributePrimitive prim, + size_t *attr_float_size, + size_t *attr_float2_size, + size_t *attr_float3_size, + size_t *attr_float4_size, + size_t *attr_uchar4_size) +{ + if (mattr) { + size_t size = mattr->element_size(geom, prim); + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if (mattr->type == TypeFloat2) { + *attr_float2_size += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + *attr_float4_size += size * 4; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + *attr_float4_size += size; + } + else { + *attr_float3_size += size; + } + } +} + +void GeometryManager::device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Mesh", "Computing attributes"); + + /* gather per mesh requested attributes. as meshes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector geom_attributes(scene->geometry.size()); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + + geom->index = i; + scene->need_global_attributes(geom_attributes[i]); + + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast(node); + geom_attributes[i].add(shader->attributes); + } + + if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { + geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); + } + } + + /* convert object attributes to use the same data structures as geometry ones */ + vector object_attributes(scene->objects.size()); + vector object_attribute_values; + + object_attribute_values.reserve(scene->objects.size()); + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + Geometry *geom = object->geometry; + size_t geom_idx = geom->index; + + assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom); + + object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY)); + + AttributeRequestSet &geom_requests = geom_attributes[geom_idx]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + for (size_t j = 0; j < object->attributes.size(); j++) { + ParamValue ¶m = object->attributes[j]; + + /* add attributes that are requested and not already handled by the mesh */ + if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) { + attributes.add(param.name()); + + Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT); + assert(param.datasize() == attr->buffer.size()); + memcpy(attr->buffer.data(), param.data(), param.datasize()); + } + } + } + + /* mesh attribute are stored in a single array per data type. here we fill + * those arrays, and set the offset and element type to create attribute + * maps next */ + + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float2_size = 0; + size_t attr_float3_size = 0; + size_t attr_float4_size = 0; + size_t attr_uchar4_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + update_attribute_element_size(geom, + attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + update_attribute_element_size(mesh, + subd_attr, + ATTR_PRIM_SUBD, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + } + } + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + foreach (Attribute &attr, object_attribute_values[i].attributes) { + update_attribute_element_size(object->geometry, + &attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + } + } + + dscene->attributes_float.alloc(attr_float_size); + dscene->attributes_float2.alloc(attr_float2_size); + dscene->attributes_float3.alloc(attr_float3_size); + dscene->attributes_float4.alloc(attr_float4_size); + dscene->attributes_uchar4.alloc(attr_uchar4_size); + + /* The order of those flags needs to match that of AttrKernelDataType. */ + const bool attributes_need_realloc[AttrKernelDataType::NUM] = { + dscene->attributes_float.need_realloc(), + dscene->attributes_float2.need_realloc(), + dscene->attributes_float3.need_realloc(), + dscene->attributes_float4.need_realloc(), + dscene->attributes_uchar4.need_realloc(), + }; + + size_t attr_float_offset = 0; + size_t attr_float2_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_float4_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + if (attr) { + /* force a copy if we need to reallocate all the data */ + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + update_attribute_element_offset(geom, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + if (subd_attr) { + /* force a copy if we need to reallocate all the data */ + subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; + } + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + subd_attr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_desc); + } + + if (progress.get_cancel()) + return; + } + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = values.find(req); + + if (attr) { + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + update_attribute_element_offset(object->geometry, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + /* object attributes don't care about subdivision */ + req.subd_type = req.type; + req.subd_desc = req.desc; + + if (progress.get_cancel()) + return; + } + } + + /* create attribute lookup maps */ + if (scene->shader_manager->use_osl()) + update_osl_globals(device, scene); + + update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); + + if (progress.get_cancel()) + return; + + /* copy to device */ + progress.set_status("Updating Mesh", "Copying Attributes to device"); + + dscene->attributes_float.copy_to_device_if_modified(); + dscene->attributes_float2.copy_to_device_if_modified(); + dscene->attributes_float3.copy_to_device_if_modified(); + dscene->attributes_float4.copy_to_device_if_modified(); + dscene->attributes_uchar4.copy_to_device_if_modified(); + + if (progress.get_cancel()) + return; + + /* After mesh attributes and patch tables have been copied to device memory, + * we need to update offsets in the objects. */ + scene->object_manager->device_update_geom_offsets(device, dscene, scene); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_bvh.cpp b/intern/cycles/scene/geometry_bvh.cpp new file mode 100644 index 00000000000..9785d1a867a --- /dev/null +++ b/intern/cycles/scene/geometry_bvh.cpp @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void Geometry::compute_bvh(Device *device, + DeviceScene *dscene, + SceneParams *params, + Progress *progress, + size_t n, + size_t total) +{ + if (progress->get_cancel()) + return; + + compute_bounds(); + + const BVHLayout bvh_layout = BVHParams::best_bvh_layout( + params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + if (need_build_bvh(bvh_layout)) { + string msg = "Updating Geometry BVH "; + if (name.empty()) + msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); + else + msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); + + Object object; + + /* Ensure all visibility bits are set at the geometry level BVH. In + * the object level BVH is where actual visibility is tested. */ + object.set_is_shadow_catcher(true); + object.set_visibility(~0); + + object.set_geometry(this); + + vector geometry; + geometry.push_back(this); + vector objects; + objects.push_back(&object); + + if (bvh && !need_update_rebuild) { + progress->set_status(msg, "Refitting BVH"); + + bvh->replace_geometry(geometry, objects); + + device->build_bvh(bvh, *progress, true); + } + else { + progress->set_status(msg, "Building BVH"); + + BVHParams bparams; + bparams.use_spatial_split = params->use_bvh_spatial_split; + bparams.use_compact_structure = params->use_bvh_compact_structure; + bparams.bvh_layout = bvh_layout; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.num_motion_point_steps = params->num_bvh_time_steps; + bparams.bvh_type = params->bvh_type; + bparams.curve_subdivisions = params->curve_subdivisions(); + + delete bvh; + bvh = BVH::create(bparams, geometry, objects, device); + MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); + } + } + + need_update_rebuild = false; + need_update_bvh_for_offset = false; +} + +void GeometryManager::device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* bvh build */ + progress.set_status("Updating Scene BVH", "Building"); + + BVHParams bparams; + bparams.top_level = true; + bparams.bvh_layout = BVHParams::best_bvh_layout( + scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; + bparams.bvh_type = scene->params.bvh_type; + bparams.curve_subdivisions = scene->params.curve_subdivisions(); + + VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; + + const bool can_refit = scene->bvh != nullptr && + (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || + bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); + + BVH *bvh = scene->bvh; + if (!scene->bvh) { + bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); + } + + device->build_bvh(bvh, progress, can_refit); + + if (progress.get_cancel()) { + return; + } + + const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); + + PackedBVH pack; + if (has_bvh2_layout) { + pack = std::move(static_cast(bvh)->pack); + } + else { + pack.root_index = -1; + } + + /* copy to device */ + progress.set_status("Updating Scene BVH", "Copying BVH to device"); + + /* When using BVH2, we always have to copy/update the data as its layout is dependent on the + * BVH's leaf nodes which may be different when the objects or vertices move. */ + + if (pack.nodes.size()) { + dscene->bvh_nodes.steal_data(pack.nodes); + dscene->bvh_nodes.copy_to_device(); + } + if (pack.leaf_nodes.size()) { + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); + dscene->bvh_leaf_nodes.copy_to_device(); + } + if (pack.object_node.size()) { + dscene->object_node.steal_data(pack.object_node); + dscene->object_node.copy_to_device(); + } + if (pack.prim_type.size()) { + dscene->prim_type.steal_data(pack.prim_type); + dscene->prim_type.copy_to_device(); + } + if (pack.prim_visibility.size()) { + dscene->prim_visibility.steal_data(pack.prim_visibility); + dscene->prim_visibility.copy_to_device(); + } + if (pack.prim_index.size()) { + dscene->prim_index.steal_data(pack.prim_index); + dscene->prim_index.copy_to_device(); + } + if (pack.prim_object.size()) { + dscene->prim_object.steal_data(pack.prim_object); + dscene->prim_object.copy_to_device(); + } + if (pack.prim_time.size()) { + dscene->prim_time.steal_data(pack.prim_time); + dscene->prim_time.copy_to_device(); + } + + dscene->data.bvh.root = pack.root_index; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); + dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); + /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ + dscene->data.device_bvh = 0; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_mesh.cpp b/intern/cycles/scene/geometry_mesh.cpp new file mode 100644 index 00000000000..954a79f9de7 --- /dev/null +++ b/intern/cycles/scene/geometry_mesh.cpp @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/osl.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#ifdef WITH_OSL +# include "kernel/osl/globals.h" +#endif + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void GeometryManager::device_update_mesh(Device *, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + size_t curve_segment_size = 0; + + size_t point_size = 0; + + size_t patch_size = 0; + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + if (mesh->get_num_subd_faces()) { + Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + curve_key_size += hair->get_curve_keys().size(); + curve_size += hair->num_curves(); + curve_segment_size += hair->num_segments(); + } + else if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + point_size += pointcloud->num_points(); + } + } + + /* Fill in all the arrays. */ + if (tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); + + packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); + uint *tri_shader = dscene->tri_shader.alloc(tri_size); + packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); + packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); + uint *tri_patch = dscene->tri_patch.alloc(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + + const bool copy_all_data = dscene->tri_shader.need_realloc() || + dscene->tri_vindex.need_realloc() || + dscene->tri_vnormal.need_realloc() || + dscene->tri_patch.need_realloc() || + dscene->tri_patch_uv.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + if (mesh->shader_is_modified() || mesh->smooth_is_modified() || + mesh->triangles_is_modified() || copy_all_data) { + mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); + } + + if (mesh->verts_is_modified() || copy_all_data) { + mesh->pack_normals(&vnormal[mesh->vert_offset]); + } + + if (mesh->verts_is_modified() || mesh->triangles_is_modified() || + mesh->vert_patch_uv_is_modified() || copy_all_data) { + mesh->pack_verts(&tri_verts[mesh->vert_offset], + &tri_vindex[mesh->prim_offset], + &tri_patch[mesh->prim_offset], + &tri_patch_uv[mesh->vert_offset]); + } + + if (progress.get_cancel()) + return; + } + } + + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + dscene->tri_verts.copy_to_device_if_modified(); + dscene->tri_shader.copy_to_device_if_modified(); + dscene->tri_vnormal.copy_to_device_if_modified(); + dscene->tri_vindex.copy_to_device_if_modified(); + dscene->tri_patch.copy_to_device_if_modified(); + dscene->tri_patch_uv.copy_to_device_if_modified(); + } + + if (curve_segment_size != 0) { + progress.set_status("Updating Mesh", "Copying Curves to device"); + + float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); + KernelCurve *curves = dscene->curves.alloc(curve_size); + KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); + + const bool copy_all_data = dscene->curve_keys.need_realloc() || + dscene->curves.need_realloc() || + dscene->curve_segments.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + bool curve_keys_co_modified = hair->curve_radius_is_modified() || + hair->curve_keys_is_modified(); + bool curve_data_modified = hair->curve_shader_is_modified() || + hair->curve_first_key_is_modified(); + + if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { + continue; + } + + hair->pack_curves(scene, + &curve_keys[hair->curve_key_offset], + &curves[hair->prim_offset], + &curve_segments[hair->curve_segment_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->curve_keys.copy_to_device_if_modified(); + dscene->curves.copy_to_device_if_modified(); + dscene->curve_segments.copy_to_device_if_modified(); + } + + if (point_size != 0) { + progress.set_status("Updating Mesh", "Copying Point clouds to device"); + + float4 *points = dscene->points.alloc(point_size); + uint *points_shader = dscene->points_shader.alloc(point_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + pointcloud->pack( + scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->points.copy_to_device(); + dscene->points_shader.copy_to_device(); + } + + if (patch_size != 0 && dscene->patches.need_realloc()) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.alloc(patch_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + mesh->pack_patches(&patch_data[mesh->patch_offset]); + + if (mesh->patch_table) { + mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], + mesh->patch_table_offset); + } + + if (progress.get_cancel()) + return; + } + } + + dscene->patches.copy_to_device(); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index ee94e2bd724..2b68d1bd9a6 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -24,6 +24,7 @@ #include "scene/svm.h" #include "scene/tables.h" #include "scene/volume.h" +#include "scene/devicescene.h" #include "session/session.h" #include "util/foreach.h" @@ -33,59 +34,7 @@ CCL_NAMESPACE_BEGIN -DeviceScene::DeviceScene(Device *device) - : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), - bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), - object_node(device, "object_node", MEM_GLOBAL), - prim_type(device, "prim_type", MEM_GLOBAL), - prim_visibility(device, "prim_visibility", MEM_GLOBAL), - prim_index(device, "prim_index", MEM_GLOBAL), - prim_object(device, "prim_object", MEM_GLOBAL), - prim_time(device, "prim_time", MEM_GLOBAL), - tri_verts(device, "tri_verts", MEM_GLOBAL), - tri_shader(device, "tri_shader", MEM_GLOBAL), - tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), - tri_vindex(device, "tri_vindex", MEM_GLOBAL), - tri_patch(device, "tri_patch", MEM_GLOBAL), - tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), - curves(device, "curves", MEM_GLOBAL), - curve_keys(device, "curve_keys", MEM_GLOBAL), - curve_segments(device, "curve_segments", MEM_GLOBAL), - patches(device, "patches", MEM_GLOBAL), - points(device, "points", MEM_GLOBAL), - points_shader(device, "points_shader", MEM_GLOBAL), - objects(device, "objects", MEM_GLOBAL), - object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), - object_motion(device, "object_motion", MEM_GLOBAL), - object_flag(device, "object_flag", MEM_GLOBAL), - object_volume_step(device, "object_volume_step", MEM_GLOBAL), - object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), - camera_motion(device, "camera_motion", MEM_GLOBAL), - attributes_map(device, "attributes_map", MEM_GLOBAL), - attributes_float(device, "attributes_float", MEM_GLOBAL), - attributes_float2(device, "attributes_float2", MEM_GLOBAL), - attributes_float3(device, "attributes_float3", MEM_GLOBAL), - attributes_float4(device, "attributes_float4", MEM_GLOBAL), - attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), - light_distribution(device, "light_distribution", MEM_GLOBAL), - lights(device, "lights", MEM_GLOBAL), - light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), - light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), - light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), - light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), - light_to_tree(device, "light_to_tree", MEM_GLOBAL), - object_to_tree(device, "object_to_tree", MEM_GLOBAL), - object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), - triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), - particles(device, "particles", MEM_GLOBAL), - svm_nodes(device, "svm_nodes", MEM_GLOBAL), - shaders(device, "shaders", MEM_GLOBAL), - lookup_table(device, "lookup_table", MEM_GLOBAL), - sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), - ies_lights(device, "ies", MEM_GLOBAL) -{ - memset((void *)&data, 0, sizeof(data)); -} + Scene::Scene(const SceneParams ¶ms_, Device *device) : name("Scene"), diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 8a522d88ac1..742d4db79f3 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -6,20 +6,16 @@ #include "bvh/params.h" +#include "scene/devicescene.h" #include "scene/film.h" #include "scene/image.h" #include "scene/shader.h" -#include "device/device.h" -#include "device/memory.h" - #include "util/param.h" #include "util/string.h" #include "util/system.h" #include "util/texture.h" #include "util/thread.h" -#include "util/types.h" -#include "util/vector.h" CCL_NAMESPACE_BEGIN @@ -54,92 +50,6 @@ class RenderStats; class SceneUpdateStats; class Volume; -/* Scene Device Data */ - -class DeviceScene { - public: - /* BVH */ - device_vector bvh_nodes; - device_vector bvh_leaf_nodes; - device_vector object_node; - device_vector prim_type; - device_vector prim_visibility; - device_vector prim_index; - device_vector prim_object; - device_vector prim_time; - - /* mesh */ - device_vector tri_verts; - device_vector tri_shader; - device_vector tri_vnormal; - device_vector tri_vindex; - device_vector tri_patch; - device_vector tri_patch_uv; - - device_vector curves; - device_vector curve_keys; - device_vector curve_segments; - - device_vector patches; - - /* point-cloud */ - device_vector points; - device_vector points_shader; - - /* objects */ - device_vector objects; - device_vector object_motion_pass; - device_vector object_motion; - device_vector object_flag; - device_vector object_volume_step; - device_vector object_prim_offset; - - /* cameras */ - device_vector camera_motion; - - /* attributes */ - device_vector attributes_map; - device_vector attributes_float; - device_vector attributes_float2; - device_vector attributes_float3; - device_vector attributes_float4; - device_vector attributes_uchar4; - - /* lights */ - device_vector light_distribution; - device_vector lights; - device_vector light_background_marginal_cdf; - device_vector light_background_conditional_cdf; - - /* light tree */ - device_vector light_tree_nodes; - device_vector light_tree_emitters; - device_vector light_to_tree; - device_vector object_to_tree; - device_vector object_lookup_offset; - device_vector triangle_to_tree; - - /* particles */ - device_vector particles; - - /* shaders */ - device_vector svm_nodes; - device_vector shaders; - - /* lookup tables */ - device_vector lookup_table; - - /* integrator */ - device_vector sample_pattern_lut; - - /* IES lights */ - device_vector ies_lights; - - KernelData data; - - DeviceScene(Device *device); -}; - /* Scene Parameters */ class SceneParams { -- 2.30.2 From 0e23aef6b6dc000aecdd3e9a780a1e0602e83e2e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 20 Apr 2023 15:46:15 +0200 Subject: [PATCH 55/61] Fix build error when not using unity build --- source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index f6b44a9ac47..c4c0d4b1517 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -7,6 +7,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_attribute_math.hh" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "UI_interface.h" -- 2.30.2 From 5c4b0c98d37d7fa1d7248217af0d0cb32f63c9cf Mon Sep 17 00:00:00 2001 From: Nate Rupsis Date: Thu, 20 Apr 2023 17:40:19 +0200 Subject: [PATCH 56/61] Animation: Add in Parent space alignment option to the Transform Orientation gizmo Animation: Adds a new "Parent Space" Orientation option for the Transformation Gizmo. --- For child targets (objects, bones, etc) being able to transform in parent space is a desired feature (especially when it comes to rigging / animation). For objects: * with a parent, the gizmo orients to it's parents orientation * without a parent, the gizmo orients to Global space For Armatures: * Child bone shows parent's space regardless if "Local Location" is set for parent bone * For root bone **without** "Local Location" set, use the armature objects space. * For root bone **with** "Local Location" set, use local bone space. --- No new transformation orientation code needs to be written, we can achieve the desired results be using the existing `transform_orientations_create_from_axis`, `ED_getTransformOrientationMatrix`, and `unit_m3` methods. To do this, we check to see if the bone has a parent, if so, we use the bones pose matrix (`pose_mat`). This is done similarly for objects using the parent's object matrix (`object_to_world`). Pull Request: https://projects.blender.org/blender/blender/pulls/104724 --- .../transform/transform_orientations.c | 45 ++++++++++++++++++- source/blender/makesdna/DNA_view3d_types.h | 1 + source/blender/makesrna/intern/rna_scene.c | 5 +++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index f1e83c5090c..64bd87cbf79 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -580,6 +580,33 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3 scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat); } +static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3]) +{ + bPoseChannel *active_pchan = BKE_pose_channel_active(ob, false); + + /* Check if target bone is a child. */ + if (active_pchan->parent) { + /* For child, show parent local regardless if "local location" is set for parent bone. */ + transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat)); + return; + } + + /* For root, use local transform of armature object. */ + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world)); +} + +static void handle_object_parent_orientation(Object *ob, float r_mat[3][3]) +{ + /* If object has parent, then orient to parent. */ + if (ob->parent) { + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->parent->object_to_world)); + } + else { + /* If object doesn't have parent, then orient to world. */ + unit_m3(r_mat); + } +} + short ED_transform_calc_orientation_from_type_ex(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, @@ -609,6 +636,20 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, /* If not gimbal, fall through to normal. */ ATTR_FALLTHROUGH; } + case V3D_ORIENT_PARENT: { + if (ob) { + if (ob->mode & OB_MODE_POSE) { + handle_armature_parent_orientation(ob, r_mat); + break; + } + else { + handle_object_parent_orientation(ob, r_mat); + break; + } + } + /* No break; we define 'parent' as 'normal' otherwise. */ + ATTR_FALLTHROUGH; + } case V3D_ORIENT_NORMAL: { if (obedit || (ob && ob->mode & OB_MODE_POSE)) { ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); @@ -621,7 +662,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, if (ob) { if (ob->mode & OB_MODE_POSE) { /* Each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display #33575, this works as expected on a single + * use the active bone's axis for display #33575, this works as expected on a single * bone and users who select many bones will understand what's going on and what local * means when they start transforming. */ ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); @@ -741,6 +782,8 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien return TIP_("view"); case V3D_ORIENT_CURSOR: return TIP_("cursor"); + case V3D_ORIENT_PARENT: + return TIP_("parent"); case V3D_ORIENT_CUSTOM_MATRIX: return TIP_("custom"); case V3D_ORIENT_CUSTOM: diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index ff82cd2183f..741f5e1ae44 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -630,6 +630,7 @@ enum { V3D_ORIENT_VIEW = 3, V3D_ORIENT_GIMBAL = 4, V3D_ORIENT_CURSOR = 5, + V3D_ORIENT_PARENT = 6, V3D_ORIENT_CUSTOM = 1024, /** Runtime only, never saved to DNA. */ V3D_ORIENT_CUSTOM_MATRIX = (V3D_ORIENT_CUSTOM - 1), diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index c2dc81bb9e5..7ad1adb66b4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -628,6 +628,11 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = { ICON_ORIENTATION_CURSOR, "Cursor", "Align the transformation axes to the 3D cursor"}, + {V3D_ORIENT_PARENT, + "PARENT", + ICON_BLANK1, + "Parent", + "Align the transformation axes to the object's parent space"}, // {V3D_ORIENT_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"}, {0, NULL, 0, NULL, NULL}, }; -- 2.30.2 From b2c822065c0f1f4671c0a471b5718123e83f57ca Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 20 Apr 2023 18:40:07 +0200 Subject: [PATCH 57/61] Fix #106977: Crash when OpenEXR IO fails The crash can occur in the following situations: - Attempt to open a corrupted EXR file - Attempt to save an EXR file under a non-existing directory. The root cause is not really clear: for some reason the OpenEXE API on the Blender side can not catch OpenEXE exceptions by a constant reference to a std::exception, although it can by a constant reference to an Iex::BaseExc. This does not seem to be an issue with the OpenEXR library itself as the idiff tool from our SVN folder catches the exceptions correctly. It is also not caused by the symbols_apple.map as erasing it does not make the problem go away. It could still be some compiler/visibility flag which we were unable to nail down yet. The proposed solution is to add catch-all cases, mimicking the OIIO tools. This solves the problem with the downside is that there are no friendly error messages in the terminal. Those messages could be brought as part of the workaround by additionally catching the Iex::BaseExc exception. But probably nobody relies on those error prints anyway, so added complexity in the code is likely does not worth it. Pull Request: https://projects.blender.org/blender/blender/pulls/107184 --- .../imbuf/intern/openexr/openexr_api.cpp | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 155aa4783a0..00baceff4ac 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -560,6 +560,12 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags return false; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + delete file_stream; + printf("OpenEXR-save: UNKNOWN ERROR\n"); + + return false; + } delete file_stream; return true; @@ -636,6 +642,11 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag delete file_stream; return false; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + printf("OpenEXR-save: UNKNOWN ERROR\n"); + delete file_stream; + return false; + } delete file_stream; return true; @@ -939,6 +950,15 @@ bool IMB_exr_begin_write(void *handle, data->ofile = nullptr; data->ofile_stream = nullptr; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "IMB_exr_begin_write: UNKNOWN ERROR" << std::endl; + + delete data->ofile; + delete data->ofile_stream; + + data->ofile = nullptr; + data->ofile_stream = nullptr; + } return (data->ofile != nullptr); } @@ -999,7 +1019,7 @@ void IMB_exrtile_begin_write( data->ofile_stream = new OFileStream(filepath); data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size()); } - catch (const std::exception &) { + catch (...) { /* Catch-all for edge cases or compiler bugs. */ delete data->mpofile; delete data->ofile_stream; @@ -1024,7 +1044,7 @@ bool IMB_exr_begin_read( data->ifile_stream = new IFileStream(filepath); data->ifile = new MultiPartInputFile(*(data->ifile_stream)); } - catch (const std::exception &) { + catch (...) { /* Catch-all for edge cases or compiler bugs. */ delete data->ifile; delete data->ifile_stream; @@ -1199,6 +1219,9 @@ void IMB_exr_write_channels(void *handle) catch (const std::exception &exc) { std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-writePixels: UNKNOWN ERROR" << std::endl; + } /* Free temporary buffers. */ if (rect_half != nullptr) { MEM_freeN(rect_half); @@ -1258,6 +1281,9 @@ void IMB_exrtile_write_channels( catch (const std::exception &exc) { std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-writeTile: UNKNOWN ERROR" << std::endl; + } } void IMB_exr_read_channels(void *handle) @@ -1336,6 +1362,10 @@ void IMB_exr_read_channels(void *handle) std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl; break; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl; + break; + } } } @@ -2150,6 +2180,16 @@ struct ImBuf *imb_load_openexr(const uchar *mem, delete file; delete membuf; + return nullptr; + } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-Load: UNKNOWN ERROR" << std::endl; + if (ibuf) { + IMB_freeImBuf(ibuf); + } + delete file; + delete membuf; + return nullptr; } } @@ -2254,6 +2294,12 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath, delete stream; return nullptr; } + catch (...) { /* Catch-all for edge cases or compiler bugs. */ + std::cerr << "OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl; + delete file; + delete stream; + return nullptr; + } return nullptr; } -- 2.30.2 From 2f4a8ecf181c7b4b13ed385d3d700ecf6079b5f0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 20 Apr 2023 12:54:28 -0400 Subject: [PATCH 58/61] Fix: Spreadsheet missing other geometry types for edit mode mesh objects We need to add to the spreadsheet's display geometry set rather than completely replacing it with just the mesh. --- .../spreadsheet_data_source_geometry.cc | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 975e4c10f21..33651885e2a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -510,28 +510,23 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { - Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval); - if (mesh == nullptr) { - return geometry_set; + if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) { + if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) { + geometry_set = *geometry_eval; + } + + if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { + if (Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval)) { + BKE_mesh_wrapper_ensure_mdata(mesh); + geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly); + } } - BKE_mesh_wrapper_ensure_mdata(mesh); - MeshComponent &mesh_component = geometry_set.get_component_for_write(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); } else { - if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) { - /* Use final evaluated object. */ - if (object_eval->runtime.geometry_set_eval != nullptr) { - geometry_set = *object_eval->runtime.geometry_set_eval; - } - } - else { - if (const ViewerNodeLog *viewer_log = - nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path( - sspreadsheet->viewer_path)) { - geometry_set = viewer_log->geometry; - } + if (const ViewerNodeLog *viewer_log = + nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path( + sspreadsheet->viewer_path)) { + geometry_set = viewer_log->geometry; } } } -- 2.30.2 From 3af5b2f7ff1f09d63945b92f29dffd659f77d0e6 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 20 Apr 2023 14:50:41 -0400 Subject: [PATCH 59/61] Move node to "Geometry > Sample" menu --- scripts/startup/bl_ui/node_add_menu_geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index e5a3a85af2d..d673f6941b2 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -220,6 +220,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeProximity") + node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest") node_add_menu.add_node_type(layout, "GeometryNodeRaycast") node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex") node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest") @@ -528,7 +529,6 @@ class NODE_MT_category_GEO_UTILITIES_FIELD(Menu): node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField") node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex") node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain") - node_add_menu.add_node_type(layout, "GeometryNodeIndexOfNearest") node_add_menu.draw_assets_for_catalog(layout, self.bl_label) -- 2.30.2 From 1c26c392e0c21d42d9ab2371069c2991556c1c27 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 20 Apr 2023 14:57:48 -0400 Subject: [PATCH 60/61] Also mention similar node in "Sample Nearest" node --- source/blender/nodes/NOD_static_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index eba6393110a..1bd9896261e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -399,7 +399,7 @@ DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateIn DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "Retrieve data from a point on a curve at a certain distance from its start") DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface") -DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position") +DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position. Similar to the \"Index of Nearest\" node") DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, def_geo_sample_uv_surface, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate") DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces") DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space") -- 2.30.2 From f8d47be90010de788202984f18a12aae48579db7 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 20 Apr 2023 15:00:46 -0400 Subject: [PATCH 61/61] Changes to implementation: - Build the kdtree from the entire input, not using the evaluation mask - Use separate static functions for some logic - Use VArraySpan for positions - Separate Has Neighbor to a different field input --- .../nodes/node_geo_index_of_nearest.cc | 243 ++++++++++++------ 1 file changed, 171 insertions(+), 72 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc b/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc index 820f5219685..c2f624d462a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_index_of_nearest.cc @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_attribute_math.hh" - #include "BLI_kdtree.h" #include "BLI_multi_value_map.hh" #include "BLI_task.hh" @@ -19,6 +17,55 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output(N_("Has Neighbor")).field_source(); } +static KDTree_3d *build_kdtree(const Span &positions, const IndexMask mask) +{ + KDTree_3d *tree = BLI_kdtree_3d_new(mask.size()); + for (const int i : mask) { + BLI_kdtree_3d_insert(tree, i, positions[i]); + } + BLI_kdtree_3d_balance(tree); + return tree; +} + +static int find_nearest_non_self(const KDTree_3d &tree, const float3 &position, const int index) +{ + return BLI_kdtree_3d_find_nearest_cb_cpp( + &tree, position, 0, [index](const int other, const float * /*co*/, const float /*dist_sq*/) { + return index == other ? 0 : 1; + }); +} + +static void find_neighbors(const KDTree_3d &tree, + const Span positions, + const IndexMask mask, + MutableSpan indices) +{ + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + for (const int i : mask.slice(range)) { + indices[i] = find_nearest_non_self(tree, positions[i], i); + } + }); +} + +static Vector masks_from_group_ids(const Span group_ids, + const IndexMask mask, + MultiValueMap &storage) +{ + mask.foreach_index([&](const int i) { storage.add(group_ids[i], i); }); + Vector masks; + masks.reserve(storage.size()); + for (const Span indices : storage.values()) { + masks.append(indices); + } + return masks; +} + +static Vector masks_from_group_ids(const Span group_ids, + MultiValueMap &storage) +{ + return masks_from_group_ids(group_ids, group_ids.index_range(), storage); +} + class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { private: const Field positions_field_; @@ -26,70 +73,70 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { public: IndexOfNearestFieldInput(Field positions_field, Field group_field) - : bke::GeometryFieldInput(CPPType::get(), "Nearest to"), + : bke::GeometryFieldInput(CPPType::get(), "Index of Nearest"), positions_field_(std::move(positions_field)), group_field_(std::move(group_field)) { } GVArray get_varray_for_context(const bke::GeometryFieldContext &context, - IndexMask mask) const final + const IndexMask mask) const final { - fn::FieldEvaluator evaluator{context, &mask}; + if (!context.attributes()) { + return {}; + } + const int domain_size = context.attributes()->domain_size(context.domain()); + fn::FieldEvaluator evaluator{context, domain_size}; evaluator.add(positions_field_); evaluator.add(group_field_); evaluator.evaluate(); + const VArraySpan positions = evaluator.get_evaluated(0); + const VArray group = evaluator.get_evaluated(1); - const VArray &positions = evaluator.get_evaluated(0); - const VArray &group = evaluator.get_evaluated(1); + Array result(mask.min_array_size()); - MultiValueMap group_masks; - mask.foreach_index([&](const int index) { group_masks.add(group[index], index); }); - - Array indices(mask.min_array_size()); - - const auto nearest_for = [this, &positions](const IndexMask mask, MutableSpan r_indices) { - devirtualize_varray(positions, [mask, r_indices, this](const auto positions) { - KDTree_3d *tree = BLI_kdtree_3d_new(mask.size()); - mask.foreach_index([tree, positions](const int index) { - BLI_kdtree_3d_insert(tree, index, positions[index]); - }); - - BLI_kdtree_3d_balance(tree); - - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - mask.slice(range).foreach_index([&](const auto index) { - r_indices[index] = this->kdtree_find_neighboard(tree, positions[index], index); - }); - }); - - BLI_kdtree_3d_free(tree); - }); - }; - - for (const Span mask_span : group_masks.values()) { - if (mask_span.size() == 1) { - indices[mask_span.first()] = -1; - } - nearest_for(mask_span, indices); + if (group.is_single()) { + const IndexMask full_mask = positions.index_range(); + KDTree_3d *tree = build_kdtree(positions, full_mask); + find_neighbors(*tree, positions, mask, result); + BLI_kdtree_3d_free(tree); } + else { + /* The goal is to build each tree and use it immediately, rather than building all trees and + * sampling them later. That should help to keep the tree in caches before balancing and when + * sampling many points. */ + const VArraySpan group_ids(group); + MultiValueMap group_mask_storage; + const Vector tree_masks = masks_from_group_ids(group_ids, group_mask_storage); - return VArray::ForContainer(std::move(indices)); - } + MultiValueMap evaluate_masks_storage; + Vector evaluate_masks; + if (mask.size() < domain_size) { + /* Separate masks for evaluation are only necessary if the mask mask + * for field input evaluation doesn't have every element selected. */ + evaluate_masks = masks_from_group_ids(group_ids, mask, evaluate_masks_storage); + } - protected: - static int kdtree_find_neighboard(KDTree_3d *tree, const float3 &position, const int &index) - { - return BLI_kdtree_3d_find_nearest_cb_cpp( - tree, - position, - 0, - [index](const int other_new_i, const float * /*co*/, const float /*dist_sq*/) { - if (index == other_new_i) { - return 0; + /* The grain size should be larger as each tree gets smaller. */ + const int avg_tree_size = group_ids.size() / group_mask_storage.size(); + const int grain_size = std::max(8192 / avg_tree_size, 1); + threading::parallel_for(tree_masks.index_range(), grain_size, [&](const IndexRange range) { + for (const int i : range) { + const IndexMask tree_mask = tree_masks[i]; + const IndexMask evaluate_mask = evaluate_masks.is_empty() ? tree_mask : + evaluate_masks[i]; + if (tree_masks[i].size() < 2) { + result.as_mutable_span().fill_indices(evaluate_mask.indices(), 0); } - return 1; - }); + else { + KDTree_3d *tree = build_kdtree(positions, tree_mask); + find_neighbors(*tree, positions, evaluate_mask, result); + BLI_kdtree_3d_free(tree); + } + } + }); + } + return VArray::ForContainer(std::move(result)); } public: @@ -99,53 +146,105 @@ class IndexOfNearestFieldInput final : public bke::GeometryFieldInput { group_field_.node().for_each_field_input_recursive(fn); } - uint64_t hash() const override + uint64_t hash() const final { return get_default_hash_2(positions_field_, group_field_); } - bool is_equal_to(const fn::FieldNode &other) const override + bool is_equal_to(const fn::FieldNode &other) const final { - if (const IndexOfNearestFieldInput *other_field = - dynamic_cast(&other)) { + if (const auto *other_field = dynamic_cast(&other)) { return positions_field_ == other_field->positions_field_ && group_field_ == other_field->group_field_; } return false; } - std::optional preferred_domain(const GeometryComponent &component) const override + std::optional preferred_domain(const GeometryComponent &component) const final { return bke::try_detect_field_domain(component, positions_field_); } }; +class HasNeighborFieldInput final : public bke::GeometryFieldInput { + private: + const Field group_field_; + + public: + HasNeighborFieldInput(Field group_field) + : bke::GeometryFieldInput(CPPType::get(), "Has Neighbor"), + group_field_(std::move(group_field)) + { + } + + GVArray get_varray_for_context(const bke::GeometryFieldContext &context, + const IndexMask mask) const final + { + if (!context.attributes()) { + return {}; + } + const int domain_size = context.attributes()->domain_size(context.domain()); + fn::FieldEvaluator evaluator{context, domain_size}; + evaluator.add(group_field_); + evaluator.evaluate(); + const VArray group = evaluator.get_evaluated(0); + + if (group.is_single()) { + return VArray::ForSingle(true, mask.min_array_size()); + } + + /* When a group ID is contained in the set, it means there is only one element with that ID. */ + Map counts; + const VArraySpan group_span(group); + mask.foreach_index([&](const int i) { + counts.add_or_modify( + group_span[i], [](int *count) { *count = 0; }, [](int *count) { (*count)++; }); + }); + Array result(mask.min_array_size()); + mask.foreach_index([&](const int i) { result[i] = counts.lookup(group_span[i]) > 1; }); + return VArray::ForContainer(std::move(result)); + } + + public: + void for_each_field_input_recursive(FunctionRef fn) const + { + group_field_.node().for_each_field_input_recursive(fn); + } + + uint64_t hash() const final + { + return get_default_hash_2(3984756934876, group_field_); + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const auto *other_field = dynamic_cast(&other)) { + return group_field_ == other_field->group_field_; + } + return false; + } + + std::optional preferred_domain(const GeometryComponent &component) const final + { + return bke::try_detect_field_domain(component, group_field_); + } +}; + static void node_geo_exec(GeoNodeExecParams params) { Field position_field = params.extract_input>("Position"); Field group_field = params.extract_input>("Group ID"); - Field index_of_nearest_field(std::make_shared( - std::move(position_field), std::move(group_field))); - if (params.output_is_required("Index")) { - static auto clamp_fn = mf::build::SI1_SO( - "Index Clamping", - [](const int index) { return math::max(0, index); }, - mf::build::exec_presets::Materialized()); - auto clamp_op = std::make_shared( - FieldOperation(std::move(clamp_fn), {index_of_nearest_field})); - params.set_output("Index", Field(clamp_op, 0)); + params.set_output("Index", + Field(std::make_shared( + std::move(position_field), group_field))); } if (params.output_is_required("Has Neighbor")) { - static auto valid_fn = mf::build::SI1_SO( - "Index Validating", - [](const int index) { return index != -1; }, - mf::build::exec_presets::Materialized()); - auto valid_op = std::make_shared( - FieldOperation(std::move(valid_fn), {std::move(index_of_nearest_field)})); - params.set_output("Has Neighbor", Field(valid_op, 0)); + params.set_output( + "Has Neighbor", + Field(std::make_shared(std::move(group_field)))); } } -- 2.30.2