From f20d0de3b7b4678257669d558a3ebb40115939c7 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 30 Aug 2022 13:35:03 +0200 Subject: Fix T93084: Area stretch overlay full red on large scale mesh Issue arises when face areas are really large combined with small UV areas (report has a mesh ~1.5 km), then precission of shorts is insufficient. Now use floats instead. This also removes this negative signed version of the total area ratio (since with floats it is no longer used). Thx @brecht for a lot of hand-holding! NOTE: this is an alternative to D15805 (and quick tests show this does not introduce the tiny performance hit as D15805 did). Maniphest Tasks: T93084 Differential Revision: https://developer.blender.org/D15810 --- .../blender/draw/engines/overlay/overlay_edit_uv.c | 4 ---- .../blender/draw/engines/overlay/overlay_private.h | 1 - .../overlay/shaders/infos/overlay_edit_mode_info.hh | 1 - .../shaders/overlay_edit_uv_stretching_vert.glsl | 6 +++--- .../extract_mesh_vbo_edituv_stretch_area.cc | 21 +++++++-------------- 5 files changed, 10 insertions(+), 23 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c index 4cfe9fcea4e..adbe5e7155e 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_uv.c +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c @@ -160,7 +160,6 @@ void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) pd->edit_uv.draw_type = sima->dt_uvstretch; BLI_listbase_clear(&pd->edit_uv.totals); pd->edit_uv.total_area_ratio = 0.0f; - pd->edit_uv.total_area_ratio_inv = 0.0f; /* During engine initialization phase the `sima` isn't locked and * we are able to retrieve the needed data. @@ -280,8 +279,6 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float( pd->edit_uv_stretching_grp, "totalAreaRatio", &pd->edit_uv.total_area_ratio, 1); - DRW_shgroup_uniform_float( - pd->edit_uv_stretching_grp, "totalAreaRatioInv", &pd->edit_uv.total_area_ratio_inv, 1); } } @@ -510,7 +507,6 @@ static void edit_uv_stretching_update_ratios(OVERLAY_Data *vedata) if (total_area > FLT_EPSILON && total_area_uv > FLT_EPSILON) { pd->edit_uv.total_area_ratio = total_area / total_area_uv; - pd->edit_uv.total_area_ratio_inv = total_area_uv / total_area; } } BLI_freelistN(&pd->edit_uv.totals); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 7d216ca54cf..06c6ce42fd8 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -384,7 +384,6 @@ typedef struct OVERLAY_PrivateData { eSpaceImage_UVDT_Stretch draw_type; ListBase totals; float total_area_ratio; - float total_area_ratio_inv; /* stencil overlay */ struct Image *stencil_image; diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh index 58f96110887..9396a6d3f2f 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh @@ -293,7 +293,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area) .do_static_compilation(true) .vertex_in(1, Type::FLOAT, "ratio") .push_constant(Type::FLOAT, "totalAreaRatio") - .push_constant(Type::FLOAT, "totalAreaRatioInv") .additional_info("overlay_edit_uv_stretching"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_angle) diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl index bb086e8d9f5..9a3036d5940 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl @@ -55,9 +55,9 @@ float angle_normalized_v2v2(vec2 v1, vec2 v2) return (q) ? a : M_PI - a; } -float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +float area_ratio_to_stretch(float ratio, float tot_ratio) { - ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + ratio *= tot_ratio; return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } @@ -74,7 +74,7 @@ void main() stretch = stretch; stretch = 1.0 - stretch * stretch; #else - float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv); + float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio); #endif diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index 2bb786303c4..a1737f8590e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -27,7 +27,7 @@ static void extract_edituv_stretch_area_init(const MeshRenderData *mr, GPUVertBuf *vbo = static_cast(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } GPU_vertbuf_init_with_format(vbo, &format); @@ -37,15 +37,14 @@ static void extract_edituv_stretch_area_init(const MeshRenderData *mr, BLI_INLINE float area_ratio_get(float area, float uvarea) { if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) { - /* Tag inversion by using the sign. */ - return (area > uvarea) ? (uvarea / area) : -(area / uvarea); + return uvarea / area; } return 0.0f; } -BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio) { - ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + ratio *= tot_ratio; return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } @@ -97,14 +96,8 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float *area_ratio = static_cast(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area); - /* Convert in place to avoid an extra allocation */ - uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { - poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; - } - /* Copy face data for each loop. */ - uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo); + float *loop_stretch = (float *)GPU_vertbuf_get_data(vbo); if (mr->extract_type == MR_EXTRACT_BMESH) { BMFace *efa; @@ -112,7 +105,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, int f, l_index = 0; BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { for (int i = 0; i < efa->len; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[f]; + loop_stretch[l_index] = area_ratio[f]; } } } @@ -121,7 +114,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, const MPoly *mp = mr->mpoly; for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { for (int i = 0; i < mp->totloop; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[mp_index]; + loop_stretch[l_index] = area_ratio[mp_index]; } } } -- cgit v1.2.3 From d81e947c591ec6f3de2bc407b9f837b2efa36890 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 30 Aug 2022 11:29:47 -0700 Subject: BLF: Fallback Stack Error Handling Properly handle invalid fonts. See D15798 for more details Differential Revision: https://developer.blender.org/D15798 Reviewed by Brecht Van Lommel --- source/blender/blenfont/intern/blf_font.c | 4 ++++ source/blender/blenfont/intern/blf_font_default.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 886c34654c4..fb157c71172 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -110,6 +110,10 @@ static FT_Error blf_cache_face_requester(FTC_FaceID faceID, font->face->generic.data = font; font->face->generic.finalizer = blf_face_finalizer; } + else { + /* Clear this on error to avoid exception in FTC_Manager_LookupFace. */ + *face = NULL; + } return err; } diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index a88da6099e5..ffeee397c20 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -65,7 +65,9 @@ void BLF_load_font_stack() struct direntry *dir; uint num_files = BLI_filelist_dir_contents(path, &dir); for (int f = 0; f < num_files; f++) { - if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) { + if (!BLI_is_dir(dir[f].path) && + BLI_path_extension_check_n( + dir[f].path, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", NULL)) { if (!BLF_is_loaded(dir[f].path)) { int font_id = BLF_load(dir[f].path); if (font_id == -1) { -- cgit v1.2.3 From 25237d2625078c6d14d744f288776299efd3c7c8 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 14:54:53 -0500 Subject: Attributes: Improve custom data initialization options When allocating new `CustomData` layers, often we do redundant initialization of arrays. For example, it's common that values are allocated, set to their default value, and then set to some other value. This is wasteful, and it negates the benefits of optimizations to the allocator like D15082. There are two reasons for this. The first is array-of-structs storage that makes it annoying to initialize values manually, and the second is confusing options in the Custom Data API. This patch addresses the latter. The `CustomData` "alloc type" options are rearranged. Now, besides the options that use existing layers, there are two remaining: * `CD_SET_DEFAULT` sets the default value. * Usually zeroes, but for colors this is white (how it was before). * Should be used when you add the layer but don't set all values. * `CD_CONSTRUCT` refers to the "default construct" C++ term. * Only necessary or defined for non-trivial types like vertex groups. * Doesn't do anything for trivial types like `int` or `float3`. * Should be used every other time, when all values will be set. The attribute API's `AttributeInit` types are updated as well. To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and `CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional changes yet. Follow-up commits will change to avoid initializing new layers where the correctness is clear. Differential Revision: https://developer.blender.org/D15617 --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- source/blender/blenkernel/BKE_attribute.hh | 43 ++++-- source/blender/blenkernel/BKE_customdata.h | 11 +- source/blender/blenkernel/intern/DerivedMesh.cc | 42 ++--- source/blender/blenkernel/intern/attribute.cc | 2 +- .../blender/blenkernel/intern/attribute_access.cc | 30 ++-- .../blender/blenkernel/intern/curves_geometry.cc | 4 +- source/blender/blenkernel/intern/customdata.cc | 171 +++++++++++++-------- source/blender/blenkernel/intern/data_transfer.c | 18 ++- source/blender/blenkernel/intern/deform.c | 9 +- source/blender/blenkernel/intern/dynamicpaint.c | 6 +- .../blender/blenkernel/intern/editmesh_tangent.c | 2 +- .../blenkernel/intern/geometry_component_curve.cc | 11 +- .../blender/blenkernel/intern/mball_tessellate.c | 7 +- source/blender/blenkernel/intern/mesh.cc | 28 ++-- .../blenkernel/intern/mesh_boolean_convert.cc | 8 +- source/blender/blenkernel/intern/mesh_convert.cc | 5 +- .../blenkernel/intern/mesh_legacy_convert.cc | 21 +-- source/blender/blenkernel/intern/mesh_normals.cc | 2 +- source/blender/blenkernel/intern/mesh_remap.c | 2 +- .../blender/blenkernel/intern/mesh_remesh_voxel.cc | 6 +- source/blender/blenkernel/intern/mesh_tangent.c | 5 +- source/blender/blenkernel/intern/mesh_validate.cc | 4 +- source/blender/blenkernel/intern/multires.c | 4 +- .../blender/blenkernel/intern/multires_reshape.c | 3 +- .../blenkernel/intern/multires_reshape_subdivide.c | 3 +- .../blenkernel/intern/multires_unsubdivide.c | 6 +- source/blender/blenkernel/intern/object.cc | 2 +- source/blender/blenkernel/intern/object_deform.c | 3 +- source/blender/blenkernel/intern/paint.cc | 14 +- source/blender/blenkernel/intern/particle_system.c | 2 +- source/blender/blenkernel/intern/pbvh.c | 2 +- source/blender/blenkernel/intern/pointcloud.cc | 8 +- source/blender/blenkernel/intern/subdiv_mesh.cc | 4 +- source/blender/blenkernel/intern/subsurf_ccg.c | 6 +- source/blender/blenlib/intern/BLI_memarena.c | 1 + .../blender/blenloader/intern/versioning_legacy.c | 4 +- source/blender/bmesh/intern/bmesh_construct.c | 26 ++-- source/blender/bmesh/intern/bmesh_interp.c | 4 +- source/blender/bmesh/intern/bmesh_mesh_convert.cc | 48 +++--- source/blender/editors/curves/intern/curves_add.cc | 2 +- .../editors/geometry/geometry_attributes.cc | 4 +- source/blender/editors/mesh/mesh_data.cc | 27 ++-- source/blender/editors/mesh/meshtools.cc | 16 +- source/blender/editors/object/object_facemap_ops.c | 2 +- source/blender/editors/object/object_modifier.cc | 10 +- source/blender/editors/sculpt_paint/paint_hide.c | 2 +- .../blender/editors/sculpt_paint/sculpt_dyntopo.c | 2 +- source/blender/editors/sculpt_paint/sculpt_undo.c | 2 +- .../blender_interface/BlenderStrokeRenderer.cpp | 16 +- source/blender/io/alembic/intern/abc_customdata.cc | 2 +- .../blender/io/alembic/intern/abc_reader_mesh.cc | 4 +- source/blender/io/collada/MeshImporter.cpp | 15 +- source/blender/io/stl/importer/stl_import_mesh.cc | 6 +- source/blender/io/usd/intern/usd_reader_mesh.cc | 5 +- .../io/wavefront_obj/importer/obj_import_mesh.cc | 4 +- .../io/wavefront_obj/tests/obj_importer_tests.cc | 2 +- source/blender/makesrna/intern/rna_mesh.c | 13 +- source/blender/makesrna/intern/rna_mesh_api.c | 4 +- source/blender/modifiers/intern/MOD_cloth.c | 2 +- source/blender/modifiers/intern/MOD_nodes.cc | 8 +- source/blender/modifiers/intern/MOD_normal_edit.c | 2 +- source/blender/modifiers/intern/MOD_ocean.c | 12 +- source/blender/modifiers/intern/MOD_screw.c | 2 +- source/blender/modifiers/intern/MOD_skin.c | 2 +- .../modifiers/intern/MOD_solidify_extrude.c | 2 +- .../modifiers/intern/MOD_solidify_nonmanifold.c | 2 +- source/blender/modifiers/intern/MOD_uvproject.c | 2 +- .../blender/modifiers/intern/MOD_weighted_normal.c | 3 +- source/blender/modifiers/intern/MOD_weightvgedit.c | 2 +- source/blender/modifiers/intern/MOD_weightvgmix.c | 2 +- .../nodes/node_geo_store_named_attribute.cc | 2 +- .../geometry/nodes/node_geo_subdivision_surface.cc | 2 +- 74 files changed, 431 insertions(+), 333 deletions(-) diff --git a/release/datafiles/locale b/release/datafiles/locale index a2eb5078914..1b891478f44 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit a2eb507891449a0b67582be9561840075513661d +Subproject commit 1b891478f44dd047c3a92fda3ebd17fae1c3acd3 diff --git a/release/scripts/addons b/release/scripts/addons index 7a8502871c3..25ffc6f430f 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 7a8502871c34db0343cc7de52d6b49b15a84238a +Subproject commit 25ffc6f430fc995b1c046b01acba1c3e6c1896b0 diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index c2f65c93cbe..6284cce9dc0 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -73,8 +73,13 @@ struct AttributeKind { */ struct AttributeInit { enum class Type { - Default, + /** #AttributeInitConstruct. */ + Construct, + /** #AttributeInitDefaultValue. */ + DefaultValue, + /** #AttributeInitVArray. */ VArray, + /** #AttributeInitMoveArray. */ MoveArray, }; Type type; @@ -84,11 +89,20 @@ struct AttributeInit { }; /** - * Create an attribute using the default value for the data type. - * The default values may depend on the attribute provider implementation. + * Default construct new attribute values. Does nothing for trivial types. This should be used + * if all attribute element values will be set by the caller after creating the attribute. */ -struct AttributeInitDefault : public AttributeInit { - AttributeInitDefault() : AttributeInit(Type::Default) +struct AttributeInitConstruct : public AttributeInit { + AttributeInitConstruct() : AttributeInit(Type::Construct) + { + } +}; + +/** + * Create an attribute using the default value for the data type (almost always "zero"). + */ +struct AttributeInitDefaultValue : public AttributeInit { + AttributeInitDefaultValue() : AttributeInit(Type::DefaultValue) { } }; @@ -96,14 +110,11 @@ struct AttributeInitDefault : public AttributeInit { /** * Create an attribute by copying data from an existing virtual array. The virtual array * must have the same type as the newly created attribute. - * - * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - blender::GVArray varray; + GVArray varray; - AttributeInitVArray(blender::GVArray varray) - : AttributeInit(Type::VArray), varray(std::move(varray)) + AttributeInitVArray(GVArray varray) : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -119,10 +130,10 @@ struct AttributeInitVArray : public AttributeInit { * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it * can't be used directly, and that is generally how Blender expects custom data to be allocated. */ -struct AttributeInitMove : public AttributeInit { +struct AttributeInitMoveArray : public AttributeInit { void *data = nullptr; - AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + AttributeInitMoveArray(void *data) : AttributeInit(Type::MoveArray), data(data) { } }; @@ -579,7 +590,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but returns a type that makes it easier to work with the attribute as a span. @@ -590,7 +601,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but should be used when the type is known at compile time. @@ -599,7 +610,7 @@ class MutableAttributeAccessor : public AttributeAccessor { AttributeWriter lookup_or_add_for_write( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { const CPPType &cpp_type = CPPType::get(); const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type); @@ -613,7 +624,7 @@ class MutableAttributeAccessor : public AttributeAccessor { SpanAttributeWriter lookup_or_add_for_write_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { AttributeWriter attribute = this->lookup_or_add_for_write( attribute_id, domain, initializer); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 3db75fff12c..44a4f4b5395 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -55,14 +55,17 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; typedef enum eCDAllocType { /** Use the data pointer. */ CD_ASSIGN = 0, - /** Allocate blank memory. */ - CD_CALLOC = 1, - /** Allocate and set to default. */ - CD_DEFAULT = 2, + /** Allocate and set to default, which is usually just zeroed memory. */ + CD_SET_DEFAULT = 2, /** Use data pointers, set layer flag NOFREE. */ CD_REFERENCE = 3, /** Do a full copy of all layers, only allowed if source has same number of elements. */ CD_DUPLICATE = 4, + /** + * Default construct new layer values. Does nothing for trivial types. This should be used + * if all layer values will be set by the caller after creating the layer. + */ + CD_CONSTRUCT = 5, } eCDAllocType; #define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type)) diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 2ce5863c176..3afdbccb1f4 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -95,7 +95,7 @@ static MVert *dm_getVertArray(DerivedMesh *dm) if (!mvert) { mvert = (MVert *)CustomData_add_layer( - &dm->vertData, CD_MVERT, CD_CALLOC, nullptr, dm->getNumVerts(dm)); + &dm->vertData, CD_MVERT, CD_SET_DEFAULT, nullptr, dm->getNumVerts(dm)); CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY); dm->copyVertArray(dm, mvert); } @@ -109,7 +109,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) if (!medge) { medge = (MEdge *)CustomData_add_layer( - &dm->edgeData, CD_MEDGE, CD_CALLOC, nullptr, dm->getNumEdges(dm)); + &dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, dm->getNumEdges(dm)); CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); dm->copyEdgeArray(dm, medge); } @@ -123,7 +123,7 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm) if (!mloop) { mloop = (MLoop *)CustomData_add_layer( - &dm->loopData, CD_MLOOP, CD_CALLOC, nullptr, dm->getNumLoops(dm)); + &dm->loopData, CD_MLOOP, CD_SET_DEFAULT, nullptr, dm->getNumLoops(dm)); CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY); dm->copyLoopArray(dm, mloop); } @@ -137,7 +137,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) if (!mpoly) { mpoly = (MPoly *)CustomData_add_layer( - &dm->polyData, CD_MPOLY, CD_CALLOC, nullptr, dm->getNumPolys(dm)); + &dm->polyData, CD_MPOLY, CD_SET_DEFAULT, nullptr, dm->getNumPolys(dm)); CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY); dm->copyPolyArray(dm, mpoly); } @@ -284,11 +284,11 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_CALLOC, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_CALLOC, numPolys); + CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->cd_flag = source->cd_flag; @@ -584,7 +584,7 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc } if (!(layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer))) { - CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, layer, CD_SET_DEFAULT, nullptr, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer); @@ -826,7 +826,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } float3 *rest_positions = static_cast(CustomData_add_layer_named(&mesh_final->vdata, CD_PROP_FLOAT3, - CD_DEFAULT, + CD_SET_DEFAULT, nullptr, mesh_final->totvert, "rest_position")); @@ -1007,11 +1007,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ @@ -1047,8 +1047,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* add an origspace layer if needed */ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1510,8 +1513,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index ccaa6e56f08..394f9e738d4 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -247,7 +247,7 @@ CustomDataLayer *BKE_id_attribute_new( return nullptr; } - attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefault()); + attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefaultValue()); const int index = CustomData_get_named_layer_index(customdata, type, uniquename); return (index == -1) ? nullptr : &(customdata->layers[index]); diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 313e6a172ac..aed55c5db45 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -160,12 +160,19 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data const AttributeInit &initializer) { switch (initializer.type) { - case AttributeInit::Type::Default: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + case AttributeInit::Type::Construct: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); + return data != nullptr; + } + case AttributeInit::Type::DefaultValue: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num); return data != nullptr; } case AttributeInit::Type::VArray: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); if (data == nullptr) { return false; } @@ -174,7 +181,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data return true; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; + void *source_data = static_cast(initializer).data; void *data = CustomData_add_layer( &custom_data, data_type, CD_ASSIGN, source_data, domain_num); if (data == nullptr) { @@ -215,14 +222,19 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr { const int old_layer_num = custom_data.totlayer; switch (initializer.type) { - case AttributeInit::Type::Default: { + case AttributeInit::Type::Construct: { + add_generic_custom_data_layer( + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); + break; + } + case AttributeInit::Type::DefaultValue: { add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num, attribute_id); break; } case AttributeInit::Type::VArray: { void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); if (data != nullptr) { const GVArray &varray = static_cast(initializer).varray; varray.materialize_to_uninitialized(varray.index_range(), data); @@ -230,7 +242,7 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr break; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; + void *source_data = static_cast(initializer).data; void *data = add_generic_custom_data_layer( custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id); if (source_data != nullptr && data == nullptr) { @@ -722,7 +734,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, const eCustomDataType data_type) { void *result = add_generic_custom_data_layer( - data, data_type, CD_DEFAULT, nullptr, size_, attribute_id); + data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id); return result != nullptr; } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index fe9f6775995..618ff8fa97a 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -58,7 +58,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named(&this->point_data, CD_PROP_FLOAT3, - CD_DEFAULT, + CD_SET_DEFAULT, nullptr, this->point_num, ATTR_POSITION.c_str()); @@ -222,7 +222,7 @@ static MutableSpan get_mutable_attribute(CurvesGeometry &curves, return {data, num}; } data = (T *)CustomData_add_layer_named( - &custom_data, type, CD_CALLOC, nullptr, num, name.c_str()); + &custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str()); MutableSpan span = {data, num}; if (num > 0 && span.first() != default_value) { span.fill(default_value); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 1f70ab587bf..447921b6d84 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -154,9 +154,15 @@ struct LayerTypeInfo { void (*swap)(void *data, const int *corner_indices); /** - * a function to set a layer's data to default values. if null, the - * default is assumed to be all zeros */ - void (*set_default)(void *data, int count); + * Set values to the type's default. If undefined, the default is assumed to be zeroes. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*set_default_value)(void *data, int count); + /** + * Construct and fill a valid value for the type. Necessary for non-trivial types. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*construct)(void *data, int count); /** A function used by mesh validating code, must ensures passed item has valid data. */ cd_validate validate; @@ -312,6 +318,11 @@ static void layerInterp_mdeformvert(const void **sources, } } +static void layerConstruct_mdeformvert(void *data, const int count) +{ + memset(data, 0, sizeof(MDeformVert) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -497,11 +508,6 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool /** \name Callbacks for (#MIntProperty, #CD_PROP_INT32) * \{ */ -static void layerCopy_propInt(const void *source, void *dest, const int count) -{ - memcpy(dest, source, sizeof(MIntProperty) * count); -} - static void layerInterp_propInt(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -671,6 +677,11 @@ static void layerFree_mdisps(void *data, const int count, const int UNUSED(size) } } +static void layerConstruct_mdisps(void *data, const int count) +{ + memset(data, 0, sizeof(MDisps) * count); +} + static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count) { MDisps *d = static_cast(data); @@ -803,6 +814,11 @@ static void layerFree_grid_paint_mask(void *data, const int count, const int UNU } } +static void layerConstruct_grid_paint_mask(void *data, const int count) +{ + memset(data, 0, sizeof(GridPaintMask) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1645,30 +1661,23 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_mdeformvert, layerInterp_mdeformvert, nullptr, + layerConstruct_mdeformvert, nullptr}, /* 3: CD_MEDGE */ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 4: CD_MFACE */ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 5: CD_MTFACE */ - {sizeof(MTFace), "MTFace", 1, - N_("UVMap"), layerCopy_tface, nullptr, - layerInterp_tface, layerSwap_tface, layerDefault_tface, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, layerMaxNum_tface}, - /* 6: CD_MCOL */ - /* 4 MCol structs per face */ - {sizeof(MCol[4]), - "MCol", - 4, - N_("Col"), + {sizeof(MTFace), + "MTFace", + 1, + N_("UVMap"), + layerCopy_tface, nullptr, + layerInterp_tface, + layerSwap_tface, nullptr, - layerInterp_mcol, - layerSwap_mcol, - layerDefault_mcol, + layerDefault_tface, nullptr, nullptr, nullptr, @@ -1679,7 +1688,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, - layerMaxNum_mloopcol}, + layerMaxNum_tface}, + /* 6: CD_MCOL */ + /* 4 MCol structs per face */ + {sizeof(MCol[4]), "MCol", 4, + N_("Col"), nullptr, nullptr, + layerInterp_mcol, layerSwap_mcol, layerDefault_mcol, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, layerMaxNum_mloopcol}, /* 7: CD_ORIGINDEX */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex}, /* 8: CD_NORMAL */ @@ -1699,6 +1717,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerCopyValue_normal}, /* 9: CD_FACEMAP */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr}, @@ -1712,13 +1731,14 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propFloat, nullptr, nullptr, + nullptr, layerValidate_propFloat}, /* 11: CD_PROP_INT32 */ {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), - layerCopy_propInt, + nullptr, nullptr, layerInterp_propInt, nullptr}, @@ -1757,6 +1777,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_mloopuv, nullptr, nullptr, + nullptr, layerValidate_mloopuv, layerEqual_mloopuv, layerMultiply_mloopuv, @@ -1779,6 +1800,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1801,6 +1823,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerSwap_mdisps, nullptr, + layerConstruct_mdisps, nullptr, nullptr, nullptr, @@ -1870,6 +1893,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace, @@ -1887,6 +1911,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1914,7 +1939,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_grid_paint_mask, nullptr, nullptr, - nullptr}, + nullptr, + layerConstruct_grid_paint_mask}, /* 36: CD_MVERT_SKIN */ {sizeof(MVertSkin), "MVertSkin", @@ -1972,6 +1998,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_propcol, nullptr, + nullptr, layerEqual_propcol, layerMultiply_propcol, layerInitMinMax_propcol, @@ -1992,6 +2019,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat3, nullptr, nullptr, + nullptr, layerValidate_propfloat3, nullptr, layerMultiply_propfloat3, @@ -2007,6 +2035,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat2, nullptr, nullptr, + nullptr, layerValidate_propfloat2, nullptr, layerMultiply_propfloat2, @@ -2765,48 +2794,60 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, const LayerTypeInfo *typeInfo = layerType_getInfo(type); int flag = 0; - /* Passing a layer-data to copy from with an alloctype that won't copy is - * most likely a bug */ - BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); - if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; } void *newlayerdata = nullptr; - if (ELEM(alloctype, CD_ASSIGN, CD_REFERENCE)) { - newlayerdata = layerdata; - } - else if (totelem > 0 && typeInfo->size > 0) { - if (alloctype == CD_DUPLICATE && layerdata) { - newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - else { - newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - - if (!newlayerdata) { - return nullptr; - } - } - - if (alloctype == CD_DUPLICATE && layerdata) { - if (totelem > 0) { - if (typeInfo->copy) { - typeInfo->copy(layerdata, newlayerdata, totelem); + switch (alloctype) { + case CD_SET_DEFAULT: + if (totelem > 0) { + if (typeInfo->set_default_value) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + typeInfo->set_default_value(newlayerdata, totelem); + } + else { + newlayerdata = MEM_calloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + } + } + break; + case CD_CONSTRUCT: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->construct) { + typeInfo->construct(newlayerdata, totelem); + } + } + break; + case CD_ASSIGN: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; } else { - memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size); + MEM_SAFE_FREE(layerdata); } - } - } - else if (alloctype == CD_DEFAULT) { - if (typeInfo->set_default) { - typeInfo->set_default(newlayerdata, totelem); - } - } - else if (alloctype == CD_REFERENCE) { - flag |= CD_FLAG_NOFREE; + break; + case CD_REFERENCE: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; + flag |= CD_FLAG_NOFREE; + } + break; + case CD_DUPLICATE: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->copy) { + typeInfo->copy(layerdata, newlayerdata, totelem); + } + else { + BLI_assert(layerdata != nullptr); + BLI_assert(newlayerdata != nullptr); + memcpy(newlayerdata, layerdata, totelem * typeInfo->size); + } + } + break; } int index = data->totlayer; @@ -3850,8 +3891,8 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int offset = data->layers[n].offset; const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); - if (typeInfo->set_default) { - typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1); } else { memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size); @@ -4558,8 +4599,8 @@ static bool CustomData_layer_ensure_data_exists(CustomDataLayer *layer, size_t c case CD_MLOOPUV: /* See T90620. */ layer->data = MEM_calloc_arrayN(count, typeInfo->size, layerType_getName(layer->type)); BLI_assert(layer->data); - if (typeInfo->set_default) { - typeInfo->set_default(layer->data, count); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(layer->data, count); } return true; break; diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index be686635d3e..02b5175f65f 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -280,7 +280,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (do_loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); + loop_nors_dst = CustomData_add_layer( + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { @@ -333,7 +334,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src), if (!custom_nors_dst) { custom_nors_dst = CustomData_add_layer( - ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst); + ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); } /* Note loop_nors_dst contains our custom normals as transferred from source... */ @@ -561,7 +562,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if (use_create) { /* Create as much data layers as necessary! */ for (; idx_dst < idx_src; idx_dst++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } else { @@ -622,7 +623,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (use_create) { - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named( + cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } else { @@ -710,7 +712,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else if (use_dupref_dst && r_map) { /* If dest is a evaluated mesh (from modifier), @@ -763,7 +765,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else { /* If dest is a evaluated mesh (from modifier), @@ -786,7 +788,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, } /* Create as much data layers as necessary! */ for (; num <= idx_dst; num++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } /* If dest is a evaluated mesh (from modifier), @@ -805,7 +807,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } /* If dest is a evaluated mesh (from modifier), diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index ebe06fa85eb..d904744995d 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -1243,7 +1243,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * Again, use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } while (idx_src--) { @@ -1303,7 +1304,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, @@ -1442,7 +1444,8 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 423e76fce8c..8a41b2294f5 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1944,7 +1944,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name); @@ -1957,7 +1957,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name2); @@ -1988,7 +1988,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * /* apply weights into a vertex group, if doesn't exists add a new layer */ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, sData->total_points); /* Make the dvert layer easily accessible from the mesh data. */ result->dvert = dvert; } diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index 0a3107eee24..ec608f79e66 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -304,7 +304,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 22f105af0f1..56a7e38b2fc 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -547,7 +547,8 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, const Span splines) { switch (initializer.type) { - case AttributeInit::Type::Default: + case AttributeInit::Type::Construct: + case AttributeInit::Type::DefaultValue: /* This function shouldn't be called in this case, since there * is no need to copy anything to the new custom data array. */ BLI_assert_unreachable(); @@ -560,7 +561,7 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, total_num += spline->size(); } return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast(initializer).data, + static_cast(initializer).data, total_num)); } BLI_assert_unreachable(); @@ -580,7 +581,7 @@ static bool create_point_attribute(CurveEval *curve, /* First check the one case that allows us to avoid copying the input data. */ if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) { - void *source_data = static_cast(initializer).data; + void *source_data = static_cast(initializer).data; if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) { MEM_freeN(source_data); return false; @@ -600,7 +601,7 @@ static bool create_point_attribute(CurveEval *curve, } /* With a default initializer type, we can keep the values at their initial values. */ - if (initializer.type == AttributeInit::Type::Default) { + if (ELEM(initializer.type, AttributeInit::Type::DefaultValue, AttributeInit::Type::Construct)) { return true; } @@ -616,7 +617,7 @@ static bool create_point_attribute(CurveEval *curve, write_attribute.finish(); if (initializer.type == AttributeInit::Type::MoveArray) { - MEM_freeN(static_cast(initializer).data); + MEM_freeN(static_cast(initializer).data); } return true; diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 61f5a5f315f..bfa11b74782 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1444,7 +1444,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); mesh->totvert = (int)process.curvertex; - MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_DEFAULT, NULL, mesh->totvert); + MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CONSTRUCT, NULL, mesh->totvert); for (int i = 0; i < mesh->totvert; i++) { copy_v3_v3(mvert[i].co, process.co[i]); mvert->bweight = 0; @@ -1453,8 +1453,9 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) MEM_freeN(process.co); mesh->totpoly = (int)process.curindex; - MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_DEFAULT, NULL, mesh->totpoly); - MLoop *mloop = CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_DEFAULT, NULL, mesh->totpoly * 4); + MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, NULL, mesh->totpoly); + MLoop *mloop = CustomData_add_layer( + &mesh->ldata, CD_MLOOP, CD_CONSTRUCT, NULL, mesh->totpoly * 4); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0c109e6ef04..0a5eddfd319 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -822,7 +822,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { vs = (MVertSkin *)CustomData_add_layer( - &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); + &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -844,7 +844,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -987,20 +987,20 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, mesh->totface); } } @@ -1097,12 +1097,12 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->cd_flag = me_src->cd_flag; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len); + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len); + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1203,7 +1203,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) if (CustomData_has_layer(&data, CD_ORIGINDEX)) { return; } - int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_DEFAULT, nullptr, size); + int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, size); range_vn_i(indices, size, 0); } @@ -1882,7 +1882,7 @@ static float (*ensure_corner_normal_layer(Mesh &mesh))[3] } else { r_loopnors = (float(*)[3])CustomData_add_layer( - &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop); + &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, mesh.totloop); CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } return r_loopnors; diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index a1ef2d2e6b5..903198e249a 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -663,15 +663,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { CustomData_merge( - &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_DEFAULT, target->totvert); + &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { CustomData_merge( - &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_DEFAULT, target->totloop); + &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { CustomData_merge( - &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_DEFAULT, target->totpoly); + &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } } @@ -682,7 +682,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { CustomData_merge( - &me->edata, &target->edata, CD_MASK_MESH.emask, CD_DEFAULT, target->totedge); + &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } } diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 3806ea76cfe..cb72e09af16 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -195,7 +195,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba MPoly *mpoly = polys.data(); MLoop *mloop = loops.data(); MLoopUV *mloopuv = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, "UVMap")); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, "UVMap")); /* verts and faces */ vertcount = 0; @@ -676,7 +676,8 @@ void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me) &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint); /* Convert the Position attribute to a mesh vertex. */ - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); CustomData_update_typemap(&me->vdata); const int layer_idx = CustomData_get_named_layer_index( diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index cc96a5e8c60..45cbf3aa28b 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -137,19 +137,19 @@ static void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int to for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { CustomData_add_layer_named( - ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { CustomData_add_layer_named( - ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MDISPS) { CustomData_add_layer_named( - ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { CustomData_add_layer_named( - ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } } } @@ -849,26 +849,27 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total) for (int i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_MLOOPUV) { CustomData_add_layer_named( - fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_MTFACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { - CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named( + fdata, CD_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_PREVIEW_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_ORIGSPACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_NORMAL) { CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TESSLOOPNORMAL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_TANGENT) { CustomData_add_layer_named( - fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TANGENT, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 2366b7526a1..f90a2e1b887 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -2054,7 +2054,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const } else { clnors = (short(*)[2])CustomData_add_layer( - &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops); + &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, numloops); } mesh_normals_loop_custom_set(mesh->mvert, diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 5313cc39646..4c6ee0ae3ee 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1352,7 +1352,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (!loop_nors_dst) { loop_nors_dst = CustomData_add_layer( - ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, numloops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 423f76407a0..c840c917eb3 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -291,7 +291,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source) } else { target_mask = (float *)CustomData_add_layer( - &target->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, target->totvert); + &target->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, target->totvert); } for (int i = 0; i < target->totvert; i++) { @@ -325,7 +325,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) } else { target_face_sets = (int *)CustomData_add_layer( - &target->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, target->totpoly); + &target->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, target->totpoly); } const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source); @@ -376,7 +376,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop; CustomData_add_layer_named( - target_cdata, layer->type, CD_CALLOC, nullptr, elem_num, layer->name); + target_cdata, layer->type, CD_SET_DEFAULT, nullptr, elem_num, layer->name); layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name); } diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index 1772419e1f3..497f9ff3cbd 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -452,7 +452,8 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, { if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) { - CustomData_add_layer_named(tan_data, CD_TANGENT, CD_CALLOC, NULL, numLoopData, layer_name); + CustomData_add_layer_named( + tan_data, CD_TANGENT, CD_SET_DEFAULT, NULL, numLoopData, layer_name); } } @@ -581,7 +582,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 5bcbdb399e4..95a2eaec1aa 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -1548,8 +1548,8 @@ void BKE_mesh_calc_edges_tessface(Mesh *mesh) /* write new edges into a temporary CustomData */ CustomData edgeData; CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, nullptr, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, numEdges); MEdge *med = (MEdge *)CustomData_get_layer(&edgeData, CD_MEDGE); int *index = (int *)CustomData_get_layer(&edgeData, CD_ORIGINDEX); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 63945f9ed42..5c382a4e864 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -960,7 +960,7 @@ static void multiresModifier_disp_run( if (!mdisps) { if (op == CALC_DISPLACEMENTS) { - mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); + mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, me->totloop); } else { return; @@ -1487,7 +1487,7 @@ void multires_ensure_external_read(struct Mesh *mesh, int top_level) MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); if (mdisps == NULL) { - mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); + mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, mesh->totloop); } const int totloop = mesh->totloop; diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index b50a0787fe3..17e4860ab1b 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -181,7 +181,8 @@ void multiresModifier_subdivide_to_level(struct Object *object, * are allocated at a proper level and return. */ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c index 9fa3e93a1e6..cecb57f4de4 100644 --- a/source/blender/blenkernel/intern/multires_reshape_subdivide.c +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -68,7 +68,8 @@ void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } if (new_top_level == 1) { diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index cad680ecedd..27a1f84579e 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -901,10 +901,10 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) multires_unsubdivide_free_original_datalayers(mesh); int *l_index = CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totloop, lname); + &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totloop, lname); int *v_index = CustomData_add_layer_named( - &mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, vname); + &mesh->vdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totvert, vname); /* Initialize these data-layer with the indices in the current mesh. */ for (int i = 0; i < mesh->totloop; i++) { @@ -1174,7 +1174,7 @@ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideC CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); } MDisps *mdisps = CustomData_add_layer( - &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop); + &base_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, base_mesh->totloop); const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); const int totloop = base_mesh->totloop; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2a85811e2e8..c90c83074bd 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1665,7 +1665,7 @@ static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_t const int layer_index = CustomData_get_layer_index(data_destination, layer_type); CustomData_free_layer(data_destination, layer_type, num_elements, layer_index); BLI_assert(!CustomData_has_layer(data_destination, layer_type)); - CustomData_add_layer(data_destination, layer_type, CD_CALLOC, nullptr, num_elements); + CustomData_add_layer(data_destination, layer_type, CD_SET_DEFAULT, nullptr, num_elements); BLI_assert(CustomData_has_layer(data_destination, layer_type)); CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements); } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 310ec7678bd..08d98775e34 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -115,7 +115,8 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) { if (GS(id->name) == ID_ME) { Mesh *me = (Mesh *)id; - me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); + me->dvert = CustomData_add_layer( + &me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, me->totvert); return me->dvert; } if (GS(id->name) == ID_LT) { diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index a6b0a4d96ee..1dfc47efcd5 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1835,8 +1835,8 @@ static void sculpt_face_sets_ensure(Mesh *mesh) return; } - int *new_face_sets = static_cast( - CustomData_add_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); + int *new_face_sets = static_cast(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -1917,7 +1917,7 @@ void BKE_sculpt_color_layer_create_if_needed(Object *object) return; } - CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, orig_me->totvert); + CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_CONSTRUCT, nullptr, orig_me->totvert); CustomDataLayer *layer = orig_me->vdata.layers + CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR); @@ -1958,8 +1958,8 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) int gridarea = gridsize * gridsize; int i, j; - gmask = static_cast( - CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, nullptr, me->totloop)); + gmask = static_cast(CustomData_add_layer( + &me->ldata, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totloop)); for (i = 0; i < me->totloop; i++) { GridPaintMask *gpm = &gmask[i]; @@ -2002,7 +2002,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) /* create vertex paint mask layer if there isn't one already */ if (!paint_mask) { - CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); ret |= SCULPT_MASK_LAYER_CALC_VERT; } @@ -2078,7 +2078,7 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) else { initialize_new_face_sets = true; int *new_face_sets = static_cast(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index abecb9f8d9d..254cea0bd8b 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3322,7 +3322,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim, mesh = *r_mesh; if (!mesh) { *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0); - CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); } mvert = mesh->mvert; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 726c022ba2c..24f3097f9e3 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -3233,7 +3233,7 @@ bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) return pbvh->hide_vert; } pbvh->hide_vert = (bool *)CustomData_add_layer_named( - &pbvh->mesh->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, pbvh->mesh->totvert, ".hide_vert"); + &pbvh->mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, pbvh->mesh->totvert, ".hide_vert"); return pbvh->hide_vert; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 426ad797cef..306141cffb7 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -64,7 +64,7 @@ static void pointcloud_init_data(ID *id) CustomData_reset(&pointcloud->pdata); CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_POSITION); @@ -231,7 +231,7 @@ void *BKE_pointcloud_add_default(Main *bmain, const char *name) CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_RADIUS); @@ -251,7 +251,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_RADIUS); @@ -336,7 +336,7 @@ PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int to pointcloud_dst->totpoint = totpoint; CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint); + &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_SET_DEFAULT, totpoint); return pointcloud_dst; } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index e026a013498..da22ee6fd47 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -186,7 +186,7 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, CD_MASK_EVERYTHING.vmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; @@ -321,7 +321,7 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->ldata, &loop_interpolation->loop_data_storage, CD_MASK_EVERYTHING.lmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f19aac68d35..9737801291e 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1248,7 +1248,7 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); origindex = CustomData_add_layer( - &dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numVertData); + &dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numVertData); totorig = ccgSubSurf_getNumVerts(ss); totnone = dm->numVertData - totorig; @@ -1287,7 +1287,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numEdgeData); + &dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numEdgeData); totedge = ccgSubSurf_getNumEdges(ss); totorig = totedge * (edgeSize - 1); @@ -1330,7 +1330,7 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numPolyData); + &dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numPolyData); totface = ccgSubSurf_getNumFaces(ss); diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c index 3b73a81012d..ada2d27f9b2 100644 --- a/source/blender/blenlib/intern/BLI_memarena.c +++ b/source/blender/blenlib/intern/BLI_memarena.c @@ -158,6 +158,7 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size) BLI_assert(ma->use_calloc == false); ptr = BLI_memarena_alloc(ma, size); + BLI_assert(ptr != NULL); memset(ptr, 0, size); return ptr; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 75cc333e4b5..20659daabd6 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -291,8 +291,8 @@ static void customdata_version_242(Mesh *me) MEM_freeN(me->mcol); } - me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); - me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface); + me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_SET_DEFAULT, NULL, me->totface); + me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_SET_DEFAULT, NULL, me->totface); mtf = me->mtface; mcol = me->mcol; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 0ee5545527b..757d006b04d 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -513,23 +513,23 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, const Mesh *me_src = me_src_array[i]; if (i == 0) { CustomData_copy_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); } else { CustomData_merge_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); } cd_flag |= me_src->cd_flag; @@ -558,10 +558,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); @@ -596,7 +596,7 @@ void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, for (int l = 0; l < src->totlayer; l++) { CustomData_add_layer_named( - dst, src->layers[l].type, CD_CALLOC, NULL, 0, src->layers[l].name); + dst, src->layers[l].type, CD_SET_DEFAULT, NULL, 0, src->layers[l].name); } CustomData_bmesh_init_pool(dst, size, htypes[i]); } diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 0c3db31dd1f..b7028dee5e1 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -846,7 +846,7 @@ void BM_data_layer_add(BMesh *bm, CustomData *data, int type) /* the pool is now owned by olddata and must not be shared */ data->pool = NULL; - CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0); + CustomData_add_layer(data, type, CD_SET_DEFAULT, NULL, 0); update_data_blocks(bm, &olddata, data); if (olddata.layers) { @@ -864,7 +864,7 @@ void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char * /* the pool is now owned by olddata and must not be shared */ data->pool = NULL; - CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name); + CustomData_add_layer_named(data, type, CD_SET_DEFAULT, NULL, 0, name); update_data_blocks(bm, &olddata, data); if (olddata.layers) { diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index b9c004b5392..4e0e27cd051 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -217,10 +217,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (!me || !me->totvert) { if (me && is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); @@ -236,16 +236,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, 0); + CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, bm, BM_VERT); - CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_CALLOC, bm, BM_EDGE); - CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, bm, BM_LOOP); - CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, bm, BM_FACE); + CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); + CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); } /* -------------------------------------------------------------------- */ @@ -1016,10 +1016,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); + CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } MVert *mvert = bm->totvert ? (MVert *)MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : @@ -1271,10 +1271,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * me->totloop = bm->totloop; me->totpoly = bm->totface; - CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, bm->totface); + CustomData_add_layer(&me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, bm->totvert); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, bm->totedge); + CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, bm->totloop); + CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, bm->totface); /* Don't process shape-keys, we only feed them through the modifier stack as needed, * e.g. for applying modifiers or the like. */ @@ -1283,10 +1283,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * CustomData_MeshMasks_update(&mask, cd_mask_extra); } mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); + CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); BKE_mesh_update_customdata_pointers(me, false); diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc index 79916253207..6556f62443a 100644 --- a/source/blender/editors/curves/intern/curves_add.cc +++ b/source/blender/editors/curves/intern/curves_add.cc @@ -104,7 +104,7 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi MutableSpan positions = curves.positions_for_write(); float *radius_data = (float *)CustomData_add_layer_named( - &curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_num, "radius"); + &curves.point_data, CD_PROP_FLOAT, CD_SET_DEFAULT, nullptr, curves.point_num, "radius"); MutableSpan radii{radius_data, curves.points_num()}; for (const int i : offsets.index_range()) { diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index aec22f0f3ae..2dcb7aa438f 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -305,7 +305,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); attributes.remove(name); - attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMove(new_data)); + attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMoveArray(new_data)); break; } case ConvertAttributeMode::UVMap: { @@ -660,7 +660,7 @@ bool ED_geometry_attribute_convert(Mesh *mesh, void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); attributes.remove(name); - attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMove(new_data)); + attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMoveArray(new_data)); int *active_index = BKE_id_attributes_active_index_p(&mesh->id); if (*active_index > 0) { diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index ea29d07feaf..e394f8a7251 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -286,7 +286,8 @@ int ED_mesh_uv_add( is_init = true; } else { - CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, name); + CustomData_add_layer_named( + &me->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, me->totloop, name); } if (active_set || layernum_dst == 0) { @@ -409,7 +410,7 @@ int ED_mesh_color_add( } else { CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name); } if (active_set || layernum == 0) { @@ -432,7 +433,7 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name) if (!layer) { CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name); layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR); BKE_id_attributes_active_color_set(&me->id, layer); @@ -500,7 +501,7 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool do_init, Rep } else { CustomData_add_layer_named( - &me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name); + &me->vdata, CD_PROP_COLOR, CD_SET_DEFAULT, nullptr, me->totvert, name); } if (layernum == 0) { @@ -790,7 +791,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator me->smoothresh); } - CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, nullptr, me->totloop); + CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, me->totloop); } DEG_id_tag_update(&me->id, 0); @@ -875,11 +876,11 @@ static void mesh_add_verts(Mesh *mesh, int len) int totvert = mesh->totvert + len; CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_has_layer(&vdata, CD_MVERT)) { - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert); + CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert); } CustomData_free(&mesh->vdata, mesh->totvert); @@ -913,11 +914,11 @@ static void mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); } CustomData_free(&mesh->edata, mesh->totedge); @@ -947,11 +948,11 @@ static void mesh_add_loops(Mesh *mesh, int len) totloop = mesh->totloop + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop); + CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); } BKE_mesh_runtime_clear_cache(mesh); @@ -976,11 +977,11 @@ static void mesh_add_polys(Mesh *mesh, int len) totpoly = mesh->totpoly + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly); + CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); } CustomData_free(&mesh->pdata, mesh->totpoly); diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index b1004b23a21..e9a34cf95cb 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -100,7 +100,7 @@ static void join_mesh_single(Depsgraph *depsgraph, ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag; /* standard data */ - CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); /* vertex groups */ @@ -199,7 +199,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } if (me->totedge) { - CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, medge++) { @@ -220,7 +220,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); for (a = 0; a < me->totloop; a++, mloop++) { @@ -244,7 +244,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); for (a = 0; a < me->totpoly; a++, mpoly++) { @@ -571,10 +571,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) CustomData_reset(&ldata); CustomData_reset(&pdata); - mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert); - medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); - mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop); - mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly); + mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert); + medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); + mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); + mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); vertofs = 0; edgeofs = 0; diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index dddf5e40e87..4364375a4e3 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -53,7 +53,7 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum) /* if there's is no facemap layer then create one */ if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) { - facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, NULL, me->totpoly); } facemap[facenum] = fmap_nr; diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index f6e97f81cb6..085ef59ac21 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -586,9 +586,11 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports), me->totvert = verts_num; me->totedge = edges_num; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, verts_num); - me->medge = (MEdge *)CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, edges_num); - me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, nullptr, 0); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, verts_num); + me->medge = (MEdge *)CustomData_add_layer( + &me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, edges_num); + me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, 0); MVert *mvert = me->mvert; MEdge *medge = me->medge; @@ -2642,7 +2644,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, MVert *mvert = me_eval_deform->mvert; /* add vertex weights to original mesh */ - CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, me->totvert); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); Object *arm_ob = BKE_object_add(bmain, view_layer, OB_ARMATURE, nullptr); diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index a7aa29853e6..c1289364fb2 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -81,7 +81,7 @@ static void partialvis_update_mesh(Object *ob, bool *hide_vert = CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"); if (hide_vert == NULL) { hide_vert = CustomData_add_layer_named( - &me->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, me->totvert, ".hide_vert"); + &me->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, me->totvert, ".hide_vert"); } SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 433823c8373..000b69cc2ba 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -218,7 +218,7 @@ static void SCULPT_dynamic_topology_disable_ex( /* Reset Face Sets as they are no longer valid. */ if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly); + CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, NULL, me->totpoly); } ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); for (int i = 0; i < me->totpoly; i++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 58d62fb2165..b0dcef61c31 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1683,7 +1683,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; int totelem = attr->domain == ATTR_DOMAIN_POINT ? me->totvert : me->totloop; - CustomData_add_layer_named(cdata, attr->type, CD_DEFAULT, NULL, totelem, attr->name); + CustomData_add_layer_named(cdata, attr->type, CD_SET_DEFAULT, NULL, totelem, attr->name); layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 68d6be485a3..87a2d1620aa 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -577,13 +577,13 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) mesh->totcol = group->materials.size(); mesh->mvert = (MVert *)CustomData_add_layer( - &mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + &mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); mesh->medge = (MEdge *)CustomData_add_layer( - &mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + &mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); mesh->mpoly = (MPoly *)CustomData_add_layer( - &mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); mesh->mloop = (MLoop *)CustomData_add_layer( - &mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + &mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); MVert *vertices = mesh->mvert; MEdge *edges = mesh->medge; @@ -594,14 +594,14 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) if (hasTex) { // First UV layer CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, uvNames[0]); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[0]); CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0); BKE_mesh_update_customdata_pointers(mesh, true); loopsuv[0] = mesh->mloopuv; // Second UV layer CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, uvNames[1]); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[1]); CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1); BKE_mesh_update_customdata_pointers(mesh, true); loopsuv[1] = mesh->mloopuv; @@ -609,9 +609,9 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) // colors and transparency (the latter represented by grayscale colors) MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Color"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Color"); MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Alpha"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Alpha"); mesh->mloopcol = colors; mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList"); diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 2820a128072..644990afb35 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -540,7 +540,7 @@ void read_generated_coordinates(const ICompoundProperty &prop, cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO); } else { - cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert); + cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_SET_DEFAULT, nullptr, totvert); } float(*orcodata)[3] = static_cast(cd_data); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index bacc1f06599..e18770f2bef 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -391,7 +391,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) /* Create a new layer. */ int numloops = mesh->totloop; cd_ptr = CustomData_add_layer_named( - &mesh->ldata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); + &mesh->ldata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -890,7 +890,7 @@ static void read_vertex_creases(Mesh *mesh, } float *vertex_crease_data = (float *)CustomData_add_layer( - &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert); + &mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert); const int totvert = mesh->totvert; for (int i = 0, v = indices->size(); i < v; ++i) { diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 9fbba1b97fb..34792fd6bb4 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -341,7 +341,8 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) } me->totvert = pos.getFloatValues()->getCount() / stride; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); MVert *mvert; int i; @@ -449,9 +450,9 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) me->totpoly = total_poly_count; me->totloop = total_loop_count; me->mpoly = (MPoly *)CustomData_add_layer( - &me->pdata, CD_MPOLY, CD_CALLOC, nullptr, me->totpoly); + &me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly); me->mloop = (MLoop *)CustomData_add_layer( - &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, me->totloop); + &me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop); unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount(); for (int i = 0; i < totuvset; i++) { @@ -468,7 +469,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::String &uvname = info->mName; /* Allocate space for UV_data */ CustomData_add_layer_named( - &me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, uvname.c_str()); + &me->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, me->totloop, uvname.c_str()); } /* activate the first uv map */ me->mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0); @@ -481,7 +482,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) collada_mesh->getColors().getInputInfosArray()[i]; COLLADAFW::String colname = extract_vcolname(info->mName); CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, colname.c_str()); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, colname.c_str()); } me->mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_PROP_BYTE_COLOR, 0); } @@ -546,11 +547,11 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); } CustomData_free(&mesh->edata, mesh->totedge); diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index b9ed441f0d9..7686bfa1247 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -77,7 +77,7 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->totvert = verts_.size(); mesh->mvert = static_cast( - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert)); for (int i = 0; i < mesh->totvert; i++) { copy_v3_v3(mesh->mvert[i].co, verts_[i]); } @@ -85,9 +85,9 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->totpoly = tris_.size(); mesh->totloop = tris_.size() * 3; mesh->mpoly = static_cast( - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly)); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly)); mesh->mloop = static_cast( - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop)); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop)); threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { for (const int i : tris_range) { diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 103bb0d0cef..94ff24421e2 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -207,7 +207,8 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type /* Create a new layer. */ numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); + cd_ptr = CustomData_add_layer_named( + loopdata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -576,7 +577,7 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim } float *creases = static_cast( - CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert)); for (size_t i = 0; i < corner_indices.size(); i++) { creases[corner_indices[i]] = corner_sharpnesses[i]; 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 a570b374231..2a0676b72ff 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -181,7 +181,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) const int64_t total_verts = mesh_geometry_.get_vertex_count(); if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) { mesh->dvert = static_cast( - CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts)); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, total_verts)); } const int64_t tot_face_elems{mesh->totpoly}; @@ -262,7 +262,7 @@ void MeshFromGeometry::create_uv_verts(Mesh *mesh) return; } MLoopUV *mluv_dst = static_cast(CustomData_add_layer( - &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, mesh_geometry_.total_loops_)); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh_geometry_.total_loops_)); int tot_loop_idx = 0; for (const PolyElem &curr_face : mesh_geometry_.face_elements_) { diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index bd9360548af..35f977f41df 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -12,7 +12,7 @@ #include "BKE_scene.h" #include "BLI_listbase.h" -#include "BLI_math_base.h" +#include "BLI_math_base.hh" #include "BLI_math_vec_types.hh" #include "BLO_readfile.h" diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 2e31cab4734..994d063dbaf 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -422,7 +422,7 @@ static void rna_MeshVertex_hide_set(PointerRNA *ptr, bool value) return; } hide_vert = (bool *)CustomData_add_layer_named( - &mesh->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totvert, ".hide_vert"); + &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totvert, ".hide_vert"); } const int index = rna_MeshVertex_index_get(ptr); hide_vert[index] = value; @@ -556,7 +556,7 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value) return; } hide_poly = (bool *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totpoly, ".hide_poly"); + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, ".hide_poly"); } const int index = rna_MeshPolygon_index_get(ptr); hide_poly[index] = value; @@ -782,7 +782,7 @@ static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value) FreestyleEdge *fed = CustomData_get(&me->edata, index, CD_FREESTYLE_EDGE); if (!fed) { - fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_CALLOC, NULL, me->totedge); + fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_SET_DEFAULT, NULL, me->totedge); } if (value) { fed->flag |= FREESTYLE_EDGE_MARK; @@ -808,7 +808,7 @@ static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, bool value) FreestyleFace *ffa = CustomData_get(&me->pdata, index, CD_FREESTYLE_FACE); if (!ffa) { - ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_CALLOC, NULL, me->totpoly); + ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_SET_DEFAULT, NULL, me->totpoly); } if (value) { ffa->flag |= FREESTYLE_FACE_MARK; @@ -1291,7 +1291,7 @@ static void rna_MeshEdge_hide_set(PointerRNA *ptr, bool value) return; } hide_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totedge, ".hide_edge"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".hide_edge"); } const int index = rna_MeshEdge_index_get(ptr); hide_edge[index] = value; @@ -1734,7 +1734,8 @@ static void rna_Mesh_sculpt_vertex_color_remove(struct Mesh *me, CustomDataLayer *cdl = NULL; \ int index; \ \ - CustomData_add_layer_named(&me->cdata, cd_prop_type, CD_DEFAULT, NULL, me->countvar, name); \ + CustomData_add_layer_named( \ + &me->cdata, cd_prop_type, CD_SET_DEFAULT, NULL, me->countvar, name); \ index = CustomData_get_named_layer_index(&me->cdata, cd_prop_type, name); \ \ cdl = (index == -1) ? NULL : &(me->cdata.layers[index]); \ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 8447074a3ef..41b0d0b0bfd 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -44,7 +44,7 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, static void rna_Mesh_create_normals_split(Mesh *mesh) { if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_SET_DEFAULT, NULL, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } } @@ -64,7 +64,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char * } else { r_looptangents = CustomData_add_layer( - &mesh->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, mesh->totloop); + &mesh->ldata, CD_MLOOPTANGENT, CD_SET_DEFAULT, NULL, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 6c5baabe756..8f4a675b797 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -115,7 +115,7 @@ static void deformVerts(ModifierData *md, float(*layerorco)[3]; if (!(layerorco = CustomData_get_layer(&mesh_src->vdata, CD_CLOTH_ORCO))) { layerorco = CustomData_add_layer( - &mesh_src->vdata, CD_CLOTH_ORCO, CD_CALLOC, NULL, mesh_src->totvert); + &mesh_src->vdata, CD_CLOTH_ORCO, CD_SET_DEFAULT, NULL, mesh_src->totvert); } memcpy(layerorco, kb->data, sizeof(float[3]) * verts_num); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index d3b43176700..c571a4821b4 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -1044,7 +1044,7 @@ static void store_computed_output_attributes( if (attributes.add(store.name, store.domain, blender::bke::cpp_type_to_custom_data_type(store.data.type()), - blender::bke::AttributeInitMove(store.data.data()))) { + blender::bke::AttributeInitMoveArray(store.data.data()))) { continue; } @@ -1277,13 +1277,13 @@ static void modifyGeometry(ModifierData *md, * assumed that the output mesh does not have a mapping to the original mesh. */ Mesh &mesh = *geometry_set.get_mesh_for_write(); if (use_orig_index_verts) { - CustomData_add_layer(&mesh.vdata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totvert); + CustomData_add_layer(&mesh.vdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totvert); } if (use_orig_index_edges) { - CustomData_add_layer(&mesh.edata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totedge); + CustomData_add_layer(&mesh.edata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totedge); } if (use_orig_index_polys) { - CustomData_add_layer(&mesh.pdata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totpoly); + CustomData_add_layer(&mesh.pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totpoly); } } } diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 5a92aac6cda..9e3e06fb4dc 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -562,7 +562,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, } if (clnors == NULL) { - clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num); + clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, loops_num); } MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index ea9049200cc..c84d1b56cec 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -292,7 +292,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co /* add uvs */ if (CustomData_number_of_layers(&result->ldata, CD_MLOOPUV) < MAX_MTFACE) { gogd.mloopuvs = CustomData_add_layer( - &result->ldata, CD_MLOOPUV, CD_CALLOC, NULL, polys_num * 4); + &result->ldata, CD_MLOOPUV, CD_SET_DEFAULT, NULL, polys_num * 4); if (gogd.mloopuvs) { /* unlikely to fail */ gogd.ix = 1.0 / gogd.rx; @@ -378,12 +378,16 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes const int loops_num = result->totloop; MLoop *mloops = result->mloop; MLoopCol *mloopcols = CustomData_add_layer_named( - &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->foamlayername); + &result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, NULL, loops_num, omd->foamlayername); MLoopCol *mloopcols_spray = NULL; if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) { - mloopcols_spray = CustomData_add_layer_named( - &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->spraylayername); + mloopcols_spray = CustomData_add_layer_named(&result->ldata, + CD_PROP_BYTE_COLOR, + CD_SET_DEFAULT, + NULL, + loops_num, + omd->spraylayername); } if (mloopcols) { /* unlikely to fail */ diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 6095be48f8f..b2ebf2ffeec 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -398,7 +398,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * medge_new = result->medge; if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { - CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); + CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, (int)maxPolys); } int *origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 84795cdb2d9..b41c730024c 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1888,7 +1888,7 @@ static void skin_set_orig_indices(Mesh *mesh) int *orig, totpoly; totpoly = mesh->totpoly; - orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, totpoly); + orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, totpoly); copy_vn_i(orig, totpoly, ORIGINDEX_NONE); } diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 47277577d3e..15e8bd25997 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -994,7 +994,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (dvert == NULL) { /* Add a valid data layer! */ dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, result->totvert); } /* Ultimate security check. */ if (dvert != NULL) { diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 8a5b600974c..9205083e836 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -1981,7 +1981,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, if (dvert == NULL) { /* Add a valid data layer! */ dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, result->totvert); } result->dvert = dvert; } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 4646ba41a74..ccef867b752 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -124,7 +124,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, * (e.g. if a preceding modifier could not preserve it). */ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name); } /* make sure we're using an existing layer */ diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 039497b725b..5b5d464a710 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -609,7 +609,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * it helps when generating clnor spaces and default normals. */ const bool has_clnors = clnors != NULL; if (!clnors) { - clnors = CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num); + clnors = CustomData_add_layer( + &result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, loops_num); } MDeformVert *dvert; diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 2a509ddf220..d71813c7dd5 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -203,7 +203,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } else { /* Add a valid data layer! */ - dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, verts_num); + dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, verts_num); } /* Ultimate security check. */ if (!dvert) { diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index aa648eaec97..1d38333f15b 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -268,7 +268,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } else { /* Add a valid data layer! */ - dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, verts_num); + dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, verts_num); } /* Ultimate security check. */ if (!dvert) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index 9719833097e..c2d6f57ce8a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -123,7 +123,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, } } attributes.remove(name); - if (attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) { + if (attributes.add(name, domain, data_type, bke::AttributeInitMoveArray{buffer})) { return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index f1fb9ce5563..896364bc591 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -73,7 +73,7 @@ static void write_vertex_creases(Mesh &mesh, const VArray &crease_varray) } else { crease = static_cast( - CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh.totvert)); + CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh.totvert)); } materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert}); } -- cgit v1.2.3 From fe195f51d1a842087ba411488ec5a8b8979583ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 21:52:09 +0200 Subject: GPUStorageBuf: Add `read()` function to readback buffer data to host This is not expected to be fast. This is only for inspecting the content of the buffer for debugging or validation purpose. --- source/blender/gpu/GPU_storage_buffer.h | 7 +++++++ source/blender/gpu/intern/gpu_storage_buffer.cc | 5 +++++ source/blender/gpu/intern/gpu_storage_buffer_private.hh | 1 + source/blender/gpu/opengl/gl_storage_buffer.cc | 17 +++++++++++++++++ source/blender/gpu/opengl/gl_storage_buffer.hh | 1 + 5 files changed, 31 insertions(+) diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index ca6a848786b..8837a7c7647 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -47,6 +47,13 @@ void GPU_storagebuf_clear(GPUStorageBuf *ssbo, void *data); void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); +/** + * Read back content of the buffer to CPU for inspection. + * Slow! Only use for inspection / debugging. + * NOTE: Not synchronized. Use appropriate barrier before reading. + */ +void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data); + /** * \brief Copy a part of a vertex buffer to a storage buffer. * diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index afa27da9c85..460a643089c 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -109,4 +109,9 @@ void GPU_storagebuf_copy_sub_from_vertbuf( unwrap(ssbo)->copy_sub(unwrap(src), dst_offset, src_offset, copy_size); } +void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data) +{ + unwrap(ssbo)->read(data); +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index 9baec0c2a77..0c96f97ad30 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -44,6 +44,7 @@ class StorageBuf { eGPUDataFormat data_format, void *data) = 0; virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0; + virtual void read(void *data) = 0; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 83a56edcf04..5d876308b3c 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -166,6 +166,23 @@ void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uin } } +void GLStorageBuf::read(void *data) +{ + if (ssbo_id_ == 0) { + this->init(); + } + + if (GLContext::direct_state_access_support) { + glGetNamedBufferSubData(ssbo_id_, 0, size_in_bytes_, data); + } + else { + /* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */ + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + } +} + /** \} */ } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index ffe2de12451..680ce911bc7 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -35,6 +35,7 @@ class GLStorageBuf : public StorageBuf { void unbind() override; void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; + void read(void *data) override; /* Special internal function to bind SSBOs to indirect argument targets. */ void bind_as(GLenum target); -- cgit v1.2.3 From b15f90bf85c8ef8e22a474f1d242469f8c317616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 21:54:33 +0200 Subject: GPUBatch: Add draw parameter getter This is used to populate indirect draw commands in the draw manager. --- source/blender/gpu/GPU_batch.h | 7 +++++++ source/blender/gpu/intern/gpu_batch.cc | 24 ++++++++++++++++++++++ .../blender/gpu/intern/gpu_index_buffer_private.hh | 8 ++++++++ 3 files changed, 39 insertions(+) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index c085b592a77..b79560fdd1e 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -164,6 +164,13 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch, #define GPU_batch_texture_bind(batch, name, tex) \ GPU_texture_bind(tex, GPU_shader_get_texture_binding((batch)->shader, name)); +/** + * Return indirect draw call parameters for this batch. + * NOTE: r_base_index is set to -1 if not using an index buffer. + */ +void GPU_batch_draw_parameter_get( + GPUBatch *batch, int *r_v_count, int *r_v_first, int *r_base_index, int *r_i_count); + void GPU_batch_draw(GPUBatch *batch); void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count); /** diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 0b47a7b2952..13a91d2c808 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -220,6 +220,30 @@ void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader) /** \name Drawing / Drawcall functions * \{ */ +void GPU_batch_draw_parameter_get( + GPUBatch *gpu_batch, int *r_v_count, int *r_v_first, int *r_base_index, int *r_i_count) +{ + Batch *batch = static_cast(gpu_batch); + + if (batch->elem) { + *r_v_count = batch->elem_()->index_len_get(); + *r_v_first = batch->elem_()->index_start_get(); + *r_base_index = batch->elem_()->index_base_get(); + } + else { + *r_v_count = batch->verts_(0)->vertex_len; + *r_v_first = 0; + *r_base_index = -1; + } + + int i_count = (batch->inst[0]) ? batch->inst_(0)->vertex_len : 1; + /* Meh. This is to be able to use different numbers of verts in instance VBO's. */ + if (batch->inst[1] != nullptr) { + i_count = min_ii(i_count, batch->inst_(1)->vertex_len); + } + *r_i_count = i_count; +} + void GPU_batch_draw(GPUBatch *batch) { GPU_shader_bind(batch->shader); diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh index 6ce62ae852e..84903b05273 100644 --- a/source/blender/gpu/intern/gpu_index_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh @@ -70,6 +70,14 @@ class IndexBuf { * They can lead to graphical glitches on some systems. (See T96892) */ return is_empty_ ? 0 : index_len_; } + uint32_t index_start_get() const + { + return index_start_; + } + uint32_t index_base_get() const + { + return index_base_; + } /* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */ size_t size_get() const { -- cgit v1.2.3 From da03c1f96d9993425aad18717624a645fcb4e342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 22:01:52 +0200 Subject: GPUCodegen: Do not rely on auto resource location This allows the render engine to expect non-overlapping resources in the generated create info. Textures are indexed from 0 and up. Nodetree ubo is bound to slot 0. Uniform attributes ubo is bound to slot 1. --- source/blender/gpu/intern/gpu_codegen.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 2e1cb6b4a22..7b228c32c5c 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -199,8 +199,7 @@ static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output) } /* Trick type to change overload and keep a somewhat nice syntax. */ -struct GPUConstant : public GPUInput { -}; +struct GPUConstant : public GPUInput {}; /* Print data constructor (i.e: vec2(1.0f, 1.0f)). */ static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input) @@ -356,21 +355,22 @@ void GPUCodegen::generate_resources() std::stringstream ss; /* Textures. */ + int slot = 0; LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) { if (tex->colorband) { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH); } else if (tex->tiled_mapping_name[0] != '\0') { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name); - info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH); } else { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_2D, name, Frequency::BATCH); } } @@ -383,7 +383,7 @@ void GPUCodegen::generate_resources() } ss << "};\n\n"; - info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); + info.uniform_buf(1, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); } if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) { @@ -395,7 +395,7 @@ void GPUCodegen::generate_resources() /* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */ /* DRW_RESOURCE_CHUNK_LEN = 512 */ - info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); + info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); } info.typedef_source_generated = ss.str(); -- cgit v1.2.3 From 36e74cc4f793f8432861b401891bb5fbd4db3ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 22:03:21 +0200 Subject: GPUMaterial: Expose debug name getter This also makes it mandatory, but reduced length for release. --- source/blender/gpu/GPU_material.h | 1 + source/blender/gpu/intern/gpu_material.c | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 1ab06f3369d..51438d7909f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -228,6 +228,7 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); struct GPUShader *GPU_material_get_shader(GPUMaterial *material); +const char *GPU_material_get_name(GPUMaterial *material); /** * Return can be NULL if it's a world material. */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index a4842ef0e43..d9045a041b6 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -91,6 +91,8 @@ struct GPUMaterial { #ifndef NDEBUG char name[64]; +#else + char name[16]; #endif }; @@ -193,6 +195,11 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material) return material->pass ? GPU_pass_shader_get(material->pass) : NULL; } +const char *GPU_material_get_name(GPUMaterial *material) +{ + return material->name; +} + Material *GPU_material_get_material(GPUMaterial *material) { return material->ma; @@ -205,12 +212,7 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material) void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { -#ifndef NDEBUG - const char *name = material->name; -#else - const char *name = "Material"; -#endif - material->ubo = GPU_uniformbuf_create_from_list(inputs, name); + material->ubo = GPU_uniformbuf_create_from_list(inputs, material->name); } ListBase GPU_material_attributes(GPUMaterial *material) @@ -672,11 +674,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->graph.used_libraries = BLI_gset_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); mat->refcount = 1; -#ifndef NDEBUG STRNCPY(mat->name, name); -#else - UNUSED_VARS(name); -#endif if (is_lookdev) { mat->flag |= GPU_MATFLAG_LOOKDEV_HACK; } -- cgit v1.2.3 From f5ea2a64348ca2c12174bb67faf75916e8e09900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 22:05:34 +0200 Subject: GPUTexture: Add type correct GPU_SAMPLER_MAX constant for C++ This avoid having to cast when using it in `.cc` and `.hh` files. --- source/blender/gpu/GPU_texture.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 30e890b1591..8b54f4c9822 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -49,7 +49,12 @@ typedef enum eGPUSamplerState { * #GPU_SAMPLER_MAX is not a valid enum value, but only a limit. * It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS. */ +#ifdef __cplusplus +static constexpr eGPUSamplerState GPU_SAMPLER_MAX = eGPUSamplerState(GPU_SAMPLER_ICON + 1); +#else static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1); +#endif + ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON) #ifdef __cplusplus -- cgit v1.2.3 From 4944167dee90cc66b12766a1da4d33a13abdb2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 30 Aug 2022 21:57:39 +0200 Subject: GPUBatch: Add multi_draw_indirect capability and indirect buffer offset This is for completion and to be used by the new draw manager. --- source/blender/draw/intern/draw_debug.cc | 8 +++--- source/blender/draw/intern/draw_manager_exec.c | 2 +- source/blender/gpu/GPU_batch.h | 4 ++- source/blender/gpu/intern/gpu_batch.cc | 14 +++++++++-- source/blender/gpu/intern/gpu_batch_private.hh | 6 ++++- source/blender/gpu/opengl/gl_batch.cc | 34 +++++++++++++++++++++++--- source/blender/gpu/opengl/gl_batch.hh | 6 ++++- 7 files changed, 61 insertions(+), 13 deletions(-) diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index b9d10302c1e..ab78db5d913 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -525,14 +525,14 @@ void DebugDraw::display_lines() if (gpu_draw_buf_used) { GPU_debug_group_begin("GPU"); GPU_storagebuf_bind(gpu_draw_buf_, slot); - GPU_batch_draw_indirect(batch, gpu_draw_buf_); + GPU_batch_draw_indirect(batch, gpu_draw_buf_, 0); GPU_storagebuf_unbind(gpu_draw_buf_); GPU_debug_group_end(); } GPU_debug_group_begin("CPU"); GPU_storagebuf_bind(cpu_draw_buf_, slot); - GPU_batch_draw_indirect(batch, cpu_draw_buf_); + GPU_batch_draw_indirect(batch, cpu_draw_buf_, 0); GPU_storagebuf_unbind(cpu_draw_buf_); GPU_debug_group_end(); @@ -557,14 +557,14 @@ void DebugDraw::display_prints() if (gpu_print_buf_used) { GPU_debug_group_begin("GPU"); GPU_storagebuf_bind(gpu_print_buf_, slot); - GPU_batch_draw_indirect(batch, gpu_print_buf_); + GPU_batch_draw_indirect(batch, gpu_print_buf_, 0); GPU_storagebuf_unbind(gpu_print_buf_); GPU_debug_group_end(); } GPU_debug_group_begin("CPU"); GPU_storagebuf_bind(cpu_print_buf_, slot); - GPU_batch_draw_indirect(batch, cpu_print_buf_); + GPU_batch_draw_indirect(batch, cpu_print_buf_, 0); GPU_storagebuf_unbind(cpu_print_buf_); GPU_debug_group_end(); diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 4dda0ceb2ef..0e39cc1d3b9 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -891,7 +891,7 @@ static void draw_call_indirect(DRWShadingGroup *shgroup, } GPU_batch_set_shader(batch, shgroup->shader); - GPU_batch_draw_indirect(batch, indirect_buf); + GPU_batch_draw_indirect(batch, indirect_buf, 0); } static void draw_call_batching_start(DRWCommandsState *state) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index b79560fdd1e..8f524f72fa1 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -187,7 +187,9 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi * Issue a draw call using GPU computed arguments. The argument are expected to be valid for the * type of geometry drawn (index or non-indexed). */ -void GPU_batch_draw_indirect(GPUBatch *batch, GPUStorageBuf *indirect_buf); +void GPU_batch_draw_indirect(GPUBatch *batch, GPUStorageBuf *indirect_buf, intptr_t offset); +void GPU_batch_multi_draw_indirect( + GPUBatch *batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride); #if 0 /* future plans */ diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 13a91d2c808..9092ad5110c 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -294,13 +294,23 @@ void GPU_batch_draw_advanced( batch->draw(v_first, v_count, i_first, i_count); } -void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf) +void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, intptr_t offset) { BLI_assert(Context::get()->shader != nullptr); BLI_assert(indirect_buf != nullptr); Batch *batch = static_cast(gpu_batch); - batch->draw_indirect(indirect_buf); + batch->draw_indirect(indirect_buf, offset); +} + +void GPU_batch_multi_draw_indirect( + GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride) +{ + BLI_assert(Context::get()->shader != nullptr); + BLI_assert(indirect_buf != nullptr); + Batch *batch = static_cast(gpu_batch); + + batch->multi_draw_indirect(indirect_buf, count, offset, stride); } /** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index 8ca19884fd7..59646925d68 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -29,7 +29,11 @@ class Batch : public GPUBatch { virtual ~Batch() = default; virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; - virtual void draw_indirect(GPUStorageBuf *indirect_buf) = 0; + virtual void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) = 0; + virtual void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) = 0; /* Convenience casts. */ IndexBuf *elem_() const diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index 4ec86b98cbe..ff8867fe3e6 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -327,12 +327,13 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) } } -void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf) +void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) { GL_CHECK_RESOURCES("Batch"); this->bind(0); + /* TODO(fclem): Make the barrier and binding optional if consecutive draws are issued. */ dynamic_cast(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER); /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ glMemoryBarrier(GL_COMMAND_BARRIER_BIT); @@ -341,10 +342,37 @@ void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf) if (elem) { const GLIndexBuf *el = this->elem_(); GLenum index_type = to_gl(el->index_type_); - glDrawElementsIndirect(gl_type, index_type, (GLvoid *)nullptr); + glDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset); } else { - glDrawArraysIndirect(gl_type, (GLvoid *)nullptr); + glDrawArraysIndirect(gl_type, (GLvoid *)offset); + } + /* Unbind. */ + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); +} + +void GLBatch::multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) +{ + GL_CHECK_RESOURCES("Batch"); + + this->bind(0); + + /* TODO(fclem): Make the barrier and binding optional if consecutive draws are issued. */ + dynamic_cast(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER); + /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ + glMemoryBarrier(GL_COMMAND_BARRIER_BIT); + + GLenum gl_type = to_gl(prim_type); + if (elem) { + const GLIndexBuf *el = this->elem_(); + GLenum index_type = to_gl(el->index_type_); + glMultiDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset, count, stride); + } + else { + glMultiDrawArraysIndirect(gl_type, (GLvoid *)offset, count, stride); } /* Unbind. */ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index 0d7ea7c4a9e..714aa1220be 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -91,7 +91,11 @@ class GLBatch : public Batch { public: void draw(int v_first, int v_count, int i_first, int i_count) override; - void draw_indirect(GPUStorageBuf *indirect_buf) override; + void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override; + void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) override; void bind(int i_first); /* Convenience getters. */ -- cgit v1.2.3 From 3090edfecfcea1ac379bbfc9499cb74551fffece Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 15:18:11 -0500 Subject: Cleanup: Use standard variable name for curve points --- source/blender/draw/intern/draw_cache_impl_curves.cc | 6 +++--- source/blender/editors/curves/intern/curves_add.cc | 6 +++--- .../blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc | 11 +++++------ .../nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc | 6 +++--- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 1d3d6222f8f..4f0072ec657 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -397,10 +397,10 @@ static void curves_batch_cache_fill_strands_data(const Curves &curves_id, curves_id.geometry); for (const int i : IndexRange(curves.curves_num())) { - const IndexRange curve_range = curves.points_for_curve(i); + const IndexRange points = curves.points_for_curve(i); - *(uint *)GPU_vertbuf_raw_step(&data_step) = curve_range.start(); - *(ushort *)GPU_vertbuf_raw_step(&seg_step) = curve_range.size() - 1; + *(uint *)GPU_vertbuf_raw_step(&data_step) = points.start(); + *(ushort *)GPU_vertbuf_raw_step(&seg_step) = points.size() - 1; } } diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc index 6556f62443a..07a2dc0b8eb 100644 --- a/source/blender/editors/curves/intern/curves_add.cc +++ b/source/blender/editors/curves/intern/curves_add.cc @@ -114,9 +114,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi RandomNumberGenerator rng; for (const int i : curves.curves_range()) { - const IndexRange curve_range = curves.points_for_curve(i); - MutableSpan curve_positions = positions.slice(curve_range); - MutableSpan curve_radii = radii.slice(curve_range); + const IndexRange points = curves.points_for_curve(i); + MutableSpan curve_positions = positions.slice(points); + MutableSpan curve_radii = radius.span.slice(points); const float theta = 2.0f * M_PI * rng.get_float(); const float phi = saacosf(2.0f * rng.get_float() - 1.0f); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 1ee43d98e6f..02ae89b41e6 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -144,21 +144,20 @@ class ExtrapolateCurvesEffect : public CurvesEffect { for (const int influence_i : range) { const int curve_i = curve_indices[influence_i]; const float move_distance_cu = move_distances_cu[influence_i]; - const IndexRange curve_points = curves.points_for_curve(curve_i); + const IndexRange points = curves.points_for_curve(curve_i); - if (curve_points.size() <= 1) { + if (points.size() <= 1) { continue; } - const float3 old_last_pos_cu = positions_cu[curve_points.last()]; + const float3 old_last_pos_cu = positions_cu[points.last()]; /* Use some point within the curve rather than the end point to smooth out some random * variation. */ - const float3 direction_reference_point = - positions_cu[curve_points[curve_points.size() / 2]]; + const float3 direction_reference_point = positions_cu[points[points.size() / 2]]; const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point); const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu; - move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu); + move_last_point_and_resample(positions_cu.slice(points), new_last_pos_cu); } }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 8c3e97edac0..28d979facac 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -64,12 +64,12 @@ class EndpointFieldInput final : public bke::CurvesFieldInput { devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) { threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) { for (const int i : curves_range) { - const IndexRange range = curves.points_for_curve(i); + const IndexRange points = curves.points_for_curve(i); const int start = std::max(start_size[i], 0); const int end = std::max(end_size[i], 0); - selection_span.slice(range.take_front(start)).fill(true); - selection_span.slice(range.take_back(end)).fill(true); + selection_span.slice(points.take_front(start)).fill(true); + selection_span.slice(points.take_back(end)).fill(true); } }); }); -- cgit v1.2.3 From bcd671e565cd337292562d7b2542410f17ab0ff6 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 15:20:44 -0500 Subject: Cleanup: Use C++ attribute API --- source/blender/editors/curves/intern/curves_add.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc index 07a2dc0b8eb..f234a58f439 100644 --- a/source/blender/editors/curves/intern/curves_add.cc +++ b/source/blender/editors/curves/intern/curves_add.cc @@ -102,10 +102,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi MutableSpan offsets = curves.offsets_for_write(); MutableSpan positions = curves.positions_for_write(); - - float *radius_data = (float *)CustomData_add_layer_named( - &curves.point_data, CD_PROP_FLOAT, CD_SET_DEFAULT, nullptr, curves.point_num, "radius"); - MutableSpan radii{radius_data, curves.points_num()}; + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + bke::SpanAttributeWriter radius = attributes.lookup_or_add_for_write_only_span( + "radius", ATTR_DOMAIN_POINT); for (const int i : offsets.index_range()) { offsets[i] = points_per_curve * i; @@ -135,6 +134,8 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi } } + radius.finish(); + return curves; } -- cgit v1.2.3 From d9c48d94e41ba9f8d6b91043142af17a76b7345c Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 15:38:38 -0500 Subject: Fix: Potential name clash when adding rest position attribute If a "rest_position" attribute already existed, potentiall with another type, the next name "rest_position.001" would be used, which might even conflict with a name on another domain. Use the C++ attribute API instead, which has more standard/predictable behavior. --- source/blender/blenkernel/intern/DerivedMesh.cc | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index a29d8726f21..7ef676b3b71 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -741,6 +741,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Mesh **r_final, GeometrySet **r_geometry_set) { + using namespace blender::bke; /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals * or certain data layers. */ @@ -824,18 +825,13 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); ASSERT_IS_VALID_MESH(mesh_final); } - float3 *rest_positions = static_cast(CustomData_add_layer_named(&mesh_final->vdata, - CD_PROP_FLOAT3, - CD_DEFAULT, - nullptr, - mesh_final->totvert, - "rest_position")); - blender::threading::parallel_for( - IndexRange(mesh_final->totvert), 1024, [&](const IndexRange range) { - for (const int i : range) { - rest_positions[i] = mesh_final->mvert[i].co; - } - }); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh_final); + SpanAttributeWriter rest_positions = + attributes.lookup_or_add_for_write_only_span("rest_position", ATTR_DOMAIN_POINT); + if (rest_positions) { + attributes.lookup("position").materialize(rest_positions.span); + rest_positions.finish(); + } } /* Apply all leading deform modifiers. */ -- cgit v1.2.3 From cccc6d6905be7ac32cbe8649faf6b17e9c9f636e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 16:27:43 -0500 Subject: Mesh: Avoid redundant custom data layer initialization In all these cases, it was clear that the layer values were set right after the layer was created anyway. So there's no point in using calloc or setting the values to zero first. See 25237d2625078c6d for more info. --- source/blender/blenkernel/intern/DerivedMesh.cc | 6 +++--- source/blender/blenkernel/intern/mesh_remesh_voxel.cc | 4 ++-- source/blender/blenkernel/intern/paint.cc | 4 ++-- source/blender/io/alembic/intern/abc_customdata.cc | 2 +- source/blender/io/stl/importer/stl_import_mesh.cc | 2 +- source/blender/modifiers/intern/MOD_skin.c | 2 +- source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index adc986a3813..e83720e99f1 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -1003,11 +1003,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index c840c917eb3..5a4fd0d7d96 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -291,7 +291,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source) } else { target_mask = (float *)CustomData_add_layer( - &target->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, target->totvert); + &target->vdata, CD_PAINT_MASK, CD_CONSTRUCT, nullptr, target->totvert); } for (int i = 0; i < target->totvert; i++) { @@ -325,7 +325,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) } else { target_face_sets = (int *)CustomData_add_layer( - &target->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, target->totpoly); + &target->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, target->totpoly); } const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source); diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 1dfc47efcd5..4c3da5eabc4 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1836,7 +1836,7 @@ static void sculpt_face_sets_ensure(Mesh *mesh) } int *new_face_sets = static_cast(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, mesh->totpoly)); + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -2078,7 +2078,7 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) else { initialize_new_face_sets = true; int *new_face_sets = static_cast(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, nullptr, mesh->totpoly)); + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 644990afb35..9c71944fc92 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -540,7 +540,7 @@ void read_generated_coordinates(const ICompoundProperty &prop, cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO); } else { - cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_SET_DEFAULT, nullptr, totvert); + cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CONSTRUCT, nullptr, totvert); } float(*orcodata)[3] = static_cast(cd_data); diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index 7686bfa1247..178b5b9347f 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -87,7 +87,7 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->mpoly = static_cast( CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly)); mesh->mloop = static_cast( - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop)); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, mesh->totloop)); threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { for (const int i : tris_range) { diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index b41c730024c..982f5802df6 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1888,7 +1888,7 @@ static void skin_set_orig_indices(Mesh *mesh) int *orig, totpoly; totpoly = mesh->totpoly; - orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, totpoly); + orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CONSTRUCT, NULL, totpoly); copy_vn_i(orig, totpoly, ORIGINDEX_NONE); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 896364bc591..60c8a89a6bf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -73,7 +73,7 @@ static void write_vertex_creases(Mesh &mesh, const VArray &crease_varray) } else { crease = static_cast( - CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh.totvert)); + CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_CONSTRUCT, nullptr, mesh.totvert)); } materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert}); } -- cgit v1.2.3 From 4c91c24bc7cbe2c4f97be373025a672928a5676d Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 16:44:47 -0500 Subject: Attributes: Avoid unnecessarily initializing new attributes The "write_only" (i.e. no reading) API function expects the caller to set values for all new attribute elements, so using calloc or setting the default value first is redundant. In theory this can improve performance by avoiding an extra pass over the array. I observed a 6% improvement in a basic test with the mesh to points node: from 47.9ms to 45ms on average. See 25237d2625078c6d for more info. Similar to cccc6d6905be7ac. --- source/blender/blenkernel/intern/attribute_access.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index aed55c5db45..0187dbd6f78 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -966,7 +966,8 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span( GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) { - GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type); + GAttributeWriter attribute = this->lookup_or_add_for_write( + attribute_id, domain, data_type, AttributeInitConstruct()); if (attribute) { return GSpanAttributeWriter{std::move(attribute), false}; } -- cgit v1.2.3 From d94a11ed79b3c89176c7d436cacdc2767b4e7a4d Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 16:49:24 -0500 Subject: Curves: Avoid unnecessarily initializing new positions layer When creating a curves data-block, one is expected to set the new position values. We can slightly improve performance by avoiding doing that redundantly. Similar to cccc6d6905be7ac32cb. --- source/blender/blenkernel/intern/curves_geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 618ff8fa97a..3f549b39a00 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -58,7 +58,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named(&this->point_data, CD_PROP_FLOAT3, - CD_SET_DEFAULT, + CD_CONSTRUCT, nullptr, this->point_num, ATTR_POSITION.c_str()); -- cgit v1.2.3 From 7bfabc6444181afaaccc1049a4488d30a339f9d6 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 16:52:30 -0500 Subject: Cleanup: Remove unused point cloud function This can be done more intuitively with a "copy parameters" function like `curves_copy_parameters` or `BKE_mesh_copy_parameters` anyway. --- source/blender/blenkernel/BKE_pointcloud.h | 2 -- source/blender/blenkernel/intern/pointcloud.cc | 16 ---------------- 2 files changed, 18 deletions(-) diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index ee90fea6506..62a1824d844 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -33,8 +33,6 @@ bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, con /* Dependency Graph */ -struct PointCloud *BKE_pointcloud_new_for_eval(const struct PointCloud *pointcloud_src, - int totpoint); struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference); void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 306141cffb7..6738b5f3260 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -325,22 +325,6 @@ bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), co /* Dependency Graph */ -PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint) -{ - PointCloud *pointcloud_dst = static_cast(BKE_id_new_nomain(ID_PT, nullptr)); - CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint); - - STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name); - pointcloud_dst->mat = static_cast(MEM_dupallocN(pointcloud_src->mat)); - pointcloud_dst->totcol = pointcloud_src->totcol; - - pointcloud_dst->totpoint = totpoint; - CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_SET_DEFAULT, totpoint); - - return pointcloud_dst; -} - PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference) { int flags = LIB_ID_COPY_LOCALIZE; -- cgit v1.2.3 From b5bc08686418e6d684b28d4793de2798d049fa8b Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 17:00:36 -0500 Subject: Cleanup: Avoid using geometry component unnecessarily --- source/blender/nodes/geometry/nodes/node_geo_points.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc index dd32e6714f4..e0ba1f1c810 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc @@ -69,10 +69,8 @@ static void node_geo_exec(GeoNodeExecParams params) Field position_field = params.extract_input>("Position"); Field radius_field = params.extract_input>("Radius"); - PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count); - GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud); - PointCloudComponent &points = geometry_set.get_component_for_write(); - MutableAttributeAccessor attributes = *points.attributes_for_write(); + PointCloud *points = BKE_pointcloud_new_nomain(count); + MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(*points); AttributeWriter output_position = attributes.lookup_or_add_for_write( "position", ATTR_DOMAIN_POINT); AttributeWriter output_radii = attributes.lookup_or_add_for_write( @@ -86,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params) output_position.finish(); output_radii.finish(); - params.set_output("Geometry", std::move(geometry_set)); + params.set_output("Geometry", GeometrySet::create_with_pointcloud(points)); } } // namespace blender::nodes::node_geo_points_cc -- cgit v1.2.3 From 0331a8c67c8035c29ac6b7655cb4e4d837ddabba Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 30 Aug 2022 17:03:04 -0500 Subject: Cleanup: Remove redundant addition of attribute The radius attribute is aleady added in `pointcloud_random`. --- source/blender/blenkernel/intern/pointcloud.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 6738b5f3260..14ca3f58db9 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -228,13 +228,6 @@ void *BKE_pointcloud_add_default(Main *bmain, const char *name) PointCloud *pointcloud = static_cast(BKE_libblock_alloc(bmain, ID_PT, name, 0)); pointcloud_init_data(&pointcloud->id); - - CustomData_add_layer_named(&pointcloud->pdata, - CD_PROP_FLOAT, - CD_SET_DEFAULT, - nullptr, - pointcloud->totpoint, - POINTCLOUD_ATTR_RADIUS); pointcloud_random(pointcloud); return pointcloud; -- cgit v1.2.3 From bfa0ee13d5395fa2cf622b6808e93d0a7cd4f3ea Mon Sep 17 00:00:00 2001 From: Charlie Jolly Date: Tue, 30 Aug 2022 11:05:46 +0100 Subject: Node: Mix node This patch is a response to T92588 and is implemented as a Function/Shader node. This node has support for Float, Vector and Color data types. For Vector it supports uniform and non-uniform mixing. For Color it now has the option to remove factor clamping. It replaces the Mix RGB for Shader and Geometry node trees. As discussed in T96219, this patch converts existing nodes in .blend files. The old node is still available in the Python API but hidden from the menus. Reviewed By: HooglyBoogly, JacquesLucke, simonthommes, brecht Maniphest Tasks: T92588 Differential Revision: https://developer.blender.org/D13749 --- intern/cycles/blender/shader.cpp | 91 +++- intern/cycles/kernel/osl/shaders/CMakeLists.txt | 5 + .../cycles/kernel/osl/shaders/node_color_blend.h | 264 ++++++++++ .../cycles/kernel/osl/shaders/node_mix_color.osl | 57 +++ .../cycles/kernel/osl/shaders/node_mix_float.osl | 11 + .../cycles/kernel/osl/shaders/node_mix_vector.osl | 14 + .../osl/shaders/node_mix_vector_non_uniform.osl | 14 + intern/cycles/kernel/svm/color_util.h | 12 +- intern/cycles/kernel/svm/mix.h | 86 +++- intern/cycles/kernel/svm/node_types_template.h | 4 + intern/cycles/kernel/svm/svm.h | 12 + intern/cycles/kernel/svm/types.h | 2 +- intern/cycles/scene/constant_fold.cpp | 95 ++++ intern/cycles/scene/constant_fold.h | 1 + intern/cycles/scene/shader_nodes.cpp | 244 +++++++++- intern/cycles/scene/shader_nodes.h | 46 ++ release/scripts/startup/nodeitems_builtins.py | 4 +- source/blender/blenkernel/BKE_node.h | 3 +- source/blender/blenkernel/intern/node.cc | 1 + source/blender/blenloader/intern/versioning_300.c | 29 ++ source/blender/editors/space_node/drawnode.cc | 2 +- .../blender_interface/BlenderStrokeRenderer.cpp | 4 +- source/blender/gpu/CMakeLists.txt | 1 + .../material/gpu_shader_material_mix_color.glsl | 537 +++++++++++++++++++++ source/blender/makesdna/DNA_node_types.h | 16 + source/blender/makesrna/intern/rna_nodetree.c | 54 +++ source/blender/nodes/NOD_shader.h | 1 + source/blender/nodes/NOD_static_types.h | 3 +- source/blender/nodes/shader/CMakeLists.txt | 1 + .../blender/nodes/shader/nodes/node_shader_mix.cc | 443 +++++++++++++++++ .../nodes/shader/nodes/node_shader_mix_rgb.cc | 4 +- 31 files changed, 2040 insertions(+), 21 deletions(-) create mode 100644 intern/cycles/kernel/osl/shaders/node_color_blend.h create mode 100644 intern/cycles/kernel/osl/shaders/node_mix_color.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mix_float.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mix_vector.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl create mode 100644 source/blender/nodes/shader/nodes/node_shader_mix.cc diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 04eb1576330..9505f4ba58f 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -350,6 +350,33 @@ static ShaderNode *add_node(Scene *scene, mix->set_use_clamp(b_mix_node.use_clamp()); node = mix; } + else if (b_node.is_a(&RNA_ShaderNodeMix)) { + BL::ShaderNodeMix b_mix_node(b_node); + if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_VECTOR) { + if (b_mix_node.factor_mode() == BL::ShaderNodeMix::factor_mode_UNIFORM) { + MixVectorNode *mix_node = graph->create_node(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + else { + MixVectorNonUniformNode *mix_node = graph->create_node(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + } + else if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_RGBA) { + MixColorNode *mix_node = graph->create_node(); + mix_node->set_blend_type((NodeMix)b_mix_node.blend_type()); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + mix_node->set_use_clamp_result(b_mix_node.clamp_result()); + node = mix_node; + } + else { + MixFloatNode *mix_node = graph->create_node(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + } else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) { node = graph->create_node(); } @@ -1072,7 +1099,9 @@ static bool node_use_modified_socket_name(ShaderNode *node) return true; } -static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket) +static ShaderInput *node_find_input_by_name(BL::Node b_node, + ShaderNode *node, + BL::NodeSocket &b_socket) { string name = b_socket.identifier(); ShaderInput *input = node->input(name.c_str()); @@ -1082,6 +1111,35 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_ if (string_startswith(name, "Shader")) { string_replace(name, "Shader", "Closure"); } + + /* Map mix node internal name for shader. */ + if (b_node.is_a(&RNA_ShaderNodeMix)) { + if (string_endswith(name, "Factor_Float")) { + string_replace(name, "Factor_Float", "Factor"); + } + else if (string_endswith(name, "Factor_Vector")) { + string_replace(name, "Factor_Vector", "Factor"); + } + else if (string_endswith(name, "A_Float")) { + string_replace(name, "A_Float", "A"); + } + else if (string_endswith(name, "B_Float")) { + string_replace(name, "B_Float", "B"); + } + else if (string_endswith(name, "A_Color")) { + string_replace(name, "A_Color", "A"); + } + else if (string_endswith(name, "B_Color")) { + string_replace(name, "B_Color", "B"); + } + else if (string_endswith(name, "A_Vector")) { + string_replace(name, "A_Vector", "A"); + } + else if (string_endswith(name, "B_Vector")) { + string_replace(name, "B_Vector", "B"); + } + } + input = node->input(name.c_str()); if (!input) { @@ -1111,7 +1169,9 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_ return input; } -static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket) +static ShaderOutput *node_find_output_by_name(BL::Node b_node, + ShaderNode *node, + BL::NodeSocket &b_socket) { string name = b_socket.identifier(); ShaderOutput *output = node->output(name.c_str()); @@ -1122,6 +1182,21 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket & name = "Closure"; output = node->output(name.c_str()); } + /* Map internal name for shader. */ + if (b_node.is_a(&RNA_ShaderNodeMix)) { + if (string_endswith(name, "Result_Float")) { + string_replace(name, "Result_Float", "Result"); + output = node->output(name.c_str()); + } + else if (string_endswith(name, "Result_Color")) { + string_replace(name, "Result_Color", "Result"); + output = node->output(name.c_str()); + } + else if (string_endswith(name, "Result_Vector")) { + string_replace(name, "Result_Vector", "Result"); + output = node->output(name.c_str()); + } + } } return output; @@ -1267,7 +1342,11 @@ static void add_nodes(Scene *scene, if (node) { /* map node sockets for linking */ for (BL::NodeSocket &b_input : b_node.inputs) { - ShaderInput *input = node_find_input_by_name(node, b_input); + if (b_input.is_unavailable()) { + /* Skip unavailable sockets. */ + continue; + } + ShaderInput *input = node_find_input_by_name(b_node, node, b_input); if (!input) { /* XXX should not happen, report error? */ continue; @@ -1277,7 +1356,11 @@ static void add_nodes(Scene *scene, set_default_value(input, b_input, b_data, b_ntree); } for (BL::NodeSocket &b_output : b_node.outputs) { - ShaderOutput *output = node_find_output_by_name(node, b_output); + if (b_output.is_unavailable()) { + /* Skip unavailable sockets. */ + continue; + } + ShaderOutput *output = node_find_output_by_name(b_node, node, b_output); if (!output) { /* XXX should not happen, report error? */ continue; diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt index 741bce7c399..c79af3f6112 100644 --- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt @@ -57,6 +57,10 @@ set(SRC_OSL node_math.osl node_mix.osl node_mix_closure.osl + node_mix_color.osl + node_mix_float.osl + node_mix_vector.osl + node_mix_vector_non_uniform.osl node_musgrave_texture.osl node_noise_texture.osl node_normal.osl @@ -109,6 +113,7 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h) set(SRC_OSL_HEADERS node_color.h + node_color_blend.h node_fresnel.h node_hash.h node_math.h diff --git a/intern/cycles/kernel/osl/shaders/node_color_blend.h b/intern/cycles/kernel/osl/shaders/node_color_blend.h new file mode 100644 index 00000000000..ab4b4809a97 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_color_blend.h @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +color node_mix_blend(float t, color col1, color col2) +{ + return mix(col1, col2, t); +} + +color node_mix_add(float t, color col1, color col2) +{ + return mix(col1, col1 + col2, t); +} + +color node_mix_mul(float t, color col1, color col2) +{ + return mix(col1, col1 * col2, t); +} + +color node_mix_screen(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + return color(1.0) - (color(tm) + t * (color(1.0) - col2)) * (color(1.0) - col1); +} + +color node_mix_overlay(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (outcol[0] < 0.5) + outcol[0] *= tm + 2.0 * t * col2[0]; + else + outcol[0] = 1.0 - (tm + 2.0 * t * (1.0 - col2[0])) * (1.0 - outcol[0]); + + if (outcol[1] < 0.5) + outcol[1] *= tm + 2.0 * t * col2[1]; + else + outcol[1] = 1.0 - (tm + 2.0 * t * (1.0 - col2[1])) * (1.0 - outcol[1]); + + if (outcol[2] < 0.5) + outcol[2] *= tm + 2.0 * t * col2[2]; + else + outcol[2] = 1.0 - (tm + 2.0 * t * (1.0 - col2[2])) * (1.0 - outcol[2]); + + return outcol; +} + +color node_mix_sub(float t, color col1, color col2) +{ + return mix(col1, col1 - col2, t); +} + +color node_mix_div(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (col2[0] != 0.0) + outcol[0] = tm * outcol[0] + t * outcol[0] / col2[0]; + if (col2[1] != 0.0) + outcol[1] = tm * outcol[1] + t * outcol[1] / col2[1]; + if (col2[2] != 0.0) + outcol[2] = tm * outcol[2] + t * outcol[2] / col2[2]; + + return outcol; +} + +color node_mix_diff(float t, color col1, color col2) +{ + return mix(col1, abs(col1 - col2), t); +} + +color node_mix_dark(float t, color col1, color col2) +{ + return mix(col1, min(col1, col2), t); +} + +color node_mix_light(float t, color col1, color col2) +{ + return mix(col1, max(col1, col2), t); +} + +color node_mix_dodge(float t, color col1, color col2) +{ + color outcol = col1; + + if (outcol[0] != 0.0) { + float tmp = 1.0 - t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 1.0; + else if ((tmp = outcol[0] / tmp) > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + } + if (outcol[1] != 0.0) { + float tmp = 1.0 - t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 1.0; + else if ((tmp = outcol[1] / tmp) > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + } + if (outcol[2] != 0.0) { + float tmp = 1.0 - t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 1.0; + else if ((tmp = outcol[2] / tmp) > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + } + + return outcol; +} + +color node_mix_burn(float t, color col1, color col2) +{ + float tmp, tm = 1.0 - t; + + color outcol = col1; + + tmp = tm + t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[0]) / tmp)) < 0.0) + outcol[0] = 0.0; + else if (tmp > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + + tmp = tm + t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[1]) / tmp)) < 0.0) + outcol[1] = 0.0; + else if (tmp > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + + tmp = tm + t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[2]) / tmp)) < 0.0) + outcol[2] = 0.0; + else if (tmp > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + + return outcol; +} + +color node_mix_hue(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_sat(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + color hsv = rgb_to_hsv(outcol); + + if (hsv[1] != 0.0) { + color hsv2 = rgb_to_hsv(col2); + + hsv[1] = tm * hsv[1] + t * hsv2[1]; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +color node_mix_val(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color hsv = rgb_to_hsv(col1); + color hsv2 = rgb_to_hsv(col2); + + hsv[2] = tm * hsv[2] + t * hsv2[2]; + + return hsv_to_rgb(hsv); +} + +color node_mix_color(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + hsv[1] = hsv2[1]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_soft(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color one = color(1.0); + color scr = one - (one - col2) * (one - col1); + + return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr); +} + +color node_mix_linear(float t, color col1, color col2) +{ + color outcol = col1; + + if (col2[0] > 0.5) + outcol[0] = col1[0] + t * (2.0 * (col2[0] - 0.5)); + else + outcol[0] = col1[0] + t * (2.0 * (col2[0]) - 1.0); + + if (col2[1] > 0.5) + outcol[1] = col1[1] + t * (2.0 * (col2[1] - 0.5)); + else + outcol[1] = col1[1] + t * (2.0 * (col2[1]) - 1.0); + + if (col2[2] > 0.5) + outcol[2] = col1[2] + t * (2.0 * (col2[2] - 0.5)); + else + outcol[2] = col1[2] + t * (2.0 * (col2[2]) - 1.0); + + return outcol; +} + +color node_mix_clamp(color col) +{ + color outcol = col; + + outcol[0] = clamp(col[0], 0.0, 1.0); + outcol[1] = clamp(col[1], 0.0, 1.0); + outcol[2] = clamp(col[2], 0.0, 1.0); + + return outcol; +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_color.osl b/intern/cycles/kernel/osl/shaders/node_mix_color.osl new file mode 100644 index 00000000000..3ddd89ed306 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_color.osl @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "node_color.h" +#include "node_color_blend.h" +#include "stdcycles.h" + +shader node_mix_color(string blend_type = "mix", + int use_clamp = 0, + int use_clamp_result = 0, + float Factor = 0.5, + color A = 0.0, + color B = 0.0, + output color Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + + if (blend_type == "mix") + Result = mix(A, B, t); + if (blend_type == "add") + Result = node_mix_add(t, A, B); + if (blend_type == "multiply") + Result = node_mix_mul(t, A, B); + if (blend_type == "screen") + Result = node_mix_screen(t, A, B); + if (blend_type == "overlay") + Result = node_mix_overlay(t, A, B); + if (blend_type == "subtract") + Result = node_mix_sub(t, A, B); + if (blend_type == "divide") + Result = node_mix_div(t, A, B); + if (blend_type == "difference") + Result = node_mix_diff(t, A, B); + if (blend_type == "darken") + Result = node_mix_dark(t, A, B); + if (blend_type == "lighten") + Result = node_mix_light(t, A, B); + if (blend_type == "dodge") + Result = node_mix_dodge(t, A, B); + if (blend_type == "burn") + Result = node_mix_burn(t, A, B); + if (blend_type == "hue") + Result = node_mix_hue(t, A, B); + if (blend_type == "saturation") + Result = node_mix_sat(t, A, B); + if (blend_type == "value") + Result = node_mix_val(t, A, B); + if (blend_type == "color") + Result = node_mix_color(t, A, B); + if (blend_type == "soft_light") + Result = node_mix_soft(t, A, B); + if (blend_type == "linear_light") + Result = node_mix_linear(t, A, B); + + if (use_clamp_result) + Result = clamp(Result, 0.0, 1.0); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_float.osl b/intern/cycles/kernel/osl/shaders/node_mix_float.osl new file mode 100644 index 00000000000..fdc7b4eff6e --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_float.osl @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_float( + int use_clamp = 0, float Factor = 0.5, float A = 0.0, float B = 0.0, output float Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl new file mode 100644 index 00000000000..d76396afb0d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_vector(int use_clamp = 0, + float Factor = 0.5, + vector A = 0.0, + vector B = 0.0, + output vector Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl new file mode 100644 index 00000000000..217856bcf2a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_vector_non_uniform(int use_clamp = 0, + vector Factor = 0.5, + vector A = 0.0, + vector B = 0.0, + output vector Result = 0.0) +{ + vector t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h index 41f44378ff0..96adb6fd64c 100644 --- a/intern/cycles/kernel/svm/color_util.h +++ b/intern/cycles/kernel/svm/color_util.h @@ -247,10 +247,8 @@ ccl_device float3 svm_mix_clamp(float3 col) return saturate(col); } -ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float t, float3 c1, float3 c2) { - float t = saturatef(fac); - switch (type) { case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); @@ -282,7 +280,7 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float return svm_mix_sat(t, c1, c2); case NODE_MIX_VAL: return svm_mix_val(t, c1, c2); - case NODE_MIX_COLOR: + case NODE_MIX_COL: return svm_mix_color(t, c1, c2); case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); @@ -295,6 +293,12 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float return make_float3(0.0f, 0.0f, 0.0f); } +ccl_device_noinline_cpu float3 svm_mix_clamped_factor(NodeMix type, float t, float3 c1, float3 c2) +{ + float fac = saturatef(t); + return svm_mix(type, fac, c1, c2); +} + ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast) { float a = 1.0f + contrast; diff --git a/intern/cycles/kernel/svm/mix.h b/intern/cycles/kernel/svm/mix.h index a9796096410..ead2fc44685 100644 --- a/intern/cycles/kernel/svm/mix.h +++ b/intern/cycles/kernel/svm/mix.h @@ -21,10 +21,94 @@ ccl_device_noinline int svm_node_mix(KernelGlobals kg, float fac = stack_load_float(stack, fac_offset); float3 c1 = stack_load_float3(stack, c1_offset); float3 c2 = stack_load_float3(stack, c2_offset); - float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2); + float3 result = svm_mix_clamped_factor((NodeMix)node1.y, fac, c1, c2); stack_store_float3(stack, node1.z, result); return offset; } +ccl_device_noinline void svm_node_mix_color(ccl_private ShaderData *sd, + ccl_private float *stack, + uint options, + uint input_offset, + uint result_offset) +{ + uint use_clamp, blend_type, use_clamp_result; + uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar3(options, &use_clamp, &blend_type, &use_clamp_result); + svm_unpack_node_uchar3( + input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = svm_mix((NodeMix)blend_type, t, a, b); + if (use_clamp_result) { + result = saturate(result); + } + stack_store_float3(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_float(ccl_private ShaderData *sd, + ccl_private float *stack, + uint use_clamp, + uint input_offset, + uint result_offset) +{ + uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar3( + input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float a = stack_load_float(stack, a_in_stack_offset); + float b = stack_load_float(stack, b_in_stack_offset); + float result = a * (1 - t) + b * t; + + stack_store_float(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_vector(ccl_private ShaderData *sd, + ccl_private float *stack, + uint input_offset, + uint result_offset) +{ + uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar4( + input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = a * (one_float3() - t) + b * t; + stack_store_float3(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_vector_non_uniform(ccl_private ShaderData *sd, + ccl_private float *stack, + uint input_offset, + uint result_offset) +{ + uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar4( + input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float3 t = stack_load_float3(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturate(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = a * (one_float3() - t) + b * t; + stack_store_float3(stack, result_offset, result); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/node_types_template.h b/intern/cycles/kernel/svm/node_types_template.h index 39d279be4cb..aab9b9f1158 100644 --- a/intern/cycles/kernel/svm/node_types_template.h +++ b/intern/cycles/kernel/svm/node_types_template.h @@ -103,6 +103,10 @@ SHADER_NODE_TYPE(NODE_AOV_START) SHADER_NODE_TYPE(NODE_AOV_COLOR) SHADER_NODE_TYPE(NODE_AOV_VALUE) SHADER_NODE_TYPE(NODE_FLOAT_CURVE) +SHADER_NODE_TYPE(NODE_MIX_COLOR) +SHADER_NODE_TYPE(NODE_MIX_FLOAT) +SHADER_NODE_TYPE(NODE_MIX_VECTOR) +SHADER_NODE_TYPE(NODE_MIX_VECTOR_NON_UNIFORM) /* Padding for struct alignment. */ SHADER_NODE_TYPE(NODE_PAD1) diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 9d6d3e9222c..3ca632c5f0b 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -585,6 +585,18 @@ ccl_device void svm_eval_nodes(KernelGlobals kg, SVM_CASE(NODE_AOV_VALUE) svm_node_aov_value(kg, state, sd, stack, node, render_buffer); break; + SVM_CASE(NODE_MIX_COLOR) + svm_node_mix_color(sd, stack, node.y, node.z, node.w); + break; + SVM_CASE(NODE_MIX_FLOAT) + svm_node_mix_float(sd, stack, node.y, node.z, node.w); + break; + SVM_CASE(NODE_MIX_VECTOR) + svm_node_mix_vector(sd, stack, node.y, node.z); + break; + SVM_CASE(NODE_MIX_VECTOR_NON_UNIFORM) + svm_node_mix_vector_non_uniform(sd, stack, node.y, node.z); + break; default: kernel_assert(!"Unknown node type was passed to the SVM machine"); return; diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index 98dfe6a4375..9dd8f196e0f 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -133,7 +133,7 @@ typedef enum NodeMix { NODE_MIX_HUE, NODE_MIX_SAT, NODE_MIX_VAL, - NODE_MIX_COLOR, + NODE_MIX_COL, NODE_MIX_SOFT, NODE_MIX_LINEAR, NODE_MIX_CLAMP /* used for the clamp UI option */ diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp index 4bce5661f9b..1aa4515a087 100644 --- a/intern/cycles/scene/constant_fold.cpp +++ b/intern/cycles/scene/constant_fold.cpp @@ -291,6 +291,101 @@ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const } } +void ConstantFolder::fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const +{ + ShaderInput *fac_in = node->input("Factor"); + ShaderInput *color1_in = node->input("A"); + ShaderInput *color2_in = node->input("B"); + + float fac = clamp_factor ? saturatef(node->get_float(fac_in->socket_type)) : + node->get_float(fac_in->socket_type); + bool fac_is_zero = !fac_in->link && fac == 0.0f; + bool fac_is_one = !fac_in->link && fac == 1.0f; + + /* remove no-op node when factor is 0.0 */ + if (fac_is_zero) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { + if (try_bypass_or_make_constant(color1_in, clamp)) { + return; + } + } + } + + switch (type) { + case NODE_MIX_BLEND: + /* remove useless mix colors nodes */ + if (color1_in->link && color2_in->link) { + if (color1_in->link == color2_in->link) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + else if (!color1_in->link && !color2_in->link) { + float3 color1 = node->get_float3(color1_in->socket_type); + float3 color2 = node->get_float3(color2_in->socket_type); + if (color1 == color2) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + /* remove no-op mix color node when factor is 1.0 */ + if (fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + break; + } + break; + case NODE_MIX_ADD: + /* 0 + X (fac 1) == X */ + if (is_zero(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + /* X + 0 (fac ?) == X */ + else if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + break; + case NODE_MIX_SUB: + /* X - 0 (fac ?) == X */ + if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* X - X (fac 1) == 0 */ + else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_MUL: + /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ + if (is_one(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + else if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + else if (is_zero(color2_in) && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_DIV: + /* X / 1 (fac ?) == X */ + if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 / ? (fac ?) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + break; + default: + break; + } +} + void ConstantFolder::fold_math(NodeMathType type) const { ShaderInput *value1_in = node->input("Value1"); diff --git a/intern/cycles/scene/constant_fold.h b/intern/cycles/scene/constant_fold.h index 090ce367e6c..246ff2d31ee 100644 --- a/intern/cycles/scene/constant_fold.h +++ b/intern/cycles/scene/constant_fold.h @@ -51,6 +51,7 @@ class ConstantFolder { /* Specific nodes. */ void fold_mix(NodeMix type, bool clamp) const; + void fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const; void fold_math(NodeMathType type) const; void fold_vector_math(NodeVectorMathType type) const; void fold_mapping(NodeMappingType type) const; diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index bedb0fe2902..a9cd453947b 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -4950,7 +4950,7 @@ NODE_DEFINE(MixNode) type_enum.insert("hue", NODE_MIX_HUE); type_enum.insert("saturation", NODE_MIX_SAT); type_enum.insert("value", NODE_MIX_VAL); - type_enum.insert("color", NODE_MIX_COLOR); + type_enum.insert("color", NODE_MIX_COL); type_enum.insert("soft_light", NODE_MIX_SOFT); type_enum.insert("linear_light", NODE_MIX_LINEAR); SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND); @@ -4999,13 +4999,253 @@ void MixNode::compile(OSLCompiler &compiler) void MixNode::constant_fold(const ConstantFolder &folder) { if (folder.all_inputs_constant()) { - folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp); + folder.make_constant_clamp(svm_mix_clamped_factor(mix_type, fac, color1, color2), use_clamp); } else { folder.fold_mix(mix_type, use_clamp); } } +/* Mix Color */ + +NODE_DEFINE(MixColorNode) +{ + NodeType *type = NodeType::add("mix_color", create, NodeType::SHADER); + + static NodeEnum type_enum; + type_enum.insert("mix", NODE_MIX_BLEND); + type_enum.insert("add", NODE_MIX_ADD); + type_enum.insert("multiply", NODE_MIX_MUL); + type_enum.insert("screen", NODE_MIX_SCREEN); + type_enum.insert("overlay", NODE_MIX_OVERLAY); + type_enum.insert("subtract", NODE_MIX_SUB); + type_enum.insert("divide", NODE_MIX_DIV); + type_enum.insert("difference", NODE_MIX_DIFF); + type_enum.insert("darken", NODE_MIX_DARK); + type_enum.insert("lighten", NODE_MIX_LIGHT); + type_enum.insert("dodge", NODE_MIX_DODGE); + type_enum.insert("burn", NODE_MIX_BURN); + type_enum.insert("hue", NODE_MIX_HUE); + type_enum.insert("saturation", NODE_MIX_SAT); + type_enum.insert("value", NODE_MIX_VAL); + type_enum.insert("color", NODE_MIX_COL); + type_enum.insert("soft_light", NODE_MIX_SOFT); + type_enum.insert("linear_light", NODE_MIX_LINEAR); + SOCKET_ENUM(blend_type, "Type", type_enum, NODE_MIX_BLEND); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_COLOR(a, "A", zero_float3()); + SOCKET_IN_COLOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp_result, "Use Clamp Result", false); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_COLOR(result, "Result"); + + return type; +} + +MixColorNode::MixColorNode() : ShaderNode(get_node_type()) +{ +} + +void MixColorNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_COLOR, + compiler.encode_uchar4(use_clamp, blend_type, use_clamp_result), + compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixColorNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "blend_type"); + compiler.parameter(this, "use_clamp"); + compiler.parameter(this, "use_clamp_result"); + compiler.add(this, "node_mix_color"); +} + +void MixColorNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant_clamp(svm_mix(blend_type, fac, a, b), use_clamp_result); + } + else { + folder.fold_mix_color(blend_type, use_clamp, use_clamp_result); + } +} + +/* Mix Float */ + +NODE_DEFINE(MixFloatNode) +{ + NodeType *type = NodeType::add("mix_float", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_FLOAT(a, "A", 0.0f); + SOCKET_IN_FLOAT(b, "B", 0.0f); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + SOCKET_OUT_FLOAT(result, "Result"); + + return type; +} + +MixFloatNode::MixFloatNode() : ShaderNode(get_node_type()) +{ +} + +void MixFloatNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_FLOAT, + use_clamp, + compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixFloatNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_float"); +} + +void MixFloatNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant(a * (1 - fac) + b * fac); + } +} + +/* Mix Vector */ + +NODE_DEFINE(MixVectorNode) +{ + NodeType *type = NodeType::add("mix_vector", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_VECTOR(a, "A", zero_float3()); + SOCKET_IN_VECTOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_VECTOR(result, "Result"); + + return type; +} + +MixVectorNode::MixVectorNode() : ShaderNode(get_node_type()) +{ +} + +void MixVectorNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_VECTOR, + compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixVectorNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_vector"); +} + +void MixVectorNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant(a * (one_float3() - fac) + b * fac); + } +} + +/* Mix Vector Non Uniform */ + +NODE_DEFINE(MixVectorNonUniformNode) +{ + NodeType *type = NodeType::add("mix_vector_non_uniform", create, NodeType::SHADER); + + SOCKET_IN_VECTOR(fac, "Factor", make_float3(0.5f, 0.5f, 0.5f)); + SOCKET_IN_VECTOR(a, "A", zero_float3()); + SOCKET_IN_VECTOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_VECTOR(result, "Result"); + + return type; +} + +MixVectorNonUniformNode::MixVectorNonUniformNode() : ShaderNode(get_node_type()) +{ +} + +void MixVectorNonUniformNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_VECTOR_NON_UNIFORM, + compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixVectorNonUniformNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_vector_non_uniform"); +} + +void MixVectorNonUniformNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = saturate(fac); + } + folder.make_constant(a * (one_float3() - fac) + b * fac); + } +} + /* Combine Color */ NODE_DEFINE(CombineColorNode) diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index ac40a397c1e..cc3a71a0697 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -1101,6 +1101,52 @@ class MixNode : public ShaderNode { NODE_SOCKET_API(float, fac) }; +class MixColorNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixColorNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) + NODE_SOCKET_API(bool, use_clamp_result) + NODE_SOCKET_API(NodeMix, blend_type) +}; + +class MixFloatNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixFloatNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float, a) + NODE_SOCKET_API(float, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + +class MixVectorNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixVectorNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + +class MixVectorNonUniformNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixVectorNonUniformNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float3, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + class CombineColorNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineColorNode) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 2342ba33a3b..2091457aa59 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -424,7 +424,6 @@ shader_node_categories = [ NodeItem("ShaderNodeTexWhiteNoise"), ]), ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeInvert"), NodeItem("ShaderNodeLightFalloff"), @@ -448,6 +447,7 @@ shader_node_categories = [ NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), NodeItem("ShaderNodeMath"), + NodeItem("ShaderNodeMix"), NodeItem("ShaderNodeValToRGB"), NodeItem("ShaderNodeRGBToBW"), NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll), @@ -651,7 +651,6 @@ geometry_node_categories = [ NodeItem("GeometryNodeStoreNamedAttribute"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeValToRGB"), NodeItem("FunctionNodeSeparateColor"), @@ -719,6 +718,7 @@ geometry_node_categories = [ NodeItem("FunctionNodeBooleanMath"), NodeItem("FunctionNodeRotateEuler"), NodeItem("FunctionNodeCompare"), + NodeItem("ShaderNodeMix"), NodeItem("FunctionNodeFloatToInt"), NodeItem("GeometryNodeSwitch"), NodeItem("FunctionNodeRandomValue"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 509de0620c6..1118552b643 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1102,7 +1102,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i //#define SH_NODE_MATERIAL 100 #define SH_NODE_RGB 101 #define SH_NODE_VALUE 102 -#define SH_NODE_MIX_RGB 103 +#define SH_NODE_MIX_RGB_LEGACY 103 #define SH_NODE_VALTORGB 104 #define SH_NODE_RGBTOBW 105 #define SH_NODE_SHADERTORGB 106 @@ -1205,6 +1205,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define SH_NODE_POINT_INFO 710 #define SH_NODE_COMBINE_COLOR 711 #define SH_NODE_SEPARATE_COLOR 712 +#define SH_NODE_MIX 713 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 4ed2885dd90..1a40c0a18ed 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4583,6 +4583,7 @@ static void registerShaderNodes() register_node_type_sh_wavelength(); register_node_type_sh_blackbody(); register_node_type_sh_mix_rgb(); + register_node_type_sh_mix(); register_node_type_sh_valtorgb(); register_node_type_sh_rgbtobw(); register_node_type_sh_shadertorgb(); diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index b98f8996a2c..4d604fc7eec 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1697,6 +1697,27 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre } } +static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree) +{ + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Fac", "Factor_Float"); + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color1", "A_Color"); + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color2", "B_Color"); + version_node_output_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color", "Result_Color"); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MIX_RGB_LEGACY) { + strcpy(node->idname, "ShaderNodeMix"); + node->type = SH_NODE_MIX; + NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__); + data->blend_type = node->custom1; + data->clamp_result = node->custom2; + data->clamp_factor = 1; + data->data_type = SOCK_RGBA; + data->factor_mode = NODE_MIX_MODE_UNIFORM; + node->storage = data; + } + } +} + static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format) { /* Fix bug where curves in image format were not properly copied to file output @@ -3332,5 +3353,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Convert mix rgb node to new mix node and add storage. */ + { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + versioning_replace_legacy_mix_rgb_node(ntree); + } + FOREACH_NODETREE_END; + } } } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 25ab06850f5..e8325d658ca 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -477,7 +477,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_RGB: ntype->draw_buttons = node_buts_rgb; break; - case SH_NODE_MIX_RGB: + case SH_NODE_MIX_RGB_LEGACY: ntype->draw_buttons = node_buts_mix_rgb; break; case SH_NODE_VALTORGB: diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 87a2d1620aa..3df0d723aec 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -232,7 +232,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, storage = (NodeShaderAttribute *)input_attr_color->storage; BLI_strncpy(storage->name, "Color", sizeof(storage->name)); - bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB); + bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY); mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix mix_rgb_color->locx = 200.0f; mix_rgb_color->locy = -200.0f; @@ -246,7 +246,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, storage = (NodeShaderAttribute *)input_attr_alpha->storage; BLI_strncpy(storage->name, "Alpha", sizeof(storage->name)); - bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB); + bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY); mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix mix_rgb_alpha->locx = 600.0f; mix_rgb_alpha->locy = 300.0f; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0c11ecb293b..c289a21421a 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -394,6 +394,7 @@ set(GLSL_SRC shaders/material/gpu_shader_material_light_path.glsl shaders/material/gpu_shader_material_mapping.glsl shaders/material/gpu_shader_material_map_range.glsl + shaders/material/gpu_shader_material_mix_color.glsl shaders/material/gpu_shader_material_mix_shader.glsl shaders/material/gpu_shader_material_noise.glsl shaders/material/gpu_shader_material_normal.glsl diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl new file mode 100644 index 00000000000..933a8de9cb7 --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl @@ -0,0 +1,537 @@ +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) + +void node_mix_blend(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = mix(col1, col2, fac); + outcol.a = col1.a; +} + +void node_mix_add(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 + col2, fac); + outcol.a = col1.a; +} + +void node_mix_mult(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 * col2, fac); + outcol.a = col1.a; +} + +void node_mix_screen(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1); + outcol.a = col1.a; +} + +void node_mix_overlay(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + if (outcol.r < 0.5) { + outcol.r *= facm + 2.0 * fac * col2.r; + } + else { + outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r); + } + + if (outcol.g < 0.5) { + outcol.g *= facm + 2.0 * fac * col2.g; + } + else { + outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g); + } + + if (outcol.b < 0.5) { + outcol.b *= facm + 2.0 * fac * col2.b; + } + else { + outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b); + } +} + +void node_mix_sub(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 - col2, fac); + outcol.a = col1.a; +} + +/* A variant of mix_div that fallback to the first color upon zero division. */ +void node_mix_div_fallback(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + if (col2.r != 0.0) { + outcol.r = facm * outcol.r + fac * outcol.r / col2.r; + } + if (col2.g != 0.0) { + outcol.g = facm * outcol.g + fac * outcol.g / col2.g; + } + if (col2.b != 0.0) { + outcol.b = facm * outcol.b + fac * outcol.b / col2.b; + } +} + +void node_mix_diff(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, abs(col1 - col2), fac); + outcol.a = col1.a; +} + +void node_mix_dark(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac); + outcol.a = col1.a; +} + +void node_mix_light(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac); + outcol.a = col1.a; +} + +void node_mix_dodge(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = col1; + + if (outcol.r != 0.0) { + float tmp = 1.0 - fac * col2.r; + if (tmp <= 0.0) { + outcol.r = 1.0; + } + else if ((tmp = outcol.r / tmp) > 1.0) { + outcol.r = 1.0; + } + else { + outcol.r = tmp; + } + } + if (outcol.g != 0.0) { + float tmp = 1.0 - fac * col2.g; + if (tmp <= 0.0) { + outcol.g = 1.0; + } + else if ((tmp = outcol.g / tmp) > 1.0) { + outcol.g = 1.0; + } + else { + outcol.g = tmp; + } + } + if (outcol.b != 0.0) { + float tmp = 1.0 - fac * col2.b; + if (tmp <= 0.0) { + outcol.b = 1.0; + } + else if ((tmp = outcol.b / tmp) > 1.0) { + outcol.b = 1.0; + } + else { + outcol.b = tmp; + } + } +} + +void node_mix_burn(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float tmp, facm = 1.0 - fac; + + outcol = col1; + + tmp = facm + fac * col2.r; + if (tmp <= 0.0) { + outcol.r = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) { + outcol.r = 0.0; + } + else if (tmp > 1.0) { + outcol.r = 1.0; + } + else { + outcol.r = tmp; + } + + tmp = facm + fac * col2.g; + if (tmp <= 0.0) { + outcol.g = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) { + outcol.g = 0.0; + } + else if (tmp > 1.0) { + outcol.g = 1.0; + } + else { + outcol.g = tmp; + } + + tmp = facm + fac * col2.b; + if (tmp <= 0.0) { + outcol.b = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) { + outcol.b = 0.0; + } + else if (tmp > 1.0) { + outcol.b = 1.0; + } + else { + outcol.b = tmp; + } +} + +void node_mix_hue(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2, tmp; + rgb_to_hsv(col2, hsv2); + + if (hsv2.y != 0.0) { + rgb_to_hsv(outcol, hsv); + hsv.x = hsv2.x; + hsv_to_rgb(hsv, tmp); + + outcol = mix(outcol, tmp, fac); + outcol.a = col1.a; + } +} + +void node_mix_sat(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2; + rgb_to_hsv(outcol, hsv); + + if (hsv.y != 0.0) { + rgb_to_hsv(col2, hsv2); + + hsv.y = facm * hsv.y + fac * hsv2.y; + hsv_to_rgb(hsv, outcol); + } +} + +void node_mix_val(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + vec4 hsv, hsv2; + rgb_to_hsv(col1, hsv); + rgb_to_hsv(col2, hsv2); + + hsv.z = facm * hsv.z + fac * hsv2.z; + hsv_to_rgb(hsv, outcol); +} + +void node_mix_color(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2, tmp; + rgb_to_hsv(col2, hsv2); + + if (hsv2.y != 0.0) { + rgb_to_hsv(outcol, hsv); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + hsv_to_rgb(hsv, tmp); + + outcol = mix(outcol, tmp, fac); + outcol.a = col1.a; + } +} + +void node_mix_soft(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + vec4 one = vec4(1.0); + vec4 scr = one - (one - col2) * (one - col1); + outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr); +} + +void node_mix_linear(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = col1 + fac * (2.0 * (col2 - vec4(0.5))); +} + +void node_mix_float(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outfloat = mix(f1, f2, fac); +} + +void node_mix_vector(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outvec = mix(v1, v2, fac); +} + +void node_mix_vector_non_uniform(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outvec = mix(v1, v2, facvec); +} + +void node_mix_rgba(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = mix(col1, col2, fac); +} + +void node_mix_clamp_vector(vec3 vec, vec3 min, vec3 max, out vec3 outvec) +{ + outvec = clamp(vec, min, max); +} + +void node_mix_clamp_value(float value, float min, float max, out float outfloat) +{ + outfloat = clamp(value, min, max); +} diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 3477105f519..4ae06d0a5e4 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1475,6 +1475,17 @@ typedef struct NodeCombSepColor { int8_t mode; } NodeCombSepColor; +typedef struct NodeShaderMix { + /* eNodeSocketDatatype */ + int8_t data_type; + /* NodeShaderMixMode */ + int8_t factor_mode; + int8_t clamp_factor; + int8_t clamp_result; + int8_t blend_type; + char _pad[3]; +} NodeShaderMix; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1762,6 +1773,11 @@ typedef enum NodeBooleanMathOperation { NODE_BOOLEAN_MATH_NIMPLY = 8, } NodeBooleanMathOperation; +typedef enum NodeShaderMixMode { + NODE_MIX_MODE_UNIFORM = 0, + NODE_MIX_MODE_NON_UNIFORM = 1, +} NodeShaderMixMode; + typedef enum NodeCompareMode { NODE_COMPARE_MODE_ELEMENT = 0, NODE_COMPARE_MODE_LENGTH = 1, diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 1573a1df002..60a57bae78a 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4927,6 +4927,54 @@ static void def_compare(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_sh_mix(StructRNA *srna) +{ + static const EnumPropertyItem rna_enum_mix_data_type_items[] = { + {SOCK_FLOAT, "FLOAT", 0, "Float", ""}, + {SOCK_VECTOR, "VECTOR", 0, "Vector", ""}, + {SOCK_RGBA, "RGBA", 0, "Color", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem rna_enum_mix_mode_items[] = { + {NODE_MIX_MODE_UNIFORM, "UNIFORM", 0, "Uniform", "Use a single factor for all components"}, + {NODE_MIX_MODE_NON_UNIFORM, "NON_UNIFORM", 0, "Non-Uniform", "Per component factor"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeShaderMix", "storage"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_mix_data_type_items); + RNA_def_property_enum_default(prop, SOCK_FLOAT); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "factor_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_mix_mode_items); + RNA_def_property_enum_default(prop, SOCK_FLOAT); + RNA_def_property_ui_text(prop, "Factor Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "blend_type"); + RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); + RNA_def_property_ui_text(prop, "Blending Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "clamp_factor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "clamp_factor", 1); + RNA_def_property_ui_text(prop, "Clamp Factor", "Clamp the factor to [0,1] range"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "clamp_result", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "clamp_result", 1); + RNA_def_property_ui_text(prop, "Clamp Result", "Clamp the result to [0,1] range"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_float_to_int(StructRNA *srna) { PropertyRNA *prop; @@ -10964,6 +11012,12 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Linked", "True if the socket is connected"); + prop = RNA_def_property(srna, "is_unavailable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_UNAVAIL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Unavailable", "True if the socket is unavailable"); + prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 1d1310360b8..8fe77bffaad 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -26,6 +26,7 @@ void register_node_type_sh_camera(void); void register_node_type_sh_value(void); void register_node_type_sh_rgb(void); void register_node_type_sh_mix_rgb(void); +void register_node_type_sh_mix(void); void register_node_type_sh_valtorgb(void); void register_node_type_sh_rgbtobw(void); void register_node_type_sh_shadertorgb(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 786ce88152e..e6cdd462c66 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -25,7 +25,7 @@ DefNode(Node, NODE_REROUTE, 0, "REROUT DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker") DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Used to Input numerical values to other nodes in the tree") -DefNode(ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors") +DefNode(ShaderNode, SH_NODE_MIX_RGB_LEGACY, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors") DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "Map values to colors with the use of a gradient") DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "Convert a color's luminance to a grayscale value") DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee") @@ -122,6 +122,7 @@ DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUT DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "Map an input float to a curve and outputs a float value") DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "Create a color from individual components using multiple models") DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "Split a color into its individual components using multiple models") +DefNode(ShaderNode, SH_NODE_MIX, def_sh_mix, "MIX", Mix, "Mix", "Mix values by a factor") DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 3e90f185168..d135f9a12a4 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC nodes/node_shader_mapping.cc nodes/node_shader_math.cc nodes/node_shader_mix_rgb.cc + nodes/node_shader_mix.cc nodes/node_shader_mix_shader.cc nodes/node_shader_normal.cc nodes/node_shader_normal_map.cc diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc new file mode 100644 index 00000000000..05aad262af8 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -0,0 +1,443 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2005 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup shdnodes + */ + +#include + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_shader_util.hh" + +#include "NOD_socket_search_link.hh" +#include "RNA_enum_types.h" + +namespace blender::nodes::node_sh_mix_cc { + +NODE_STORAGE_FUNCS(NodeShaderMix) + +static void sh_node_mix_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input(N_("Factor"), "Factor_Float") + .default_value(0.5f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR); + b.add_input(N_("Factor"), "Factor_Vector") + .default_value(float3(0.5f)) + .subtype(PROP_FACTOR); + + b.add_input(N_("A"), "A_Float") + .min(-10000.0f) + .max(10000.0f) + .is_default_link_socket(); + b.add_input(N_("B"), "B_Float").min(-10000.0f).max(10000.0f); + + b.add_input(N_("A"), "A_Vector").is_default_link_socket(); + b.add_input(N_("B"), "B_Vector"); + + b.add_input(N_("A"), "A_Color") + .default_value({0.5f, 0.5f, 0.5f, 1.0f}) + .is_default_link_socket(); + b.add_input(N_("B"), "B_Color").default_value({0.5f, 0.5f, 0.5f, 1.0f}); + + b.add_output(N_("Result"), "Result_Float"); + b.add_output(N_("Result"), "Result_Vector"); + b.add_output(N_("Result"), "Result_Color"); +}; + +static void sh_node_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const NodeShaderMix &data = node_storage(*static_cast(ptr->data)); + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + if (data.data_type == SOCK_VECTOR) { + uiItemR(layout, ptr, "factor_mode", 0, "", ICON_NONE); + } + if (data.data_type == SOCK_RGBA) { + uiItemR(layout, ptr, "blend_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "clamp_result", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE); + } + else { + uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE); + } +} + +static void sh_node_mix_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) +{ + const NodeShaderMix &storage = node_storage(*node); + if (storage.data_type == SOCK_RGBA) { + const char *name; + bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, storage.blend_type, &name); + if (!enum_label) { + name = "Unknown"; + } + BLI_strncpy(label, IFACE_(name), maxlen); + } +} + +static int sh_node_mix_ui_class(const bNode *node) +{ + const NodeShaderMix &storage = node_storage(*node); + const eNodeSocketDatatype data_type = static_cast(storage.data_type); + + switch (data_type) { + case SOCK_VECTOR: + return NODE_CLASS_OP_VECTOR; + case SOCK_RGBA: + return NODE_CLASS_OP_COLOR; + default: + return NODE_CLASS_CONVERTER; + } +} + +static void sh_node_mix_update(bNodeTree *ntree, bNode *node) +{ + const NodeShaderMix &storage = node_storage(*node); + const eNodeSocketDatatype data_type = static_cast(storage.data_type); + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == data_type); + } + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == data_type); + } + + bool use_vector_factor = data_type == SOCK_VECTOR && + storage.factor_mode != NODE_MIX_MODE_UNIFORM; + + bNodeSocket *sock_factor = (bNodeSocket *)BLI_findlink(&node->inputs, 0); + nodeSetSocketAvailability(ntree, sock_factor, !use_vector_factor); + + bNodeSocket *sock_factor_vec = (bNodeSocket *)BLI_findlink(&node->inputs, 1); + nodeSetSocketAvailability(ntree, sock_factor_vec, use_vector_factor); +} + +static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const eNodeSocketDatatype sock_type = static_cast( + params.other_socket().type); + + if (ELEM(sock_type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) { + const eNodeSocketDatatype type = ELEM(sock_type, SOCK_BOOLEAN, SOCK_INT) ? SOCK_FLOAT : + sock_type; + + if (params.in_out() == SOCK_OUT) { + params.add_item(IFACE_("Result"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "Result"); + }); + } + else { + if (ELEM(sock_type, SOCK_VECTOR, SOCK_RGBA)) { + params.add_item(IFACE_("Factor (Non-Uniform)"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = SOCK_VECTOR; + node_storage(node).factor_mode = NODE_MIX_MODE_NON_UNIFORM; + params.update_and_connect_available_socket(node, "Factor"); + }); + } + params.add_item(IFACE_("Factor"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "Factor"); + }); + params.add_item(IFACE_("A"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "A"); + }); + params.add_item(IFACE_("B"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "B"); + }); + } + } +} + +static void node_mix_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeShaderMix *data = MEM_cnew(__func__); + data->data_type = SOCK_FLOAT; + data->factor_mode = NODE_MIX_MODE_UNIFORM; + data->clamp_factor = 1; + data->clamp_result = 0; + data->blend_type = MA_RAMP_BLEND; + node->storage = data; +} + +static const char *gpu_shader_get_name(eNodeSocketDatatype data_type, + const bool non_uniform, + const int blend_type) +{ + switch (data_type) { + case SOCK_FLOAT: + return "node_mix_float"; + case SOCK_VECTOR: + return (non_uniform) ? "node_mix_vector_non_uniform" : "node_mix_vector"; + case SOCK_RGBA: + switch (blend_type) { + case MA_RAMP_BLEND: + return "node_mix_blend"; + case MA_RAMP_ADD: + return "node_mix_add"; + case MA_RAMP_MULT: + return "node_mix_mult"; + case MA_RAMP_SUB: + return "node_mix_sub"; + case MA_RAMP_SCREEN: + return "node_mix_screen"; + case MA_RAMP_DIV: + return "node_mix_div_fallback"; + case MA_RAMP_DIFF: + return "node_mix_diff"; + case MA_RAMP_DARK: + return "node_mix_dark"; + case MA_RAMP_LIGHT: + return "node_mix_light"; + case MA_RAMP_OVERLAY: + return "node_mix_overlay"; + case MA_RAMP_DODGE: + return "node_mix_dodge"; + case MA_RAMP_BURN: + return "node_mix_burn"; + case MA_RAMP_HUE: + return "node_mix_hue"; + case MA_RAMP_SAT: + return "node_mix_sat"; + case MA_RAMP_VAL: + return "node_mix_val"; + case MA_RAMP_COLOR: + return "node_mix_color"; + case MA_RAMP_SOFT: + return "node_mix_soft"; + case MA_RAMP_LINEAR: + return "node_mix_linear"; + default: + BLI_assert_unreachable(); + return nullptr; + } + default: + BLI_assert_unreachable(); + return nullptr; + } +} + +static int gpu_shader_mix(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + const NodeShaderMix &storage = node_storage(*node); + const bool is_non_uniform = storage.factor_mode == NODE_MIX_MODE_NON_UNIFORM; + const bool is_color_mode = storage.data_type == SOCK_RGBA; + const bool is_vector_mode = storage.data_type == SOCK_VECTOR; + const int blend_type = storage.blend_type; + const char *name = gpu_shader_get_name( + (eNodeSocketDatatype)storage.data_type, is_non_uniform, blend_type); + + if (name == nullptr) { + return 0; + } + + if (storage.clamp_factor) { + if (is_non_uniform && is_vector_mode) { + const float min[3] = {0.0f, 0.0f, 0.0f}; + const float max[3] = {1.0f, 1.0f, 1.0f}; + const GPUNodeLink *factor_link = in[1].link ? in[1].link : GPU_uniform(in[1].vec); + GPU_link(mat, + "node_mix_clamp_vector", + factor_link, + GPU_constant(min), + GPU_constant(max), + &in[1].link); + } + else { + const float min = 0.0f; + const float max = 1.0f; + const GPUNodeLink *factor_link = in[0].link ? in[0].link : GPU_uniform(in[0].vec); + GPU_link(mat, + "node_mix_clamp_value", + factor_link, + GPU_constant(&min), + GPU_constant(&max), + &in[0].link); + } + } + + int ret = GPU_stack_link(mat, node, name, in, out); + + if (ret && is_color_mode && storage.clamp_result) { + const float min[3] = {0.0f, 0.0f, 0.0f}; + const float max[3] = {1.0f, 1.0f, 1.0f}; + GPU_link(mat, + "node_mix_clamp_vector", + out[2].link, + GPU_constant(min), + GPU_constant(max), + &out[2].link); + } + return ret; +} + +class MixColorFunction : public fn::MultiFunction { + private: + const bool clamp_factor_; + const bool clamp_result_; + const int blend_type_; + + public: + MixColorFunction(const bool clamp_factor, const bool clamp_result, const int blend_type) + : clamp_factor_(clamp_factor), clamp_result_(clamp_result), blend_type_(blend_type) + { + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static fn::MFSignature create_signature() + { + fn::MFSignatureBuilder signature{"MixColor"}; + signature.single_input("Factor"); + signature.single_input("A"); + signature.single_input("B"); + signature.single_output("Result"); + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArray &fac = params.readonly_single_input(0, "Factor"); + const VArray &col1 = params.readonly_single_input(1, "A"); + const VArray &col2 = params.readonly_single_input(2, "B"); + MutableSpan results = params.uninitialized_single_output( + 3, "Result"); + + if (clamp_factor_) { + for (int64_t i : mask) { + results[i] = col1[i]; + ramp_blend(blend_type_, results[i], std::clamp(fac[i], 0.0f, 1.0f), col2[i]); + } + } + else { + for (int64_t i : mask) { + results[i] = col1[i]; + ramp_blend(blend_type_, results[i], fac[i], col2[i]); + } + } + + if (clamp_result_) { + for (int64_t i : mask) { + clamp_v3(results[i], 0.0f, 1.0f); + } + } + } +}; + +static const fn::MultiFunction *get_multi_function(bNode &node) +{ + const NodeShaderMix *data = (NodeShaderMix *)node.storage; + bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM; + const bool clamp_factor = data->clamp_factor; + switch (data->data_type) { + case SOCK_FLOAT: { + if (clamp_factor) { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Clamp Mix Float", [](float t, const float a, const float b) { + return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f)); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Mix Float", [](const float t, const float a, const float b) { + return math::interpolate(a, b, t); + }}; + return &fn; + } + } + case SOCK_VECTOR: { + if (clamp_factor) { + if (uniform_factor) { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Clamp Mix Vector", [](const float t, const float3 a, const float3 b) { + return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f)); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Clamp Mix Vector Non Uniform", [](float3 t, const float3 a, const float3 b) { + t = math::clamp(t, 0.0f, 1.0f); + return a * (float3(1.0f) - t) + b * t; + }}; + return &fn; + } + } + else { + if (uniform_factor) { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Mix Vector", [](const float t, const float3 a, const float3 b) { + return math::interpolate(a, b, t); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO fn{ + "Mix Vector Non Uniform", [](const float3 t, const float3 a, const float3 b) { + return a * (float3(1.0f) - t) + b * t; + }}; + return &fn; + } + } + } + } + BLI_assert_unreachable(); + return nullptr; +} + +static void sh_node_mix_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + const NodeShaderMix &storage = node_storage(builder.node()); + + if (storage.data_type == SOCK_RGBA) { + builder.construct_and_set_matching_fn( + storage.clamp_factor, storage.clamp_result, storage.blend_type); + } + else { + const fn::MultiFunction *fn = get_multi_function(builder.node()); + builder.set_matching_fn(fn); + } +} + +} // namespace blender::nodes::node_sh_mix_cc + +void register_node_type_sh_mix() +{ + namespace file_ns = blender::nodes::node_sh_mix_cc; + + static bNodeType ntype; + sh_fn_node_type_base(&ntype, SH_NODE_MIX, "Mix", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_mix_declare; + ntype.ui_class = file_ns::sh_node_mix_ui_class; + node_type_gpu(&ntype, file_ns::gpu_shader_mix); + node_type_update(&ntype, file_ns::sh_node_mix_update); + node_type_init(&ntype, file_ns::node_mix_init); + node_type_storage( + &ntype, "NodeShaderMix", node_free_standard_storage, node_copy_standard_storage); + ntype.build_multi_function = file_ns::sh_node_mix_build_multi_function; + ntype.draw_buttons = file_ns::sh_node_mix_layout; + ntype.labelfunc = file_ns::sh_node_mix_label; + ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index 478a6812c36..edbded43acf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -150,11 +150,11 @@ void register_node_type_sh_mix_rgb() static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR); + sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::sh_node_mix_rgb_declare; ntype.labelfunc = node_blend_label; node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb); ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function; - + ntype.gather_link_search_ops = nullptr; nodeRegisterType(&ntype); } -- cgit v1.2.3 From 66fecfcda6f5e0dacf3d86091e08292e8624c895 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Thu, 18 Aug 2022 20:46:04 +0800 Subject: LineArt: Fix (unreported) wrong index in weight transfer Line art now uses global index for vertices but needs to have local index in order to do correct weight transfer. --- .../gpencil_modifiers/intern/lineart/MOD_lineart.h | 6 ++++ .../intern/lineart/lineart_chain.c | 32 ++++++++++++++++++++++ .../gpencil_modifiers/intern/lineart/lineart_cpu.c | 3 ++ .../intern/lineart/lineart_intern.h | 1 + 4 files changed, 42 insertions(+) diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 8d34fb2ffb2..895ffcc7818 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -84,6 +84,7 @@ typedef struct LineartElementLinkNode { /* For edge element link nodes, used for shadow edge matching. */ int obindex; + int global_index_offset; /** Per object value, always set, if not enabled by #ObjectLineArt, then it's set to global. */ float crease_threshold; @@ -205,6 +206,10 @@ typedef struct LineartEdgeChain { uint8_t intersection_mask; uint32_t shadow_mask_bits; + /* We need local index for correct weight transfer, line art index is global, thus + * local_index=lineart_index-index_offset. */ + uint32_t index_offset; + struct Object *object_ref; struct Object *silhouette_backdrop; } LineartEdgeChain; @@ -864,6 +869,7 @@ void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld); int MOD_lineart_chain_count(const LineartEdgeChain *ec); void MOD_lineart_chain_clear_picked_flag(LineartCache *lc); +void MOD_lineart_finalize_chains(LineartData *ld); /** * This is the entry point of all line art calculations. diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 7c8e0c5a6f5..f32141a31eb 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -1051,6 +1051,38 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) } } +LineartElementLinkNode *lineart_find_matching_eln_obj(ListBase *elns, struct Object *obj) +{ + LISTBASE_FOREACH (LineartElementLinkNode *, eln, elns) { + if (eln->object_ref == obj) { + return eln; + } + } + return NULL; +} + +void MOD_lineart_finalize_chains(LineartData *ld) +{ + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { + if (ELEM(ec->type, + LRT_EDGE_FLAG_INTERSECTION, + LRT_EDGE_FLAG_PROJECTED_SHADOW, + LRT_EDGE_FLAG_LIGHT_CONTOUR)) { + continue; + } + LineartElementLinkNode *eln = lineart_find_matching_eln_obj(&ld->geom.vertex_buffer_pointers, + ec->object_ref); + BLI_assert(eln != NULL); + if (LIKELY(eln)) { + LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { + if (eci->index > eln->global_index_offset) { + eci->index -= eln->global_index_offset; + } + } + } + } +} + void MOD_lineart_smooth_chains(LineartData *ld, float tolerance) { LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 2bc59d318c7..d0b1efa183d 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -2651,6 +2651,7 @@ void lineart_main_load_geometries(Depsgraph *depsgraph, } LineartVert *v = (LineartVert *)obi->v_eln->pointer; int v_count = obi->v_eln->element_count; + obi->v_eln->global_index_offset = global_i; for (int vi = 0; vi < v_count; vi++) { v[vi].index += global_i; } @@ -5106,6 +5107,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, /* At last, we need to clear flags so we don't confuse GPencil generation calls. */ MOD_lineart_chain_clear_picked_flag(lc); + + MOD_lineart_finalize_chains(ld); } lineart_mem_destroy(&lc->shadow_data_pool); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h index 3668f1dc6d7..947586aaec4 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h @@ -133,6 +133,7 @@ void lineart_main_transform_and_add_shadow(struct LineartData *ld, struct LineartElementLinkNode *eeln); LineartElementLinkNode *lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex); +LineartElementLinkNode *lineart_find_matching_eln_obj(struct ListBase *elns, struct Object *ob); LineartEdge *lineart_find_matching_edge(struct LineartElementLinkNode *shadow_eln, uint64_t edge_identifier); void lineart_register_shadow_cuts(struct LineartData *ld, -- cgit v1.2.3 From fec90a5d589e334ad4c11f3756dcd8ffd1f94666 Mon Sep 17 00:00:00 2001 From: YimingWu Date: Wed, 31 Aug 2022 10:00:35 +0800 Subject: GPencil: Fix sharp_threshold property in sample stroke operator The property registration was missing in the operator, now fixed. --- source/blender/editors/gpencil/gpencil_edit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index c05ab8c6b28..e6ab6d061ea 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4483,6 +4483,7 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) /* properties */ prop = RNA_def_float(ot->srna, "length", 0.1f, 0.0f, 100.0f, "Length", "", 0.0f, 100.0f); + prop = RNA_def_float(ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI); /* avoid re-using last var */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -- cgit v1.2.3 From 657b92c888f925a6721e30f1d43cb170b7908c12 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 12:42:41 +1000 Subject: BLF: use existing stat from 'direntry' for directory check --- source/blender/blenfont/intern/blf_font_default.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index ffeee397c20..9ab5caf3d33 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -16,6 +16,10 @@ #include "BKE_appdir.h" +#ifdef WIN32 +# include "BLI_winstuff.h" +#endif + static int blf_load_font_default(const char *filename, const bool unique) { const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR); @@ -65,7 +69,7 @@ void BLF_load_font_stack() struct direntry *dir; uint num_files = BLI_filelist_dir_contents(path, &dir); for (int f = 0; f < num_files; f++) { - if (!BLI_is_dir(dir[f].path) && + if (!S_ISDIR(dir[f].s.st_mode) && BLI_path_extension_check_n( dir[f].path, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", NULL)) { if (!BLF_is_loaded(dir[f].path)) { -- cgit v1.2.3 From cae50c83c687dcb1f7ceb334dfb82f9a22097ffa Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 12:48:00 +1000 Subject: Cleanup: split font datafile loading into a function Also use more descriptive/conventional variable names. --- source/blender/blenfont/intern/blf_font_default.c | 61 ++++++++++++++--------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index 9ab5caf3d33..d35692f6eae 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -51,38 +51,51 @@ int BLF_load_mono_default(const bool unique) return font_id; } -void BLF_load_font_stack() +static void blf_load_datafiles_dir(void) { - /* Load these if not already, might have been replaced by user custom. */ - BLF_load_default(false); - BLF_load_mono_default(false); - const char *datafiles_fonts_dir = BLF_DATAFILES_FONTS_DIR SEP_STR; const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, datafiles_fonts_dir); if (UNLIKELY(!path)) { fprintf(stderr, "Font data directory \"%s\" could not be detected!\n", datafiles_fonts_dir); + return; } - else if (UNLIKELY(!BLI_exists(path))) { + if (UNLIKELY(!BLI_exists(path))) { fprintf(stderr, "Font data directory \"%s\" does not exist!\n", path); + return; } - else { - struct direntry *dir; - uint num_files = BLI_filelist_dir_contents(path, &dir); - for (int f = 0; f < num_files; f++) { - if (!S_ISDIR(dir[f].s.st_mode) && - BLI_path_extension_check_n( - dir[f].path, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", NULL)) { - if (!BLF_is_loaded(dir[f].path)) { - int font_id = BLF_load(dir[f].path); - if (font_id == -1) { - fprintf(stderr, "Unable to load font: %s\n", dir[f].path); - } - else { - BLF_enable(font_id, BLF_DEFAULT); - } - } - } + + struct direntry *file_list; + uint file_list_num = BLI_filelist_dir_contents(path, &file_list); + for (int i = 0; i < file_list_num; i++) { + if (S_ISDIR(file_list[i].s.st_mode)) { + continue; + } + + const char *filepath = file_list[i].path; + if (!BLI_path_extension_check_n( + filepath, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", NULL)) { + continue; } - BLI_filelist_free(dir, num_files); + if (BLF_is_loaded(filepath)) { + continue; + } + + /* Attempt to load the font. */ + int font_id = BLF_load(filepath); + if (font_id == -1) { + fprintf(stderr, "Unable to load font: %s\n", filepath); + continue; + } + + BLF_enable(font_id, BLF_DEFAULT); } + BLI_filelist_free(file_list, file_list_num); +} + +void BLF_load_font_stack() +{ + /* Load these if not already, might have been replaced by user custom. */ + BLF_load_default(false); + BLF_load_mono_default(false); + blf_load_datafiles_dir(); } -- cgit v1.2.3 From 68d85ce2082aabd5ffade162a8ce495d8778232c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 13:52:44 +1000 Subject: Cleanup: format --- source/blender/editors/gpencil/gpencil_edit.c | 3 ++- .../editors/space_outliner/outliner_collections.cc | 24 ++++++++++++++++------ source/blender/gpu/intern/gpu_codegen.cc | 3 ++- source/blender/makesrna/intern/rna_nodetree.c | 3 +-- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index dc9a207e01e..280512a2dd3 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4770,7 +4770,8 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) /* properties */ prop = RNA_def_float(ot->srna, "length", 0.1f, 0.0f, 100.0f, "Length", "", 0.0f, 100.0f); - prop = RNA_def_float(ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI); + prop = RNA_def_float( + ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI); /* avoid re-using last var */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc index 23ee8a2c3f2..a76a9bddea5 100644 --- a/source/blender/editors/space_outliner/outliner_collections.cc +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -345,8 +345,12 @@ void outliner_collection_delete( /* We first walk over and find the Collections we actually want to delete * (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Effectively delete the collections. */ GSetIterator collections_to_edit_iter; @@ -707,8 +711,12 @@ static int collection_link_exec(bContext *C, wmOperator *op) data.collections_to_edit = BLI_gset_ptr_new(__func__); /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Effectively link the collections. */ GSetIterator collections_to_edit_iter; @@ -766,8 +774,12 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) /* We first walk over and find the Collections we actually want to instance * (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Find an active collection to add to, that doesn't give dependency cycles. */ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 7b228c32c5c..b6194c0816f 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -199,7 +199,8 @@ static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output) } /* Trick type to change overload and keep a somewhat nice syntax. */ -struct GPUConstant : public GPUInput {}; +struct GPUConstant : public GPUInput { +}; /* Print data constructor (i.e: vec2(1.0f, 1.0f)). */ static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 60a57bae78a..6596acfaf57 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -11015,8 +11015,7 @@ static void rna_def_node_socket(BlenderRNA *brna) prop = RNA_def_property(srna, "is_unavailable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_UNAVAIL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, "Unavailable", "True if the socket is unavailable"); + RNA_def_property_ui_text(prop, "Unavailable", "True if the socket is unavailable"); prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT); -- cgit v1.2.3 From 876d1bfe4ecbf6065bf86716a456ea8d6fa0c084 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:46 +1000 Subject: Cleanup: quiet MSVC warning using flag flag operations on boolean While harmless it wasn't clear if other bits might be set but ignored, assign the value instead. --- source/blender/render/intern/pipeline.cc | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 8cc1293eae3..746adeaddb2 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -1948,15 +1948,17 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format); - ok &= mh->append_movie(movie_ctx_arr[view_id], - rd, - preview ? scene->r.psfra : scene->r.sfra, - scene->r.cfra, - (int *)ibuf->rect, - ibuf->x, - ibuf->y, - suffix, - reports); + if (!mh->append_movie(movie_ctx_arr[view_id], + rd, + preview ? scene->r.psfra : scene->r.sfra, + scene->r.cfra, + (int *)ibuf->rect, + ibuf->x, + ibuf->y, + suffix, + reports)) { + ok = false; + } /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); @@ -1979,7 +1981,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]); - ok = mh->append_movie(movie_ctx_arr[0], + if (!mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, @@ -1987,7 +1989,9 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, ibuf_arr[2]->x, ibuf_arr[2]->y, "", - reports); + reports)) { + ok = false; + } for (i = 0; i < 3; i++) { /* imbuf knows which rects are not part of ibuf */ -- cgit v1.2.3 From 0f8ebd21e3a0b32e1d982382acad4422a07ac707 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:47 +1000 Subject: Cleanup: reduce scope, quiet unused variable warnings When building without thumbnails some variables weren't used, reduce their scope as well as the BlPath sub-string. --- source/blender/blenlib/intern/winstuff.c | 33 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index e90a0ee02db..7e2c5e8f1dd 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -63,23 +63,17 @@ bool BLI_windows_register_blend_extension(const bool background) char buffer[256]; char BlPath[MAX_PATH]; - char InstallDir[FILE_MAXDIR]; - char SysDir[FILE_MAXDIR]; - const char *ThumbHandlerDLL; - char RegCmd[MAX_PATH * 2]; char MBox[256]; - char *blender_app; -# ifndef _WIN64 - BOOL IsWOW64; -# endif printf("Registering file extension..."); GetModuleFileName(0, BlPath, MAX_PATH); /* Replace the actual app name with the wrapper. */ - blender_app = strstr(BlPath, "blender.exe"); - if (blender_app != NULL) { - strcpy(blender_app, "blender-launcher.exe"); + { + char *blender_app = strstr(BlPath, "blender.exe"); + if (blender_app != NULL) { + strcpy(blender_app, "blender-launcher.exe"); + } } /* root is HKLM by default */ @@ -157,12 +151,17 @@ bool BLI_windows_register_blend_extension(const bool background) } # ifdef WITH_BLENDER_THUMBNAILER - BLI_windows_get_executable_dir(InstallDir); - GetSystemDirectory(SysDir, FILE_MAXDIR); - ThumbHandlerDLL = "BlendThumb.dll"; - snprintf( - RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL); - system(RegCmd); + { + char RegCmd[MAX_PATH * 2]; + char InstallDir[FILE_MAXDIR]; + char SysDir[FILE_MAXDIR]; + BLI_windows_get_executable_dir(InstallDir); + GetSystemDirectory(SysDir, FILE_MAXDIR); + const char *ThumbHandlerDLL = "BlendThumb.dll"; + snprintf( + RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL); + system(RegCmd); + } # endif RegCloseKey(root); -- cgit v1.2.3 From c4a16389bc1881d26738b5576024e3f0f1b33d5c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:49 +1000 Subject: Cleanup: use bool for GHOST_SystemWin32::setConsoleWindowState return --- intern/ghost/GHOST_ISystem.h | 4 ++-- intern/ghost/intern/GHOST_C-api.cpp | 3 +-- intern/ghost/intern/GHOST_SystemCocoa.h | 4 ++-- intern/ghost/intern/GHOST_SystemHeadless.h | 2 +- intern/ghost/intern/GHOST_SystemSDL.h | 4 ++-- intern/ghost/intern/GHOST_SystemWayland.cpp | 4 ++-- intern/ghost/intern/GHOST_SystemWayland.h | 2 +- intern/ghost/intern/GHOST_SystemWin32.cpp | 10 +++++----- intern/ghost/intern/GHOST_SystemWin32.h | 4 ++-- intern/ghost/intern/GHOST_SystemX11.h | 2 +- 10 files changed, 19 insertions(+), 20 deletions(-) diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 0dd855bb513..aa893a66a9d 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -437,9 +437,9 @@ class GHOST_ISystem { /** * Set the Console State * \param action: console state - * \return current status (1 -visible, 0 - hidden) + * \return current status (true: visible, 0: hidden) */ - virtual int setConsoleWindowState(GHOST_TConsoleWindowState action) = 0; + virtual bool setConsoleWindowState(GHOST_TConsoleWindowState action) = 0; /*************************************************************************************** * Access to clipboard. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 62e1e470010..710512881e8 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -869,8 +869,7 @@ void GHOST_putClipboard(const char *buffer, bool selection) bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action) { GHOST_ISystem *system = GHOST_ISystem::getSystem(); - /* FIXME: use `bool` instead of int for this value. */ - return (bool)system->setConsoleWindowState(action); + return system->setConsoleWindowState(action); } bool GHOST_UseNativePixels(void) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 8b6dfb4efed..a9e659d3565 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -236,9 +236,9 @@ class GHOST_SystemCocoa : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState action) + bool setConsoleWindowState(GHOST_TConsoleWindowState action) { - return 0; + return false; } /** diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h index dcf445420a4..b02a82fc9eb 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.h +++ b/intern/ghost/intern/GHOST_SystemHeadless.h @@ -30,7 +30,7 @@ class GHOST_SystemHeadless : public GHOST_System { { return false; } - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override { return 0; } diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index aefea5eda34..bee277ba674 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -33,9 +33,9 @@ class GHOST_SystemSDL : public GHOST_System { bool processEvents(bool waitForEvent); - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 13357a3d31a..c2859edc56b 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -3035,9 +3035,9 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent) return any_processed; } -int GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) +bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 632f4bf28d8..f3b42de5a1b 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -97,7 +97,7 @@ class GHOST_SystemWayland : public GHOST_System { bool processEvents(bool waitForEvent) override; - int setConsoleWindowState(GHOST_TConsoleWindowState action) override; + bool setConsoleWindowState(GHOST_TConsoleWindowState action) override; GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 5ea369c50bf..afc18704c9b 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -131,7 +131,7 @@ GHOST_SystemWin32::GHOST_SystemWin32() GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); m_displayManager->initialize(); - m_consoleStatus = 1; + m_consoleStatus = true; /* Tell Windows we are per monitor DPI aware. This disables the default * blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. */ @@ -2320,7 +2320,7 @@ static bool isStartedFromCommandPrompt() return false; } -int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) +bool GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) { HWND wnd = GetConsoleWindow(); @@ -2328,13 +2328,13 @@ int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) case GHOST_kConsoleWindowStateHideForNonConsoleLaunch: { if (!isStartedFromCommandPrompt()) { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; } break; } case GHOST_kConsoleWindowStateHide: { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; break; } case GHOST_kConsoleWindowStateShow: { @@ -2342,7 +2342,7 @@ int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) if (!isStartedFromCommandPrompt()) { DeleteMenu(GetSystemMenu(wnd, FALSE), SC_CLOSE, MF_BYCOMMAND); } - m_consoleStatus = 1; + m_consoleStatus = true; break; } case GHOST_kConsoleWindowStateToggle: { diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 93b56a128c0..81c565ae732 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -430,7 +430,7 @@ class GHOST_SystemWin32 : public GHOST_System { * \param action: console state * \return current status (1 -visible, 0 - hidden) */ - int setConsoleWindowState(GHOST_TConsoleWindowState action); + bool setConsoleWindowState(GHOST_TConsoleWindowState action); /** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */ unsigned short m_keycode_last_repeat_key; @@ -450,7 +450,7 @@ class GHOST_SystemWin32 : public GHOST_System { HKL m_keylayout; /** Console status. */ - int m_consoleStatus; + bool m_consoleStatus; /** Wheel delta accumulator. */ int m_wheelDeltaAccum; diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 7938aa2b646..bd6ace101e9 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -253,7 +253,7 @@ class GHOST_SystemX11 : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { return 0; } -- cgit v1.2.3 From 8bfb65e2547f5fda1b3c9cee4d9ae88c73cf12a1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:51 +1000 Subject: Cleanup: remove 'else' after return --- intern/ghost/intern/GHOST_SystemWin32.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index afc18704c9b..d011f413345 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -2123,8 +2123,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, char *GHOST_SystemWin32::getClipboard(bool selection) const { - char *temp_buff; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { wchar_t *buffer; HANDLE hData = GetClipboardData(CF_UNICODETEXT); @@ -2138,7 +2136,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return NULL; } - temp_buff = alloc_utf_8_from_16(buffer, 0); + char *temp_buff = alloc_utf_8_from_16(buffer, 0); /* Buffer mustn't be accessed after CloseClipboard * it would like accessing free-d memory */ @@ -2147,7 +2145,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { + if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { char *buffer; size_t len = 0; HANDLE hData = GetClipboardData(CF_TEXT); @@ -2162,7 +2160,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const } len = strlen(buffer); - temp_buff = (char *)malloc(len + 1); + char *temp_buff = (char *)malloc(len + 1); strncpy(temp_buff, buffer, len); temp_buff[len] = '\0'; @@ -2173,9 +2171,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else { - return NULL; - } + return nullptr; } void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const -- cgit v1.2.3 From e9d4a20a59a82125f5b84e17b0e9a9a73059152e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:53 +1000 Subject: Cleanup: tablet press could fall through to release on GHOST/Win32 Introduced in [0], checking the logic here, there seems to be no reason a press event should ever run release logic, relocate break statement. In practice this was unlikely to cause problems as peeking into press events would need to fail, peeking into release would need to succeed. Even so, better avoid accidental fall through in switch statements. [0]: 6f158f834dcfa638639391f37afcb2ca8457cb45 --- intern/ghost/intern/GHOST_SystemWin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index d011f413345..8b196ca3118 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -900,11 +900,11 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); mouseMoveHandled = true; - break; } else { WINTAB_PRINTF(" ... but no system button\n"); } + break; } case GHOST_kEventButtonUp: { WINTAB_PRINTF("HWND %p Wintab button up", window->getHWND()); -- cgit v1.2.3 From 065a1cd0b1b12aa371d52de5e5c7b0f634533ff8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:54 +1000 Subject: Cleanup: check GetKeyboardState succeeds before using it's values Quiets compiler warning. --- intern/ghost/intern/GHOST_SystemWin32.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 8b196ca3118..c03d468160a 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -1156,10 +1156,10 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA * those events here as well. */ if (!is_repeated_modifier) { char utf8_char[6] = {0}; - BYTE state[256] = {0}; - GetKeyboardState((PBYTE)state); - bool ctrl_pressed = state[VK_CONTROL] & 0x80; - bool alt_pressed = state[VK_MENU] & 0x80; + BYTE state[256]; + const BOOL has_state = GetKeyboardState((PBYTE)state); + const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80; + const bool alt_pressed = has_state && state[VK_MENU] & 0x80; if (!key_down) { /* Pass. */ -- cgit v1.2.3 From 4df3cf020bd0038f5533382989a05f4e4f76a111 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:56 +1000 Subject: Fix uninitialized variable use for ID3D11RenderTargetView When 'm_render_target' was NULL, backbuffer_res would be used without being assigned. While it seems likely this code-path is rarely used (if at all), resolve the logical error. --- intern/ghost/intern/GHOST_ContextD3D.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp index 4fc05cf912c..857323941ea 100644 --- a/intern/ghost/intern/GHOST_ContextD3D.cpp +++ b/intern/ghost/intern/GHOST_ContextD3D.cpp @@ -123,8 +123,6 @@ class GHOST_SharedOpenGLResource { ID3D11RenderTargetView *render_target = nullptr) : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height) { - ID3D11Resource *backbuffer_res; - if (!render_target) { D3D11_TEXTURE2D_DESC texDesc{}; D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{}; @@ -157,11 +155,12 @@ class GHOST_SharedOpenGLResource { m_render_target = render_target; if (m_render_target) { + ID3D11Resource *backbuffer_res = nullptr; m_render_target->GetResource(&backbuffer_res); - } - if (backbuffer_res) { - backbuffer_res->QueryInterface(&m_render_target_tex); - backbuffer_res->Release(); + if (backbuffer_res) { + backbuffer_res->QueryInterface(&m_render_target_tex); + backbuffer_res->Release(); + } } if (!m_render_target || !m_render_target_tex) { -- cgit v1.2.3 From ff651a08b50cade1adf6e4d7a810500c88eb1987 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 14:26:58 +1000 Subject: Fix returning a freed context when initialization fails for GHOST/Win32 --- intern/ghost/intern/GHOST_SystemWin32.cpp | 1 + intern/ghost/intern/GHOST_WindowWin32.cpp | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index c03d468160a..b583d39dd1f 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -353,6 +353,7 @@ GHOST_ContextD3D *GHOST_SystemWin32::createOffscreenContextD3D() context = new GHOST_ContextD3D(false, wnd); if (context->initializeDrawingContext() == GHOST_kFailure) { delete context; + context = nullptr; } return context; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 4d8e0d492d9..50ee9385e39 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -624,11 +624,9 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty GHOST_Context *context; context = new GHOST_ContextD3D(false, m_hWnd); - if (context->initializeDrawingContext()) { - return context; - } - else { + if (!context->initializeDrawingContext()) { delete context; + context = nullptr; } return context; -- cgit v1.2.3 From 70035e64732415aee039196e81ab31554e5577b1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 15:58:33 +1000 Subject: Cleanup: break before the default case in switch statements While missing the break before a default that only breaks isn't an error, it means adding new cases needs to remember to add the break for an existing case, changing the default case will also result in an unintended fall-through. Also avoid `default:;` and add an explicit break. --- source/blender/blenkernel/intern/attribute.cc | 1 + source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc | 2 ++ source/blender/editors/interface/interface.cc | 3 ++- source/blender/editors/interface/interface_template_search_menu.cc | 1 + source/blender/editors/object/object_vgroup.cc | 6 ++++-- source/blender/modifiers/intern/MOD_nodes.cc | 1 + source/blender/windowmanager/intern/wm_event_system.cc | 1 + 7 files changed, 12 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 394f9e738d4..0f7fabcff9b 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -421,6 +421,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) if (mesh->edit_mesh != nullptr) { return 0; } + break; } default: break; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 96ab9388023..9ccd7ed447b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -62,6 +62,7 @@ void RuntimeBackup::init_from_id(ID *id) break; case ID_GD: gpencil_backup.init_from_gpencil(reinterpret_cast(id)); + break; default: break; } @@ -104,6 +105,7 @@ void RuntimeBackup::restore_to_id(ID *id) break; case ID_GD: gpencil_backup.restore_to_gpencil(reinterpret_cast(id)); + break; default: break; } diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index c076845af3c..933724c9294 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -6754,10 +6754,11 @@ void UI_but_extra_icon_string_info_get(struct bContext *C, uiButExtraOpIcon *ext if (ui_but_extra_icon_event_operator_string(C, extra_icon, buf, sizeof(buf))) { tmp = BLI_strdup(buf); } + break; } + default: /* Other types not supported. The caller should expect that outcome, no need to message or * assert here. */ - default: break; } diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc index c3021028b97..c777b7834f2 100644 --- a/source/blender/editors/interface/interface_template_search_menu.cc +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -918,6 +918,7 @@ static void menu_search_arg_free_fn(void *data_v) WM_operator_properties_free(item->op.opptr); MEM_freeN(item->op.opptr); } + break; } case MenuSearch_Item::Type::RNA: { break; diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index 0e0f5bd94cc..7a61adfb95c 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -1773,7 +1773,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask) continue; } break; - default:; + default: + break; } if (dg->flag & DG_LOCK_WEIGHT) { @@ -1795,7 +1796,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask) continue; } break; - default:; + default: + break; } switch (action) { diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c571a4821b4..56967e62d8a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -297,6 +297,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte case ID_IM: case ID_TE: { DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier"); + break; } default: { /* Purposefully don't add relations for materials. While there are material sockets, diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 2bba0ac802d..3054708fbdb 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -1591,6 +1591,7 @@ static int wm_operator_call_internal(bContext *C, case WM_OP_EXEC_AREA: case WM_OP_EXEC_SCREEN: event = nullptr; + break; default: break; } -- cgit v1.2.3 From a0ff2be19991acdec5885b02fca0d937055d9d6c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 16:12:24 +1000 Subject: Cleanup: remove pointless strcpy return value check --- intern/ghost/intern/GHOST_DropTargetWin32.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 2283cff3827..5ca48ee9cd5 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -288,11 +288,8 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) return NULL; } - if (!::strcpy(tmp_string, str)) { - ::free(tmp_string); - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } + ::strcpy(tmp_string, str); + /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); -- cgit v1.2.3 From 60576fba117c7b059f7172644e35139af587dbee Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 31 Aug 2022 16:28:32 +1000 Subject: Fix resource leak dropping files in GHOST/Win32 Early returns in error cases missed calling ReleaseStgMedium for getDropDataAsFilenames, getDropDataAsString & getDropDataAsString. --- intern/ghost/intern/GHOST_DropTargetWin32.cpp | 59 ++++++++++++--------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 5ca48ee9cd5..03d55c848e3 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -219,35 +219,30 @@ void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject) hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0); - if (!totfiles) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - - strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); - strArray->count = 0; - strArray->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); - - for (UINT nfile = 0; nfile < totfiles; nfile++) { - if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { - if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { - continue; + if (totfiles) { + strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); + strArray->count = 0; + strArray->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); + + for (UINT nfile = 0; nfile < totfiles; nfile++) { + if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { + if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { + continue; + } + /* Just ignore paths that could not be converted verbatim. */ + + strArray->strings[nvalid] = (uint8_t *)temp_path; + strArray->count = nvalid + 1; + nvalid++; } - /* Just ignore paths that could not be converted verbatim. */ - - strArray->strings[nvalid] = (uint8_t *)temp_path; - strArray->count = nvalid + 1; - nvalid++; } } /* Free up memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); - - return strArray; } } - return NULL; + return strArray; } void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) @@ -261,16 +256,18 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) if (pDataObject->QueryGetData(&fmtetc) == S_OK) { if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal); - if (!(tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0))) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } + + tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0); + /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); + #ifdef WITH_GHOST_DEBUG - ::printf("\n\n%s\n\n", - tmp_string); + if (tmp_string) { + ::printf("\n\n%s\n\n", + tmp_string); + } #endif /* WITH_GHOST_DEBUG */ return tmp_string; } @@ -283,13 +280,9 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) char *str = (char *)::GlobalLock(stgmed.hGlobal); tmp_string = (char *)::malloc(::strlen(str) + 1); - if (!tmp_string) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; + if (tmp_string) { + ::strcpy(tmp_string, str); } - - ::strcpy(tmp_string, str); - /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); -- cgit v1.2.3 From e2deee73abf3fe5885aefa131c337f3b0d6762d6 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 31 Aug 2022 09:42:17 +0200 Subject: Update freedesktop file. Add new features for upcoming Blender 3.3 and also missing 3.2 notes, which were not merged to master. --- .../freedesktop/org.blender.Blender.appdata.xml | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/release/freedesktop/org.blender.Blender.appdata.xml b/release/freedesktop/org.blender.Blender.appdata.xml index 12291860050..0f1aa5099b6 100644 --- a/release/freedesktop/org.blender.Blender.appdata.xml +++ b/release/freedesktop/org.blender.Blender.appdata.xml @@ -40,6 +40,47 @@ + + +

New features:

+
    +
  • New hair system
  • +
  • Cycles Rendering on Intel Arc GPUs
  • +
  • Grease Pencil Light and Shadow calculations
  • +
  • Motion Tracker Image Plane Marker
  • +
+

Enhancements:

+
    +
  • Faster Line Art loading time
  • +
  • Library Overrides improvements
  • +
  • Massive performance gains importing large amounts of objects in USD, Alembic, and OBJ
  • +
  • UV improvements
  • +
  • Improved sculpting performance in EEVEE
  • +
  • Cycles GPU rendering improvements for AMD GPUs and Apple Silicon
  • +
+
+
+ + +

New features:

+
    +
  • Cycles Light Groups
  • +
  • Cycles Shadow Caustics using Manifold Next Event Estimation
  • +
  • New Tools and usability improvements for Polygon Painting
  • +
  • More Geometry Nodes, including Duplicate Elements
  • +
  • Asset Browser: Support for Asset Collections
  • +
+

Enhancements:

+
    +
  • Enhanced channels in the video sequencer
  • +
  • Support for WebP format
  • +
  • New experimental OBJ importer
  • +
  • Motion Paths improvements
  • +
  • Grease Pencil Envelope Modifier
  • +
  • New Curve Pen Tool
  • +
+
+

New features:

-- cgit v1.2.3 From 68f234b8ab2ef4f69498650ece54015d174bea07 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Mon, 29 Aug 2022 21:10:16 +0300 Subject: Cleanup: obj: simplify import/export syntax handling code I want to add support for PBR materials extension to OBJ, but the way current I/O code syntax handling was done made it quite cumbersome to extend the number of MTL textures/parameters. Simplify all that by removing FormatHandler template on "syntax" that gets routed through keyword enums, and instead just have simple `write_obj_*` and `write_mtl_*` functions. Simplify MTLMaterial to not contain a map of textures (that is always fully filled with all possible textures), instead now there's a simple array. Rename `tex_map_XX` to `MTLTexMap`. All this does not affect behavior or performance, but it does result in 170 fewer lines of code, and saves a couple kilobytes of executable size. --- .../exporter/obj_export_file_writer.cc | 249 ++++++------- .../exporter/obj_export_file_writer.hh | 29 +- .../io/wavefront_obj/exporter/obj_export_io.hh | 404 +++++++-------------- .../io/wavefront_obj/exporter/obj_export_mtl.cc | 33 +- .../io/wavefront_obj/exporter/obj_export_mtl.hh | 46 +-- .../io/wavefront_obj/exporter/obj_exporter.cc | 4 +- .../importer/obj_import_file_reader.cc | 37 +- .../io/wavefront_obj/importer/obj_import_mtl.cc | 44 +-- .../io/wavefront_obj/importer/obj_import_mtl.hh | 5 +- .../io/wavefront_obj/tests/obj_exporter_tests.cc | 22 +- .../io/wavefront_obj/tests/obj_mtl_parser_tests.cc | 40 +- 11 files changed, 371 insertions(+), 542 deletions(-) diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 66dd71d4246..9bcc061caf7 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -44,7 +44,7 @@ static const char *DEFORM_GROUP_DISABLED = "off"; * So an empty material name is written. */ static const char *MATERIAL_GROUP_DISABLED = ""; -void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh, +void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span uv_indices, @@ -57,12 +57,12 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh, const int uv_offset = offsets.uv_vertex_offset + 1; const int normal_offset = offsets.normal_offset + 1; const int n = vert_indices.size(); - fh.write(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset, + uv_indices[j] + uv_offset, + normal_indices[j] + normal_offset); } } else { @@ -71,15 +71,15 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh, * then go backwards. Same logic in other write_*_indices functions below. */ for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset, + uv_indices[j] + uv_offset, + normal_indices[j] + normal_offset); } } - fh.write(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_normal_indices(FormatHandler &fh, +void OBJWriter::write_vert_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span /*uv_indices*/, @@ -90,24 +90,24 @@ void OBJWriter::write_vert_normal_indices(FormatHandler &fh, const int vertex_offset = offsets.vertex_offset + 1; const int normal_offset = offsets.normal_offset + 1; const int n = vert_indices.size(); - fh.write(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write(vert_indices[j] + vertex_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset, + normal_indices[j] + normal_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write(vert_indices[j] + vertex_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset, + normal_indices[j] + normal_offset); } } - fh.write(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_uv_indices(FormatHandler &fh, +void OBJWriter::write_vert_uv_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span uv_indices, @@ -118,24 +118,22 @@ void OBJWriter::write_vert_uv_indices(FormatHandler &fh, const int vertex_offset = offsets.vertex_offset + 1; const int uv_offset = offsets.uv_vertex_offset + 1; const int n = vert_indices.size(); - fh.write(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset); + fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset); + fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset); } } - fh.write(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_indices(FormatHandler &fh, +void OBJWriter::write_vert_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span /*uv_indices*/, @@ -144,27 +142,27 @@ void OBJWriter::write_vert_indices(FormatHandler &fh, { const int vertex_offset = offsets.vertex_offset + 1; const int n = vert_indices.size(); - fh.write(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write(vert_indices[j] + vertex_offset); + fh.write_obj_poly_v(vert_indices[j] + vertex_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write(vert_indices[j] + vertex_offset); + fh.write_obj_poly_v(vert_indices[j] + vertex_offset); } } - fh.write(); + fh.write_obj_poly_end(); } void OBJWriter::write_header() const { using namespace std::string_literals; - FormatHandler fh; - fh.write("# Blender "s + BKE_blender_version_string() + "\n"); - fh.write("# www.blender.org\n"); + FormatHandler fh; + fh.write_string("# Blender "s + BKE_blender_version_string()); + fh.write_string("# www.blender.org"); fh.write_to_file(outfile_); } @@ -174,8 +172,8 @@ void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const char mtl_file_name[FILE_MAXFILE]; char mtl_dir_name[FILE_MAXDIR]; BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE); - FormatHandler fh; - fh.write(mtl_file_name); + FormatHandler fh; + fh.write_obj_mtllib(mtl_file_name); fh.write_to_file(outfile_); } @@ -184,18 +182,17 @@ static void spaces_to_underscores(std::string &r_name) std::replace(r_name.begin(), r_name.end(), ' ', '_'); } -void OBJWriter::write_object_name(FormatHandler &fh, - const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const { std::string object_name = obj_mesh_data.get_object_name(); spaces_to_underscores(object_name); if (export_params_.export_object_groups) { std::string mesh_name = obj_mesh_data.get_object_mesh_name(); spaces_to_underscores(mesh_name); - fh.write(object_name + "_" + mesh_name); + fh.write_obj_group(object_name + "_" + mesh_name); return; } - fh.write(object_name); + fh.write_obj_object(object_name); } /* Split up large meshes into multi-threaded jobs; each job processes @@ -213,9 +210,7 @@ static int calc_chunk_count(int count) * will be written into the final /fh/ buffer at the end. */ template -void obj_parallel_chunked_output(FormatHandler &fh, - int tot_count, - const Function &function) +void obj_parallel_chunked_output(FormatHandler &fh, int tot_count, const Function &function) { if (tot_count <= 0) { return; @@ -231,7 +226,7 @@ void obj_parallel_chunked_output(FormatHandler &fh, return; } /* Give each chunk its own temporary output buffer, and process them in parallel. */ - std::vector> buffers(chunk_count); + std::vector buffers(chunk_count); blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) { for (const int r : range) { int i_start = r * chunk_size; @@ -248,7 +243,7 @@ void obj_parallel_chunked_output(FormatHandler &fh, } } -void OBJWriter::write_vertex_coords(FormatHandler &fh, +void OBJWriter::write_vertex_coords(FormatHandler &fh, const OBJMesh &obj_mesh_data, bool write_colors) const { @@ -265,41 +260,40 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh, colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f}); BLI_assert(tot_count == attribute.size()); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); ColorGeometry4f linear = attribute.get(i); float srgb[3]; linearrgb_to_srgb_v3_v3(srgb, linear); - buf.write( - vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]); + buf.write_obj_vertex_color(vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]); }); } else { - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); - buf.write(vertex[0], vertex[1], vertex[2]); + buf.write_obj_vertex(vertex[0], vertex[1], vertex[2]); }); } } -void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) const +void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) const { const Vector &uv_coords = r_obj_mesh_data.get_uv_coords(); const int tot_count = uv_coords.size(); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { const float2 &uv_vertex = uv_coords[i]; - buf.write(uv_vertex[0], uv_vertex[1]); + buf.write_obj_uv(uv_vertex[0], uv_vertex[1]); }); } -void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data) +void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data) { /* Poly normals should be calculated earlier via store_normal_coords_and_indices. */ const Vector &normal_coords = obj_mesh_data.get_normal_coords(); const int tot_count = normal_coords.size(); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { const float3 &normal = normal_coords[i]; - buf.write(normal[0], normal[1], normal[2]); + buf.write_obj_normal(normal[0], normal[1], normal[2]); }); } @@ -334,7 +328,7 @@ static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams ¶ms, return group; } -void OBJWriter::write_poly_elements(FormatHandler &fh, +void OBJWriter::write_poly_elements(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data, std::function matname_fn) @@ -346,7 +340,7 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, const int tot_deform_groups = obj_mesh_data.tot_deform_groups(); threading::EnumerableThreadSpecific> group_weights; - obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler &buf, int idx) { + obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler &buf, int idx) { /* Polygon order for writing into the file is not necessarily the same * as order in the mesh; it will be sorted by material indices. Remap current * and previous indices here according to the order. */ @@ -362,7 +356,7 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, const int prev_group = get_smooth_group(obj_mesh_data, export_params_, prev_i); const int group = get_smooth_group(obj_mesh_data, export_params_, i); if (group != prev_group) { - buf.write(group); + buf.write_obj_smooth(group); } } @@ -375,9 +369,8 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, prev_i, local_weights); const int16_t group = obj_mesh_data.get_poly_deform_group_index(i, local_weights); if (group != prev_group) { - buf.write( - group == NOT_FOUND ? DEFORM_GROUP_DISABLED : - obj_mesh_data.get_poly_deform_group_name(group)); + buf.write_obj_group(group == NOT_FOUND ? DEFORM_GROUP_DISABLED : + obj_mesh_data.get_poly_deform_group_name(group)); } } @@ -387,7 +380,7 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, const int16_t mat = obj_mesh_data.ith_poly_matnr(i); if (mat != prev_mat) { if (mat == NOT_FOUND) { - buf.write(MATERIAL_GROUP_DISABLED); + buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED); } else { const char *mat_name = matname_fn(mat); @@ -397,9 +390,9 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, if (export_params_.export_material_groups) { std::string object_name = obj_mesh_data.get_object_name(); spaces_to_underscores(object_name); - fh.write(object_name + "_" + mat_name); + fh.write_obj_group(object_name + "_" + mat_name); } - buf.write(mat_name); + buf.write_obj_usemtl(mat_name); } } } @@ -414,7 +407,7 @@ void OBJWriter::write_poly_elements(FormatHandler &fh, }); } -void OBJWriter::write_edges_indices(FormatHandler &fh, +void OBJWriter::write_edges_indices(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data) const { @@ -426,13 +419,12 @@ void OBJWriter::write_edges_indices(FormatHandler &fh, if (!vertex_indices) { continue; } - fh.write((*vertex_indices)[0] + offsets.vertex_offset + 1, - (*vertex_indices)[1] + offsets.vertex_offset + 1); + fh.write_obj_edge((*vertex_indices)[0] + offsets.vertex_offset + 1, + (*vertex_indices)[1] + offsets.vertex_offset + 1); } } -void OBJWriter::write_nurbs_curve(FormatHandler &fh, - const OBJCurve &obj_nurbs_data) const +void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_data) const { const int total_splines = obj_nurbs_data.total_splines(); for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) { @@ -440,15 +432,14 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( spline_idx, vertex_idx, export_params_.scaling_factor); - fh.write( - vertex_coords[0], vertex_coords[1], vertex_coords[2]); + fh.write_obj_vertex(vertex_coords[0], vertex_coords[1], vertex_coords[2]); } const char *nurbs_name = obj_nurbs_data.get_curve_name(); const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx); - fh.write(nurbs_name); - fh.write(); - fh.write(nurbs_degree); + fh.write_obj_group(nurbs_name); + fh.write_obj_cstype(); + fh.write_obj_nurbs_degree(nurbs_degree); /** * The numbers written here are indices into the vertex coordinates written * earlier, relative to the line that is going to be written. @@ -457,13 +448,13 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices. */ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx); - fh.write(); + fh.write_obj_curve_begin(); for (int i = 0; i < total_control_points; i++) { /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the * last vertex coordinate, -2 second last. */ - fh.write(-((i % total_vertices) + 1)); + fh.write_obj_poly_v(-((i % total_vertices) + 1)); } - fh.write(); + fh.write_obj_curve_end(); /** * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the @@ -474,7 +465,7 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, const short flagsu = obj_nurbs_data.get_nurbs_flagu(spline_idx); const bool cyclic = flagsu & CU_NURB_CYCLIC; const bool endpoint = !cyclic && (flagsu & CU_NURB_ENDPOINT); - fh.write(); + fh.write_obj_nurbs_parm_begin(); for (int i = 1; i <= total_control_points + 2; i++) { float parm = 1.0f * i / (total_control_points + 2 + 1); if (endpoint) { @@ -485,11 +476,10 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, parm = 1; } } - fh.write(parm); + fh.write_obj_nurbs_parm(parm); } - fh.write(); - - fh.write(); + fh.write_obj_nurbs_parm_end(); + fh.write_obj_nurbs_group_end(); } } @@ -497,6 +487,18 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, /** \name .MTL writers. * \{ */ +static const char *tex_map_type_to_string[] = { + "map_Kd", + "map_Ks", + "map_Ns", + "map_d", + "map_refl", + "map_Ke", + "map_Bump", +}; +BLI_STATIC_ASSERT(ARRAY_SIZE(tex_map_type_to_string) == (int)MTLTexMapType::Count, + "array size mismatch"); + /** * Convert #float3 to string of space-separated numbers, with no leading or trailing space. * Only to be used in NON-performance-critical code. @@ -537,9 +539,9 @@ void MTLWriter::write_header(const char *blen_filepath) const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ? BLI_path_basename(blen_filepath) : "None"; - fmt_handler_.write("# Blender "s + BKE_blender_version_string() + - " MTL File: '" + blen_basename + "'\n"); - fmt_handler_.write("# www.blender.org\n"); + fmt_handler_.write_string("# Blender "s + BKE_blender_version_string() + " MTL File: '" + + blen_basename + "'"); + fmt_handler_.write_string("# www.blender.org"); } StringRefNull MTLWriter::mtl_file_path() const @@ -552,67 +554,52 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl) /* For various material properties, we only capture information * coming from the texture, or the default value of the socket. * When the texture is present, do not emit the default value. */ - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ns).is_valid()) { - fmt_handler_.write(mtl.Ns); + if (!mtl.tex_map_of_type(MTLTexMapType::Ns).is_valid()) { + fmt_handler_.write_mtl_float("Ns", mtl.Ns); } - fmt_handler_.write(mtl.Ka.x, mtl.Ka.y, mtl.Ka.z); - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Kd).is_valid()) { - fmt_handler_.write(mtl.Kd.x, mtl.Kd.y, mtl.Kd.z); + fmt_handler_.write_mtl_float3("Ka", mtl.Ka.x, mtl.Ka.y, mtl.Ka.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Kd).is_valid()) { + fmt_handler_.write_mtl_float3("Kd", mtl.Kd.x, mtl.Kd.y, mtl.Kd.z); } - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ks).is_valid()) { - fmt_handler_.write(mtl.Ks.x, mtl.Ks.y, mtl.Ks.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Ks).is_valid()) { + fmt_handler_.write_mtl_float3("Ks", mtl.Ks.x, mtl.Ks.y, mtl.Ks.z); } - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ke).is_valid()) { - fmt_handler_.write(mtl.Ke.x, mtl.Ke.y, mtl.Ke.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { + fmt_handler_.write_mtl_float3("Ke", mtl.Ke.x, mtl.Ke.y, mtl.Ke.z); } - fmt_handler_.write(mtl.Ni); - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_d).is_valid()) { - fmt_handler_.write(mtl.d); + fmt_handler_.write_mtl_float("Ni", mtl.Ni); + if (!mtl.tex_map_of_type(MTLTexMapType::d).is_valid()) { + fmt_handler_.write_mtl_float("d", mtl.d); } - fmt_handler_.write(mtl.illum); + fmt_handler_.write_mtl_illum(mtl.illum); } -void MTLWriter::write_texture_map( - const MTLMaterial &mtl_material, - const Map::Item &texture_map, - const char *blen_filedir, - const char *dest_dir, - ePathReferenceMode path_mode, - Set> ©_set) +void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, + MTLTexMapType texture_key, + const MTLTexMap &texture_map, + const char *blen_filedir, + const char *dest_dir, + ePathReferenceMode path_mode, + Set> ©_set) { std::string options; /* Option strings should have their own leading spaces. */ - if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) { - options.append(" -o ").append(float3_to_string(texture_map.value.translation)); + if (texture_map.translation != float3{0.0f, 0.0f, 0.0f}) { + options.append(" -o ").append(float3_to_string(texture_map.translation)); } - if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) { - options.append(" -s ").append(float3_to_string(texture_map.value.scale)); + if (texture_map.scale != float3{1.0f, 1.0f, 1.0f}) { + options.append(" -s ").append(float3_to_string(texture_map.scale)); } - if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) { + if (texture_key == MTLTexMapType::bump && mtl_material.map_Bump_strength > 0.0001f) { options.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength)); } std::string path = path_reference( - texture_map.value.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set); + texture_map.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set); /* Always emit forward slashes for cross-platform compatibility. */ std::replace(path.begin(), path.end(), '\\', '/'); -#define SYNTAX_DISPATCH(eMTLSyntaxElement) \ - if (texture_map.key == eMTLSyntaxElement) { \ - fmt_handler_.write(options, path.c_str()); \ - return; \ - } - - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_d); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump); -#undef SYNTAX_DISPATCH - - BLI_assert(!"This map type was not written to the file."); + fmt_handler_.write_mtl_map(tex_map_type_to_string[(int)texture_key], options, path); } void MTLWriter::write_materials(const char *blen_filepath, @@ -633,14 +620,16 @@ void MTLWriter::write_materials(const char *blen_filepath, [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; }); Set> copy_set; for (const MTLMaterial &mtlmat : mtlmaterials_) { - fmt_handler_.write("\n"); - fmt_handler_.write(mtlmat.name); + fmt_handler_.write_string(""); + fmt_handler_.write_mtl_newmtl(mtlmat.name); write_bsdf_properties(mtlmat); - for (const auto &tex : mtlmat.texture_maps.items()) { - if (!tex.value.is_valid()) { + for (int key = 0; key < (int)MTLTexMapType::Count; key++) { + const MTLTexMap &tex = mtlmat.texture_maps[key]; + if (!tex.is_valid()) { continue; } - write_texture_map(mtlmat, tex, blen_filedir, dest_dir, path_mode, copy_set); + write_texture_map( + mtlmat, (MTLTexMapType)key, tex, blen_filedir, dest_dir, path_mode, copy_set); } } path_reference_copy(copy_set); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh index 97c23484426..4544037fbc1 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh @@ -66,7 +66,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write object's name or group. */ - void write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const; + void write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const; /** * Write file name of Material Library in .OBJ file. */ @@ -74,19 +74,19 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b". */ - void write_vertex_coords(FormatHandler &fh, + void write_vertex_coords(FormatHandler &fh, const OBJMesh &obj_mesh_data, bool write_colors) const; /** * Write UV vertex coordinates for all vertices as `vt u v`. * \note UV indices are stored here, but written with polygons later. */ - void write_uv_coords(FormatHandler &fh, OBJMesh &obj_mesh_data) const; + void write_uv_coords(FormatHandler &fh, OBJMesh &obj_mesh_data) const; /** * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z". * \note Normal indices ares stored here, but written with polygons later. */ - void write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data); + void write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data); /** * Write polygon elements with at least vertex indices, and conditionally with UV vertex * indices and polygon normal indices. Also write groups: smooth, vertex, material. @@ -94,23 +94,23 @@ class OBJWriter : NonMovable, NonCopyable { * name used in the .obj file. * \note UV indices were stored while writing UV vertices. */ - void write_poly_elements(FormatHandler &fh, + void write_poly_elements(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data, std::function matname_fn); /** * Write loose edges of a mesh as "l v1 v2". */ - void write_edges_indices(FormatHandler &fh, + void write_edges_indices(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data) const; /** * Write a NURBS curve to the .OBJ file in parameter form. */ - void write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_data) const; + void write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_data) const; private: - using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler &fh, + using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span uv_indices, @@ -124,7 +124,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...". */ - void write_vert_uv_normal_indices(FormatHandler &fh, + void write_vert_uv_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span uv_indices, @@ -133,7 +133,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...". */ - void write_vert_normal_indices(FormatHandler &fh, + void write_vert_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span /*uv_indices*/, @@ -142,7 +142,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...". */ - void write_vert_uv_indices(FormatHandler &fh, + void write_vert_uv_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span uv_indices, @@ -151,7 +151,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1 v2 ...". */ - void write_vert_indices(FormatHandler &fh, + void write_vert_indices(FormatHandler &fh, const IndexOffsets &offsets, Span vert_indices, Span /*uv_indices*/, @@ -164,7 +164,7 @@ class OBJWriter : NonMovable, NonCopyable { */ class MTLWriter : NonMovable, NonCopyable { private: - FormatHandler fmt_handler_; + FormatHandler fmt_handler_; FILE *outfile_; std::string mtl_filepath_; Vector mtlmaterials_; @@ -208,7 +208,8 @@ class MTLWriter : NonMovable, NonCopyable { * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image". */ void write_texture_map(const MTLMaterial &mtl_material, - const Map::Item &texture_map, + MTLTexMapType texture_key, + const MTLTexMap &texture_map, const char *blen_filedir, const char *dest_dir, ePathReferenceMode mode, diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh index 5413c9969e3..cc0f7c0824c 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -23,268 +23,24 @@ namespace blender::io::obj { -enum class eFileType { - OBJ, - MTL, -}; - -enum class eOBJSyntaxElement { - vertex_coords, - vertex_coords_color, - uv_vertex_coords, - normal, - poly_element_begin, - vertex_uv_normal_indices, - vertex_normal_indices, - vertex_uv_indices, - vertex_indices, - poly_element_end, - poly_usemtl, - edge, - cstype, - nurbs_degree, - curve_element_begin, - curve_element_end, - nurbs_parameter_begin, - nurbs_parameters, - nurbs_parameter_end, - nurbs_group_end, - new_line, - mtllib, - smooth_group, - object_group, - object_name, - /* Use rarely. New line is NOT included for string. */ - string, -}; - -enum class eMTLSyntaxElement { - newmtl, - Ni, - d, - Ns, - illum, - Ka, - Kd, - Ks, - Ke, - map_Kd, - map_Ks, - map_Ns, - map_d, - map_refl, - map_Ke, - map_Bump, - /* Use rarely. New line is NOT included for string. */ - string, -}; - -template struct FileTypeTraits; - -/* Used to prevent mixing of say OBJ file format with MTL syntax elements. */ -template<> struct FileTypeTraits { - using SyntaxType = eOBJSyntaxElement; -}; - -template<> struct FileTypeTraits { - using SyntaxType = eMTLSyntaxElement; -}; - -struct FormattingSyntax { - /* Formatting syntax with the file format key like `newmtl %s\n`. */ - const char *fmt = nullptr; - /* Number of arguments needed by the syntax. */ - const int total_args = 0; - /* Whether types of the given arguments are accepted by the syntax above. Fail to compile by - * default. - */ - const bool are_types_valid = false; -}; - -/** - * Type dependent but always false. Use to add a `constexpr` conditional compile-time error. - */ -template struct always_false : std::false_type { -}; - -template -constexpr bool is_type_float = (... && std::is_floating_point_v>); - -template -constexpr bool is_type_integral = (... && std::is_integral_v>); - -template -constexpr bool is_type_string_related = (... && std::is_constructible_v); - -/* GCC (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on, - * results in "obj_export_io.hh:205:18: warning: ‘%s’ directive output truncated writing 34 bytes - * into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered - * as an edge case by tests on purpose. */ -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-truncation" -#endif -template -constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key) -{ - switch (key) { - case eOBJSyntaxElement::vertex_coords: { - return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float}; - } - case eOBJSyntaxElement::vertex_coords_color: { - return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float}; - } - case eOBJSyntaxElement::uv_vertex_coords: { - return {"vt {:.6f} {:.6f}\n", 2, is_type_float}; - } - case eOBJSyntaxElement::normal: { - return {"vn {:.4f} {:.4f} {:.4f}\n", 3, is_type_float}; - } - case eOBJSyntaxElement::poly_element_begin: { - return {"f", 0, is_type_string_related}; - } - case eOBJSyntaxElement::vertex_uv_normal_indices: { - return {" {}/{}/{}", 3, is_type_integral}; - } - case eOBJSyntaxElement::vertex_normal_indices: { - return {" {}//{}", 2, is_type_integral}; - } - case eOBJSyntaxElement::vertex_uv_indices: { - return {" {}/{}", 2, is_type_integral}; - } - case eOBJSyntaxElement::vertex_indices: { - return {" {}", 1, is_type_integral}; - } - case eOBJSyntaxElement::poly_usemtl: { - return {"usemtl {}\n", 1, is_type_string_related}; - } - case eOBJSyntaxElement::edge: { - return {"l {} {}\n", 2, is_type_integral}; - } - case eOBJSyntaxElement::cstype: { - return {"cstype bspline\n", 0, is_type_string_related}; - } - case eOBJSyntaxElement::nurbs_degree: { - return {"deg {}\n", 1, is_type_integral}; - } - case eOBJSyntaxElement::curve_element_begin: { - return {"curv 0.0 1.0", 0, is_type_string_related}; - } - case eOBJSyntaxElement::nurbs_parameter_begin: { - return {"parm u 0.0", 0, is_type_string_related}; - } - case eOBJSyntaxElement::nurbs_parameters: { - return {" {:.6f}", 1, is_type_float}; - } - case eOBJSyntaxElement::nurbs_parameter_end: { - return {" 1.0\n", 0, is_type_string_related}; - } - case eOBJSyntaxElement::nurbs_group_end: { - return {"end\n", 0, is_type_string_related}; - } - case eOBJSyntaxElement::poly_element_end: { - ATTR_FALLTHROUGH; - } - case eOBJSyntaxElement::curve_element_end: { - ATTR_FALLTHROUGH; - } - case eOBJSyntaxElement::new_line: { - return {"\n", 0, is_type_string_related}; - } - case eOBJSyntaxElement::mtllib: { - return {"mtllib {}\n", 1, is_type_string_related}; - } - case eOBJSyntaxElement::smooth_group: { - return {"s {}\n", 1, is_type_integral}; - } - case eOBJSyntaxElement::object_group: { - return {"g {}\n", 1, is_type_string_related}; - } - case eOBJSyntaxElement::object_name: { - return {"o {}\n", 1, is_type_string_related}; - } - case eOBJSyntaxElement::string: { - return {"{}", 1, is_type_string_related}; - } - } -} - -template -constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key) -{ - switch (key) { - case eMTLSyntaxElement::newmtl: { - return {"newmtl {}\n", 1, is_type_string_related}; - } - case eMTLSyntaxElement::Ni: { - return {"Ni {:.6f}\n", 1, is_type_float}; - } - case eMTLSyntaxElement::d: { - return {"d {:.6f}\n", 1, is_type_float}; - } - case eMTLSyntaxElement::Ns: { - return {"Ns {:.6f}\n", 1, is_type_float}; - } - case eMTLSyntaxElement::illum: { - return {"illum {}\n", 1, is_type_integral}; - } - case eMTLSyntaxElement::Ka: { - return {"Ka {:.6f} {:.6f} {:.6f}\n", 3, is_type_float}; - } - case eMTLSyntaxElement::Kd: { - return {"Kd {:.6f} {:.6f} {:.6f}\n", 3, is_type_float}; - } - case eMTLSyntaxElement::Ks: { - return {"Ks {:.6f} {:.6f} {:.6f}\n", 3, is_type_float}; - } - case eMTLSyntaxElement::Ke: { - return {"Ke {:.6f} {:.6f} {:.6f}\n", 3, is_type_float}; - } - /* NOTE: first texture map related argument, if present, will have its own leading space. */ - case eMTLSyntaxElement::map_Kd: { - return {"map_Kd{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_Ks: { - return {"map_Ks{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_Ns: { - return {"map_Ns{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_d: { - return {"map_d{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_refl: { - return {"map_refl{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_Ke: { - return {"map_Ke{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::map_Bump: { - return {"map_Bump{} {}\n", 2, is_type_string_related}; - } - case eMTLSyntaxElement::string: { - return {"{}", 1, is_type_string_related}; - } - } -} -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - /** - * File format and syntax agnostic file buffer writer. + * File buffer writer. * All writes are done into an internal chunked memory buffer * (list of default 64 kilobyte blocks). * Call write_fo_file once in a while to write the memory buffer(s) * into the given file. */ -template class FormatHandler : NonCopyable, NonMovable { private: typedef std::vector VectorChar; std::vector blocks_; + size_t buffer_chunk_size_; public: + FormatHandler(size_t buffer_chunk_size = 64 * 1024) : buffer_chunk_size_(buffer_chunk_size) + { + } + /* Write contents to the buffer(s) into a file, and clear the buffers. */ void write_to_file(FILE *f) { @@ -305,7 +61,7 @@ class FormatHandler : NonCopyable, NonMovable { return blocks_.size(); } - void append_from(FormatHandler &v) + void append_from(FormatHandler &v) { blocks_.insert(blocks_.end(), std::make_move_iterator(v.blocks_.begin()), @@ -313,24 +69,132 @@ class FormatHandler : NonCopyable, NonMovable { v.blocks_.clear(); } - /** - * Example invocation: `writer->write("foo")`. - * - * \param key: Must match what the instance's filetype expects; i.e., `eMTLSyntaxElement` for - * `eFileType::MTL`. - */ - template::SyntaxType key, typename... T> - constexpr void write(T &&...args) - { - /* Get format syntax, number of arguments expected and whether types of given arguments are - * valid. - */ - constexpr FormattingSyntax fmt_nargs_valid = syntax_elem_to_formatting(key); - BLI_STATIC_ASSERT(fmt_nargs_valid.are_types_valid && - (sizeof...(T) == fmt_nargs_valid.total_args), - "Types of all arguments and the number of arguments should match what the " - "formatting specifies."); - write_impl(fmt_nargs_valid.fmt, std::forward(args)...); + void write_obj_vertex(float x, float y, float z) + { + write_impl("v {:.6f} {:.6f} {:.6f}\n", x, y, z); + } + void write_obj_vertex_color(float x, float y, float z, float r, float g, float b) + { + write_impl("v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", x, y, z, r, g, b); + } + void write_obj_uv(float x, float y) + { + write_impl("vt {:.6f} {:.6f}\n", x, y); + } + void write_obj_normal(float x, float y, float z) + { + write_impl("vn {:.4f} {:.4f} {:.4f}\n", x, y, z); + } + void write_obj_poly_begin() + { + write_impl("f"); + } + void write_obj_poly_end() + { + write_obj_newline(); + } + void write_obj_poly_v_uv_normal(int v, int uv, int n) + { + write_impl(" {}/{}/{}", v, uv, n); + } + void write_obj_poly_v_normal(int v, int n) + { + write_impl(" {}//{}", v, n); + } + void write_obj_poly_v_uv(int v, int uv) + { + write_impl(" {}/{}", v, uv); + } + void write_obj_poly_v(int v) + { + write_impl(" {}", v); + } + void write_obj_usemtl(StringRef s) + { + write_impl("usemtl {}\n", s); + } + void write_obj_mtllib(StringRef s) + { + write_impl("mtllib {}\n", s); + } + void write_obj_smooth(int s) + { + write_impl("s {}\n", s); + } + void write_obj_group(StringRef s) + { + write_impl("g {}\n", s); + } + void write_obj_object(StringRef s) + { + write_impl("o {}\n", s); + } + void write_obj_edge(int a, int b) + { + write_impl("l {} {}\n", a, b); + } + void write_obj_cstype() + { + write_impl("cstype bspline\n"); + } + void write_obj_nurbs_degree(int deg) + { + write_impl("deg {}\n", deg); + } + void write_obj_curve_begin() + { + write_impl("curv 0.0 1.0"); + } + void write_obj_curve_end() + { + write_obj_newline(); + } + void write_obj_nurbs_parm_begin() + { + write_impl("parm u 0.0"); + } + void write_obj_nurbs_parm(float v) + { + write_impl(" {:.6f}", v); + } + void write_obj_nurbs_parm_end() + { + write_impl(" 1.0\n"); + } + void write_obj_nurbs_group_end() + { + write_impl("end\n"); + } + void write_obj_newline() + { + write_impl("\n"); + } + + void write_mtl_newmtl(StringRef s) + { + write_impl("newmtl {}\n", s); + } + void write_mtl_float(const char *type, float v) + { + write_impl("{} {:.6f}\n", type, v); + } + void write_mtl_float3(const char *type, float r, float g, float b) + { + write_impl("{} {:.6f} {:.6f} {:.6f}\n", type, r, g, b); + } + void write_mtl_illum(int mode) + { + write_impl("illum {}\n", mode); + } + /* Note: options, if present, will have its own leading space. */ + void write_mtl_map(const char *type, StringRef options, StringRef value) + { + write_impl("{}{} {}\n", type, options, value); + } + + void write_string(StringRef s) + { + write_impl("{}\n", s); } private: @@ -340,7 +204,7 @@ class FormatHandler : NonCopyable, NonMovable { { if (blocks_.empty() || (blocks_.back().capacity() - blocks_.back().size() < at_least)) { VectorChar &b = blocks_.emplace_back(VectorChar()); - b.reserve(std::max(at_least, buffer_chunk_size)); + b.reserve(std::max(at_least, buffer_chunk_size_)); } } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index 4ed148ec64e..dafbca0f995 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -22,6 +22,18 @@ namespace blender::io::obj { +const char *tex_map_type_to_socket_id[] = { + "Base Color", + "Specular", + "Roughness", + "Alpha", + "Metallic", + "Emission", + "Normal", +}; +BLI_STATIC_ASSERT(ARRAY_SIZE(tex_map_type_to_socket_id) == (int)MTLTexMapType::Count, + "array size mismatch"); + /** * Copy a float property of the given type from the bNode to given buffer. */ @@ -73,7 +85,7 @@ static void copy_property_from_node(const eNodeSocketDatatype property_type, */ static void linked_sockets_to_dest_id(const bNode *dest_node, const nodes::NodeTreeRef &node_tree, - StringRefNull dest_socket_id, + const char *dest_socket_id, Vector &r_linked_sockets) { r_linked_sockets.clear(); @@ -84,7 +96,7 @@ static void linked_sockets_to_dest_id(const bNode *dest_node, Span dest_inputs = object_dest_nodes.first()->inputs(); const nodes::InputSocketRef *dest_socket = nullptr; for (const nodes::InputSocketRef *curr_socket : dest_inputs) { - if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) { + if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id)) { dest_socket = curr_socket; break; } @@ -269,12 +281,12 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, * - finding "Strength" property of the node for `-bm` option. */ - for (Map::MutableItem texture_map : - r_mtl_mat.texture_maps.items()) { + for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { + MTLTexMap &value = r_mtl_mat.texture_maps[key]; Vector linked_sockets; const bNode *normal_map_node{nullptr}; - if (texture_map.key == eMTLSyntaxElement::map_Bump) { + if (key == (int)MTLTexMapType::bump) { /* Find sockets linked to destination "Normal" socket in P-BSDF node. */ linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets); /* Among the linked sockets, find Normal Map shader node. */ @@ -285,7 +297,7 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, } else { /* Skip emission map if emission strength is zero. */ - if (texture_map.key == eMTLSyntaxElement::map_Ke) { + if (key == (int)MTLTexMapType::Ke) { float emission_strength = 0.0f; copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); if (emission_strength == 0.0f) { @@ -293,8 +305,7 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, } } /* Find sockets linked to the destination socket of interest, in P-BSDF node. */ - linked_sockets_to_dest_id( - bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets); + linked_sockets_to_dest_id(bnode, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); } /* Among the linked sockets, find Image Texture shader node. */ @@ -317,10 +328,10 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, } /* Texture transform options. Only translation (origin offset, "-o") and scale * ("-o") are supported. */ - copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3}); - copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3}); + copy_property_from_node(SOCK_VECTOR, mapping, "Location", {value.translation, 3}); + copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {value.scale, 3}); - texture_map.value.image_path = tex_image_filepath; + value.image_path = tex_image_filepath; } } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh index f83b3b49bf5..d8eafff107b 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh @@ -6,36 +6,23 @@ #pragma once -#include "BLI_map.hh" #include "BLI_math_vec_types.hh" #include "DNA_node_types.h" -#include "obj_export_io.hh" - -namespace blender { -template<> struct DefaultHash { - uint64_t operator()(const io::obj::eMTLSyntaxElement value) const - { - return static_cast(value); - } -}; - -} // namespace blender +struct Material; namespace blender::io::obj { -/** - * Generic container for texture node properties. - */ -struct tex_map_XX { - tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){}; +enum class MTLTexMapType { Kd = 0, Ks, Ns, d, refl, Ke, bump, Count }; +extern const char *tex_map_type_to_socket_id[]; + +struct MTLTexMap { bool is_valid() const { return !image_path.empty(); } /* Target socket which this texture node connects to. */ - const std::string dest_socket_id; float3 translation{0.0f}; float3 scale{1.0f}; /* Only Flat and Sphere projections are supported. */ @@ -48,26 +35,13 @@ struct tex_map_XX { * Container suited for storing Material data for/from a .MTL file. */ struct MTLMaterial { - MTLMaterial() - { - texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color")); - texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular")); - texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness")); - texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha")); - texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic")); - texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission")); - texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal")); - } - - const tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key) const + const MTLTexMap &tex_map_of_type(MTLTexMapType key) const { - BLI_assert(texture_maps.contains(key)); - return texture_maps.lookup(key); + return texture_maps[(int)key]; } - tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key) + MTLTexMap &tex_map_of_type(MTLTexMapType key) { - BLI_assert(texture_maps.contains(key)); - return texture_maps.lookup(key); + return texture_maps[(int)key]; } std::string name; @@ -81,7 +55,7 @@ struct MTLMaterial { float Ni{-1.0f}; float d{-1.0f}; int illum{-1}; - Map texture_maps; + MTLTexMap texture_maps[(int)MTLTexMapType::Count]; /** Only used for Normal Map node: "map_Bump". */ float map_Bump_strength{-1.0f}; }; diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index 77d4f6268bc..76cf9066bf4 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -143,7 +143,7 @@ static void write_mesh_objects(Vector> exportable_as_me * we have to have the output text buffer for each object, * and write them all into the file at the end. */ size_t count = exportable_as_mesh.size(); - std::vector> buffers(count); + std::vector buffers(count); /* Serial: gather material indices, ensure normals & edges. */ Vector> mtlindices; @@ -242,7 +242,7 @@ static void write_mesh_objects(Vector> exportable_as_me static void write_nurbs_curve_objects(const Vector> &exportable_as_nurbs, const OBJWriter &obj_writer) { - FormatHandler fh; + FormatHandler fh; /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine * to wait for #blender::Vector to clean the objects up. */ for (const std::unique_ptr &obj_curve : exportable_as_nurbs) { diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index 633f70b2e38..088784b4194 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -592,36 +592,31 @@ void OBJParser::parse(Vector> &r_all_geometries, add_default_mtl_library(); } -static eMTLSyntaxElement mtl_line_start_to_enum(const char *&p, const char *end) +static MTLTexMapType mtl_line_start_to_texture_type(const char *&p, const char *end) { if (parse_keyword(p, end, "map_Kd")) { - return eMTLSyntaxElement::map_Kd; + return MTLTexMapType::Kd; } if (parse_keyword(p, end, "map_Ks")) { - return eMTLSyntaxElement::map_Ks; + return MTLTexMapType::Ks; } if (parse_keyword(p, end, "map_Ns")) { - return eMTLSyntaxElement::map_Ns; + return MTLTexMapType::Ns; } if (parse_keyword(p, end, "map_d")) { - return eMTLSyntaxElement::map_d; + return MTLTexMapType::d; } - if (parse_keyword(p, end, "refl")) { - return eMTLSyntaxElement::map_refl; - } - if (parse_keyword(p, end, "map_refl")) { - return eMTLSyntaxElement::map_refl; + if (parse_keyword(p, end, "refl") || parse_keyword(p, end, "map_refl")) { + return MTLTexMapType::refl; } if (parse_keyword(p, end, "map_Ke")) { - return eMTLSyntaxElement::map_Ke; - } - if (parse_keyword(p, end, "bump")) { - return eMTLSyntaxElement::map_Bump; + return MTLTexMapType::Ke; } - if (parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) { - return eMTLSyntaxElement::map_Bump; + if (parse_keyword(p, end, "bump") || parse_keyword(p, end, "map_Bump") || + parse_keyword(p, end, "map_bump")) { + return MTLTexMapType::bump; } - return eMTLSyntaxElement::string; + return MTLTexMapType::Count; } static const std::pair unsupported_texture_options[] = { @@ -639,7 +634,7 @@ static const std::pair unsupported_texture_options[] = { static bool parse_texture_option(const char *&p, const char *end, MTLMaterial *material, - tex_map_XX &tex_map) + MTLTexMap &tex_map) { p = drop_whitespace(p, end); if (parse_keyword(p, end, "-o")) { @@ -693,13 +688,13 @@ static void parse_texture_map(const char *p, if (!is_map && !is_refl && !is_bump) { return; } - eMTLSyntaxElement key = mtl_line_start_to_enum(p, end); - if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) { + MTLTexMapType key = mtl_line_start_to_texture_type(p, end); + if (key == MTLTexMapType::Count) { /* No supported texture map found. */ std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl; return; } - tex_map_XX &tex_map = material->texture_maps.lookup(key); + MTLTexMap &tex_map = material->tex_map_of_type(key); tex_map.mtl_dir_path = mtl_dir_path; /* Parse texture map options. */ diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 093cbec32fe..c28de14f2f7 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -17,8 +17,6 @@ #include "NOD_shader.h" -/* TODO: move eMTLSyntaxElement out of following file into a more neutral place */ -#include "obj_export_io.hh" #include "obj_import_mtl.hh" #include "obj_import_string_utils.hh" @@ -29,12 +27,12 @@ namespace blender::io::obj { * Only float value(s) can be set using this method. */ static void set_property_of_socket(eNodeSocketDatatype property_type, - StringRef socket_id, + const char *socket_id, Span value, bNode *r_node) { BLI_assert(r_node); - bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id.data())}; + bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id)}; BLI_assert(socket && socket->type == property_type); switch (property_type) { case SOCK_FLOAT: { @@ -95,7 +93,7 @@ static Image *create_placeholder_image(Main *bmain, const std::string &path) return image; } -static Image *load_texture_image(Main *bmain, const tex_map_XX &tex_map, bool relative_paths) +static Image *load_texture_image(Main *bmain, const MTLTexMap &tex_map, bool relative_paths) { Image *image = nullptr; @@ -206,15 +204,15 @@ std::pair ShaderNodetreeWrap::set_node_locations(const int pos_x) } void ShaderNodetreeWrap::link_sockets(bNode *from_node, - StringRef from_node_id, + const char *from_node_id, bNode *to_node, - StringRef to_node_id, + const char *to_node_id, const int from_node_pos_x) { std::tie(from_node->locx, from_node->locy) = set_node_locations(from_node_pos_x); std::tie(to_node->locx, to_node->locy) = set_node_locations(from_node_pos_x + 1); - bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id.data())}; - bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id.data())}; + bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id)}; + bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id)}; BLI_assert(from_sock && to_sock); nodeAddLink(nodetree_.get(), from_node, from_sock, to_node, to_sock); } @@ -338,7 +336,7 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat) if (emission_color.x >= 0 && emission_color.y >= 0 && emission_color.z >= 0) { set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf_); } - if (mtl_mat_.tex_map_of_type(eMTLSyntaxElement::map_Ke).is_valid()) { + if (mtl_mat_.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf_); } set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf_); @@ -359,38 +357,36 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat) void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat, bool relative_paths) { - for (const Map::Item texture_map : - mtl_mat_.texture_maps.items()) { - if (!texture_map.value.is_valid()) { + for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { + const MTLTexMap &value = mtl_mat_.texture_maps[key]; + if (!value.is_valid()) { /* No Image texture node of this map type can be added to this material. */ continue; } bNode *image_texture = add_node_to_tree(SH_NODE_TEX_IMAGE); BLI_assert(image_texture); - Image *image = load_texture_image(bmain, texture_map.value, relative_paths); + Image *image = load_texture_image(bmain, value, relative_paths); if (image == nullptr) { continue; } image_texture->id = &image->id; - static_cast(image_texture->storage)->projection = - texture_map.value.projection_type; + static_cast(image_texture->storage)->projection = value.projection_type; /* Add normal map node if needed. */ bNode *normal_map = nullptr; - if (texture_map.key == eMTLSyntaxElement::map_Bump) { + if (key == (int)MTLTexMapType::bump) { normal_map = add_node_to_tree(SH_NODE_NORMAL_MAP); const float bump = std::max(0.0f, mtl_mat_.map_Bump_strength); set_property_of_socket(SOCK_FLOAT, "Strength", {bump}, normal_map); } /* Add UV mapping & coordinate nodes only if needed. */ - if (texture_map.value.translation != float3(0, 0, 0) || - texture_map.value.scale != float3(1, 1, 1)) { + if (value.translation != float3(0, 0, 0) || value.scale != float3(1, 1, 1)) { bNode *mapping = add_node_to_tree(SH_NODE_MAPPING); bNode *texture_coordinate = add_node_to_tree(SH_NODE_TEX_COORD); - set_property_of_socket(SOCK_VECTOR, "Location", {texture_map.value.translation, 3}, mapping); - set_property_of_socket(SOCK_VECTOR, "Scale", {texture_map.value.scale, 3}, mapping); + set_property_of_socket(SOCK_VECTOR, "Location", {value.translation, 3}, mapping); + set_property_of_socket(SOCK_VECTOR, "Scale", {value.scale, 3}, mapping); link_sockets(texture_coordinate, "UV", mapping, "Vector", 0); link_sockets(mapping, "Vector", image_texture, "Vector", 1); @@ -400,12 +396,12 @@ void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat, bool rel link_sockets(image_texture, "Color", normal_map, "Color", 2); link_sockets(normal_map, "Normal", bsdf_, "Normal", 3); } - else if (texture_map.key == eMTLSyntaxElement::map_d) { - link_sockets(image_texture, "Alpha", bsdf_, texture_map.value.dest_socket_id, 2); + else if (key == (int)MTLTexMapType::d) { + link_sockets(image_texture, "Alpha", bsdf_, tex_map_type_to_socket_id[key], 2); mat->blend_method = MA_BM_BLEND; } else { - link_sockets(image_texture, "Color", bsdf_, texture_map.value.dest_socket_id, 2); + link_sockets(image_texture, "Color", bsdf_, tex_map_type_to_socket_id[key], 2); } } } diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh b/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh index 17dd0106fea..2c51d92a2cd 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh @@ -10,7 +10,6 @@ #include "BLI_map.hh" #include "BLI_math_vec_types.hh" -#include "BLI_string_ref.hh" #include "BLI_vector.hh" #include "DNA_node_types.h" @@ -75,9 +74,9 @@ class ShaderNodetreeWrap { * \param from_node_pos_x: 0 to 4 value as per nodetree arrangement. */ void link_sockets(bNode *from_node, - StringRef from_node_id, + const char *from_node_id, bNode *to_node, - StringRef to_node_id, + const char *to_node_id, const int from_node_pos_x); /** * Set values of sockets in p-BSDF node of the nodetree. 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 f582064e0c1..0fd711bdac6 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -185,17 +185,17 @@ TEST(obj_exporter_writer, mtllib) TEST(obj_exporter_writer, format_handler_buffer_chunking) { /* Use a tiny buffer chunk size, so that the test below ends up creating several blocks. */ - FormatHandler h; - h.write("abc"); - h.write("abcd"); - h.write("abcde"); - h.write("abcdef"); - h.write("012345678901234567890123456789abcd"); - h.write("123"); - h.write(); - h.write(); - h.write(); - h.write(); + FormatHandler h(16); + h.write_obj_object("abc"); + h.write_obj_object("abcd"); + h.write_obj_object("abcde"); + h.write_obj_object("abcdef"); + h.write_obj_object("012345678901234567890123456789abcd"); + h.write_obj_object("123"); + h.write_obj_curve_begin(); + h.write_obj_newline(); + h.write_obj_nurbs_parm_begin(); + h.write_obj_newline(); size_t got_blocks = h.get_block_count(); ASSERT_EQ(got_blocks, 7); diff --git a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc index 08050ac34c9..41faba95b30 100644 --- a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc @@ -58,9 +58,9 @@ class obj_mtl_parser_test : public testing::Test { EXPECT_NEAR(exp.d, got.d, tol); EXPECT_NEAR(exp.map_Bump_strength, got.map_Bump_strength, tol); EXPECT_EQ(exp.illum, got.illum); - for (const auto &it : exp.texture_maps.items()) { - const tex_map_XX &exp_tex = it.value; - const tex_map_XX &got_tex = got.texture_maps.lookup(it.key); + for (int key = 0; key < (int)MTLTexMapType::Count; key++) { + const MTLTexMap &exp_tex = exp.texture_maps[key]; + const MTLTexMap &got_tex = got.texture_maps[key]; EXPECT_STREQ(exp_tex.image_path.c_str(), got_tex.image_path.c_str()); EXPECT_V3_NEAR(exp_tex.translation, got_tex.translation, tol); EXPECT_V3_NEAR(exp_tex.scale, got_tex.scale, tol); @@ -113,8 +113,8 @@ TEST_F(obj_mtl_parser_test, string_newlines_whitespace) mat[4].Kd = {0.6f, 0.7f, 0.8f}; mat[5].name = "crlf_ending"; mat[5].Ns = 5.0f; - mat[5].tex_map_of_type(eMTLSyntaxElement::map_Kd).image_path = "sometex_d.png"; - mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ks).image_path = "sometex_s_spaces_after_name.png"; + mat[5].tex_map_of_type(MTLTexMapType::Kd).image_path = "sometex_d.png"; + mat[5].tex_map_of_type(MTLTexMapType::Ks).image_path = "sometex_s_spaces_after_name.png"; check_string(text, mat, ARRAY_SIZE(mat)); } @@ -175,13 +175,13 @@ TEST_F(obj_mtl_parser_test, materials) mat[1].illum = 2; mat[1].map_Bump_strength = 1; { - tex_map_XX &kd = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[1].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "texture.png"; - tex_map_XX &ns = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[1].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "sometexture_Roughness.png"; - tex_map_XX &refl = mat[1].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[1].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "sometexture_Metallic.png"; - tex_map_XX &bump = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[1].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "sometexture_Normal.png"; } @@ -202,13 +202,13 @@ TEST_F(obj_mtl_parser_test, materials) mat[3].Ns = 800; mat[3].map_Bump_strength = 0.5f; { - tex_map_XX &kd = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[3].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "someHatTexture_BaseColor.jpg"; - tex_map_XX &ns = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[3].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "someHatTexture_Roughness.jpg"; - tex_map_XX &refl = mat[3].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[3].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "someHatTexture_Metalness.jpg"; - tex_map_XX &bump = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[3].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "someHatTexture_Normal.jpg"; } @@ -222,30 +222,30 @@ TEST_F(obj_mtl_parser_test, materials) mat[4].d = 0.5; mat[4].map_Bump_strength = 0.1f; { - tex_map_XX &kd = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[4].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "sometex_d.png"; - tex_map_XX &ns = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[4].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "sometex_ns.psd"; - tex_map_XX &refl = mat[4].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[4].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "clouds.tiff"; refl.scale = {1.5f, 2.5f, 3.5f}; refl.translation = {4.5f, 5.5f, 6.5f}; refl.projection_type = SHD_PROJ_SPHERE; - tex_map_XX &bump = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[4].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "somebump.tga"; bump.scale = {3, 4, 5}; } mat[5].name = "Parser_ScaleOffset_Test"; { - tex_map_XX &kd = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[5].tex_map_of_type(MTLTexMapType::Kd); kd.translation = {2.5f, 0.0f, 0.0f}; kd.image_path = "OffsetOneValue.png"; - tex_map_XX &ks = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ks); + MTLTexMap &ks = mat[5].tex_map_of_type(MTLTexMapType::Ks); ks.scale = {1.5f, 2.5f, 1.0f}; ks.translation = {3.5f, 4.5f, 0.0f}; ks.image_path = "ScaleOffsetBothTwovalues.png"; - tex_map_XX &ns = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[5].tex_map_of_type(MTLTexMapType::Ns); ns.scale = {0.5f, 1.0f, 1.0f}; ns.image_path = "1.Value.png"; } -- cgit v1.2.3 From 6177d9f0c8981837491f5153e3aab4ec0d04db44 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 10:28:35 +0200 Subject: Fix: reverse uv lookup fails due to floating point accuracy issues The case when the query uv is almost on an edge but outside of any triangle was handled before. Now the case where the query uv is almost on an edge but inside more than one triangle is handled as well. --- source/blender/geometry/intern/reverse_uv_sampler.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc index 39fec40333c..f66e4a3ac2e 100644 --- a/source/blender/geometry/intern/reverse_uv_sampler.cc +++ b/source/blender/geometry/intern/reverse_uv_sampler.cc @@ -50,6 +50,11 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const float3 best_bary_weights; const MLoopTri *best_looptri; + /* The distance to an edge that is allowed to be inside or outside the triangle. Without this, + * the lookup can fail for floating point accuracy reasons when the uv is almost exact on an + * edge. */ + const float edge_epsilon = 0.00001f; + for (const int looptri_index : looptri_indices) { const MLoopTri &looptri = looptris_[looptri_index]; const float2 &uv_0 = uv_map_[looptri.tri[0]]; @@ -68,8 +73,12 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const const float dist = MAX3(x_dist, y_dist, z_dist); if (dist <= 0.0f && best_dist <= 0.0f) { - /* The uv sample is in multiple triangles. */ - return Result{ResultType::Multiple}; + const float worse_dist = std::max(dist, best_dist); + /* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */ + if (worse_dist < -edge_epsilon) { + /* The uv sample is in multiple triangles. */ + return Result{ResultType::Multiple}; + } } if (dist < best_dist) { @@ -79,8 +88,9 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const } } - /* Allow for a small epsilon in case the uv is on th edge. */ - if (best_dist < 0.00001f) { + /* Allow using the closest (but not intersecting) triangle if the uv is almost exactly on an + * edge. */ + if (best_dist < edge_epsilon) { return Result{ResultType::Ok, best_looptri, math::clamp(best_bary_weights, 0.0f, 1.0f)}; } -- cgit v1.2.3 From 5a60535a20393a4215f7a03fe77d927bacb71438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 31 Aug 2022 11:18:12 +0200 Subject: GPUCapabilities: Add GPU_shader_draw_parameters_support This checks for the availability of `gl_BaseInstanceARB` or equivalent. Disabling for any workaround that disables shader_image_load_store_support as a preventive measure. --- source/blender/gpu/GPU_capabilities.h | 1 + source/blender/gpu/intern/gpu_capabilities.cc | 5 +++++ source/blender/gpu/intern/gpu_capabilities_private.hh | 1 + source/blender/gpu/metal/mtl_backend.mm | 2 ++ source/blender/gpu/opengl/gl_backend.cc | 5 +++++ 5 files changed, 14 insertions(+) diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h index 7fe467de402..aa01f446b9b 100644 --- a/source/blender/gpu/GPU_capabilities.h +++ b/source/blender/gpu/GPU_capabilities.h @@ -47,6 +47,7 @@ bool GPU_crappy_amd_driver(void); bool GPU_compute_shader_support(void); bool GPU_shader_storage_buffer_objects_support(void); bool GPU_shader_image_load_store_support(void); +bool GPU_shader_draw_parameters_support(void); bool GPU_mem_stats_supported(void); void GPU_mem_stats_get(int *totalmem, int *freemem); diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index 18748627b83..73f94ecfb1b 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -161,6 +161,11 @@ bool GPU_shader_image_load_store_support() return GCaps.shader_image_load_store_support; } +bool GPU_shader_draw_parameters_support() +{ + return GCaps.shader_draw_parameters_support; +} + int GPU_max_shader_storage_buffer_bindings() { return GCaps.max_shader_storage_buffer_bindings; diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index a17dbe7f8e6..dadd14791e7 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -44,6 +44,7 @@ struct GPUCapabilities { bool compute_shader_support = false; bool shader_storage_buffer_objects_support = false; bool shader_image_load_store_support = false; + bool shader_draw_parameters_support = false; bool transform_feedback_support = false; /* OpenGL related workarounds. */ diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm index 83cf3af0804..a15da4df083 100644 --- a/source/blender/gpu/metal/mtl_backend.mm +++ b/source/blender/gpu/metal/mtl_backend.mm @@ -381,6 +381,8 @@ void MTLBackend::capabilities_init(MTLContext *ctx) GCaps.shader_image_load_store_support = ([device supportsFamily:MTLGPUFamilyApple3] || MTLBackend::capabilities.supports_family_mac1 || MTLBackend::capabilities.supports_family_mac2); + /* TODO(Metal): Add support? */ + GCaps.shader_draw_parameters_support = false; GCaps.compute_shader_support = false; /* TODO(Metal): Add compute support. */ GCaps.shader_storage_buffer_objects_support = false; /* TODO(Metal): implement Storage Buffer support. */ diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 6a1577fb907..24ca8c25bc0 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -227,6 +227,7 @@ static void detect_workarounds() GLContext::unused_fb_slot_workaround = true; /* Turn off extensions. */ GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.shader_storage_buffer_objects_support = false; GLContext::base_instance_support = false; GLContext::clear_texture_support = false; @@ -271,6 +272,7 @@ static void detect_workarounds() GLContext::unused_fb_slot_workaround = true; GCaps.mip_render_workaround = true; GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* Compute shaders have some issues with those versions (see T94936). */ @@ -284,12 +286,14 @@ static void detect_workarounds() strstr(renderer, "AMD TAHITI"))) { GLContext::unused_fb_slot_workaround = true; GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* Fix slowdown on this particular driver. (see T77641) */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && strstr(version, "Mesa 19.3.4")) { GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the @@ -492,6 +496,7 @@ void GLBackend::capabilities_init() GCaps.mem_stats_support = epoxy_has_gl_extension("GL_NVX_gpu_memory_info") || epoxy_has_gl_extension("GL_ATI_meminfo"); GCaps.shader_image_load_store_support = epoxy_has_gl_extension("GL_ARB_shader_image_load_store"); + GCaps.shader_draw_parameters_support = epoxy_has_gl_extension("GL_ARB_shader_draw_parameters"); GCaps.compute_shader_support = epoxy_has_gl_extension("GL_ARB_compute_shader") && epoxy_gl_version() >= 43; if (GCaps.compute_shader_support) { -- cgit v1.2.3 From 25e307d725d0b924fb0e87e4ffde84f915b74310 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 12:15:57 +0200 Subject: Nodes: move NodeTreeRef functionality into node runtime data The purpose of `NodeTreeRef` was to speed up various queries on a read-only `bNodeTree`. Not that we have runtime data in nodes and sockets, we can also store the result of some queries there. This has some benefits: * No need for a read-only separate node tree data structure which increased complexity. * Makes it easier to reuse cached queries in more parts of Blender that can benefit from it. A downside is that we loose some type safety that we got by having different types for input and output sockets, as well as internal and non-internal links. This patch also refactors `DerivedNodeTree` so that it does not use `NodeTreeRef` anymore, but uses `bNodeTree` directly instead. To provide a convenient API (that is also close to what `NodeTreeRef` has), a new approach is implemented: `bNodeTree`, `bNode`, `bNodeSocket` and `bNodeLink` now have C++ methods declared in `DNA_node_types.h` which are implemented in `BKE_node_runtime.hh`. To make this work, `makesdna` now skips c++ sections when parsing dna header files. No user visible changes are expected. Differential Revision: https://developer.blender.org/D15491 --- source/blender/blenkernel/BKE_node_runtime.hh | 439 +++++++++++- source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/node.cc | 2 - source/blender/blenkernel/intern/node_runtime.cc | 403 +++++++++++ .../blender/blenkernel/intern/node_tree_update.cc | 534 +++++++-------- source/blender/blenlib/BLI_multi_value_map.hh | 5 + .../realtime_compositor/COM_evaluator.hh | 3 - .../realtime_compositor/COM_utilities.hh | 4 +- .../realtime_compositor/intern/compile_state.cc | 10 +- .../realtime_compositor/intern/evaluator.cc | 21 +- .../intern/input_single_value_operation.cc | 10 +- .../realtime_compositor/intern/node_operation.cc | 18 +- .../realtime_compositor/intern/scheduler.cc | 67 +- .../realtime_compositor/intern/shader_node.cc | 30 +- .../realtime_compositor/intern/shader_operation.cc | 38 +- .../realtime_compositor/intern/utilities.cc | 15 +- .../editors/space_node/node_relationships.cc | 83 ++- .../io/wavefront_obj/exporter/obj_export_mtl.cc | 104 ++- source/blender/makesdna/DNA_node_types.h | 180 ++++- source/blender/makesdna/intern/makesdna.c | 64 ++ source/blender/modifiers/intern/MOD_nodes.cc | 84 +-- .../modifiers/intern/MOD_nodes_evaluator.cc | 194 +++--- source/blender/nodes/CMakeLists.txt | 2 - source/blender/nodes/NOD_derived_node_tree.hh | 172 +++-- source/blender/nodes/NOD_geometry_exec.hh | 2 +- source/blender/nodes/NOD_multi_function.hh | 18 +- source/blender/nodes/NOD_node_tree_ref.hh | 760 --------------------- .../nodes/composite/nodes/node_composite_image.cc | 18 +- .../nodes/composite/nodes/node_composite_normal.cc | 7 +- .../blender/nodes/function/node_function_util.hh | 2 + .../nodes/node_fn_align_euler_to_vector.cc | 2 +- .../nodes/function/nodes/node_fn_boolean_math.cc | 2 +- .../nodes/function/nodes/node_fn_combine_color.cc | 2 +- .../nodes/function/nodes/node_fn_compare.cc | 2 +- .../nodes/function/nodes/node_fn_float_to_int.cc | 2 +- .../nodes/function/nodes/node_fn_input_bool.cc | 2 +- .../nodes/function/nodes/node_fn_input_color.cc | 2 +- .../nodes/function/nodes/node_fn_input_int.cc | 2 +- .../nodes/function/nodes/node_fn_input_string.cc | 2 +- .../nodes/function/nodes/node_fn_input_vector.cc | 2 +- .../nodes/function/nodes/node_fn_rotate_euler.cc | 2 +- .../blender/nodes/geometry/node_geometry_util.hh | 2 + source/blender/nodes/intern/derived_node_tree.cc | 139 ++-- .../nodes/intern/geometry_nodes_eval_log.cc | 8 +- source/blender/nodes/intern/node_geometry_exec.cc | 34 +- source/blender/nodes/intern/node_multi_function.cc | 8 +- source/blender/nodes/intern/node_tree_ref.cc | 679 ------------------ source/blender/nodes/shader/node_shader_util.hh | 2 + .../nodes/shader/nodes/node_shader_color_ramp.cc | 2 +- .../nodes/shader/nodes/node_shader_curves.cc | 6 +- .../blender/nodes/shader/nodes/node_shader_math.cc | 2 +- .../blender/nodes/shader/nodes/node_shader_mix.cc | 2 +- .../nodes/shader/nodes/node_shader_mix_rgb.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_brick.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_gradient.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_magic.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_musgrave.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_wave.cc | 2 +- .../shader/nodes/node_shader_tex_white_noise.cc | 2 +- .../nodes/shader/nodes/node_shader_vector_math.cc | 2 +- .../shader/nodes/node_shader_vector_rotate.cc | 2 +- 61 files changed, 1865 insertions(+), 2349 deletions(-) create mode 100644 source/blender/blenkernel/intern/node_runtime.cc delete mode 100644 source/blender/nodes/NOD_node_tree_ref.hh delete mode 100644 source/blender/nodes/intern/node_tree_ref.cc diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index f5fb53f962b..64325959ce5 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -3,9 +3,20 @@ #pragma once #include +#include -#include "BLI_sys_types.h" +#include "BLI_multi_value_map.hh" #include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "DNA_node_types.h" + +#include "BKE_node.h" + +struct bNode; +struct bNodeSocket; +struct bNodeTree; +struct bNodeType; namespace blender::nodes { struct FieldInferencingInterface; @@ -36,6 +47,32 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { /** Information about how inputs and outputs of the node group interact with fields. */ std::unique_ptr field_inferencing_interface; + + /** + * Protects access to all topology cache variables below. This is necessary so that the cache can + * be updated on a const #bNodeTree. + */ + std::mutex topology_cache_mutex; + bool topology_cache_is_dirty = true; + bool topology_cache_exists = false; + /** + * Under some circumstances, it can be useful to use the cached data while editing the + * #bNodeTree. By default, this is protected against using an assert. + */ + mutable std::atomic allow_use_dirty_topology_cache = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector nodes; + Vector links; + Vector sockets; + Vector input_sockets; + Vector output_sockets; + MultiValueMap nodes_by_type; + Vector toposort_left_to_right; + Vector toposort_right_to_left; + bool has_link_cycle = false; + bool has_undefined_nodes_or_sockets = false; + bNode *group_output_node = nullptr; }; /** @@ -47,12 +84,24 @@ class bNodeSocketRuntime : NonCopyable, NonMovable { public: /** * References a socket declaration that is owned by `node->declaration`. This is only runtime - * data. It has to be updated when the node declaration changes. + * data. It has to be updated when the node declaration changes. Access can be allowed by using + * #AllowUsingOutdatedInfo. */ const SocketDeclarationHandle *declaration = nullptr; /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector directly_linked_links; + Vector directly_linked_sockets; + Vector logically_linked_sockets; + Vector logically_linked_skipped_sockets; + bNode *owner_node = nullptr; + bNodeSocket *internal_link_input = nullptr; + int index_in_node = -1; + int index_in_all_sockets = -1; + int index_in_inout_sockets = -1; }; /** @@ -84,6 +133,392 @@ class bNodeRuntime : NonCopyable, NonMovable { /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid if #topology_cache_is_dirty is false. */ + Vector inputs; + Vector outputs; + Vector internal_links; + Map inputs_by_identifier; + Map outputs_by_identifier; + int index_in_tree = -1; + bool has_linked_inputs = false; + bool has_linked_outputs = false; + bNodeTree *owner_tree = nullptr; }; +namespace node_tree_runtime { + +class AllowUsingOutdatedInfo : NonCopyable, NonMovable { + private: + const bNodeTree &tree_; + + public: + AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree) + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1); + } + + ~AllowUsingOutdatedInfo() + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1); + } +}; + +inline bool topology_cache_is_available(const bNodeTree &tree) +{ + if (!tree.runtime->topology_cache_exists) { + return false; + } + if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) { + return true; + } + return !tree.runtime->topology_cache_is_dirty; +} + +inline bool topology_cache_is_available(const bNode &node) +{ + const bNodeTree *ntree = node.runtime->owner_tree; + if (ntree == nullptr) { + return false; + } + return topology_cache_is_available(*ntree); +} + +inline bool topology_cache_is_available(const bNodeSocket &socket) +{ + const bNode *node = socket.runtime->owner_node; + if (node == nullptr) { + return false; + } + return topology_cache_is_available(*node); +} + +} // namespace node_tree_runtime + } // namespace blender::bke + +/* -------------------------------------------------------------------- */ +/** \name #bNodeTree Inline Methods + * \{ */ + +inline blender::Span bNodeTree::nodes_by_type(const blender::StringRefNull type_idname) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span bNodeTree::nodes_by_type( + const blender::StringRefNull type_idname) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span bNodeTree::toposort_left_to_right() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_left_to_right; +} + +inline blender::Span bNodeTree::toposort_right_to_left() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_right_to_left; +} + +inline blender::Span bNodeTree::all_nodes() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline blender::Span bNodeTree::all_nodes() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline bool bNodeTree::has_link_cycle() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_link_cycle; +} + +inline bool bNodeTree::has_undefined_nodes_or_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_undefined_nodes_or_sockets; +} + +inline const bNode *bNodeTree::group_output_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->group_output_node; +} + +inline blender::Span bNodeTree::all_input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span bNodeTree::all_input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span bNodeTree::all_output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span bNodeTree::all_output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span bNodeTree::all_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +inline blender::Span bNodeTree::all_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNode Inline Methods + * \{ */ + +inline blender::Span bNode::input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span bNode::output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline blender::Span bNode::input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span bNode::output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline bNodeSocket &bNode::input_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline bNodeSocket &bNode::output_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline const bNodeSocket &bNode::output_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs_by_identifier.lookup_as(identifier); +} + +inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs_by_identifier.lookup_as(identifier); +} + +inline blender::StringRefNull bNode::label_or_name() const +{ + if (this->label[0] == '\0') { + return this->name; + } + return this->label; +} + +inline bool bNode::is_muted() const +{ + return this->flag & NODE_MUTED; +} + +inline bool bNode::is_reroute() const +{ + return this->type == NODE_REROUTE; +} + +inline bool bNode::is_frame() const +{ + return this->type == NODE_FRAME; +} + +inline bool bNode::is_group() const +{ + return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP); +} + +inline bool bNode::is_group_input() const +{ + return this->type == NODE_GROUP_INPUT; +} + +inline bool bNode::is_group_output() const +{ + return this->type == NODE_GROUP_OUTPUT; +} + +inline blender::Span bNode::internal_links_span() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->internal_links; +} + +inline const blender::nodes::NodeDeclaration *bNode::declaration() const +{ + BLI_assert(this->runtime->declaration != nullptr); + return this->runtime->declaration; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeLink Inline Methods + * \{ */ + +inline bool bNodeLink::is_muted() const +{ + return this->flag & NODE_LINK_MUTED; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeSocket Inline Methods + * \{ */ + +inline int bNodeSocket::index() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_node; +} + +inline int bNodeSocket::index_in_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_all_sockets; +} + +inline bool bNodeSocket::is_available() const +{ + return (this->flag & SOCK_UNAVAIL) == 0; +} + +inline bNode &bNodeSocket::owner_node() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +inline const bNodeTree &bNodeSocket::owner_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node->runtime->owner_tree; +} + +inline blender::Span bNodeSocket::logically_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->logically_linked_sockets; +} + +inline blender::Span bNodeSocket::directly_linked_links() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span bNodeSocket::directly_linked_links() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span bNodeSocket::directly_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_sockets; +} + +inline bool bNodeSocket::is_directly_linked() const +{ + return !this->directly_linked_links().is_empty(); +} + +inline bool bNodeSocket::is_logically_linked() const +{ + return !this->logically_linked_sockets().is_empty(); +} + +inline const bNodeSocket *bNodeSocket::internal_link_input() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + BLI_assert(this->in_out == SOCK_OUT); + return this->runtime->internal_link_input; +} + +template const T *bNodeSocket::default_value_typed() const +{ + return static_cast(this->default_value); +} + +inline bool bNodeSocket::is_input() const +{ + return this->in_out == SOCK_IN; +} + +inline bool bNodeSocket::is_output() const +{ + return this->in_out == SOCK_OUT; +} + +inline bool bNodeSocket::is_multi_input() const +{ + return this->flag & SOCK_MULTI_INPUT; +} + +inline const bNode &bNodeSocket::owner_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +/** \} */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 465573745ec..61549a66e1f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -230,6 +230,7 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc + intern/node_runtime.cc intern/node_tree_update.cc intern/object.cc intern/object_deform.c diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 1a40c0a18ed..4eb48e9edc9 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -72,7 +72,6 @@ #include "NOD_function.h" #include "NOD_geometry.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_shader.h" #include "NOD_socket.h" #include "NOD_texture.h" @@ -104,7 +103,6 @@ using blender::nodes::NodeDeclaration; using blender::nodes::OutputFieldDependency; using blender::nodes::OutputSocketFieldType; using blender::nodes::SocketDeclaration; -using namespace blender::nodes::node_tree_ref_types; /* Fallback types for undefined tree, nodes, sockets */ static bNodeTreeType NodeTreeTypeUndefined; diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc new file mode 100644 index 00000000000..20ee3c41534 --- /dev/null +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_node.h" +#include "BKE_node_runtime.hh" + +#include "DNA_node_types.h" + +#include "BLI_function_ref.hh" +#include "BLI_stack.hh" +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +namespace blender::bke::node_tree_runtime { + +static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef fn) +{ + if (!data_is_dirty) { + return; + } + std::lock_guard lock{mutex}; + if (!data_is_dirty) { + return; + } + fn(); + data_is_dirty = false; +} + +static void double_checked_lock_with_task_isolation(std::mutex &mutex, + bool &data_is_dirty, + FunctionRef fn) +{ + double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); }); +} + +static void update_node_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes.clear(); + tree_runtime.has_undefined_nodes_or_sockets = false; + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node); + node->runtime->owner_tree = const_cast(&ntree); + tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined; + } +} + +static void update_link_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.links.clear(); + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + tree_runtime.links.append(link); + } +} + +static void update_internal_links(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + node->runtime->internal_links.clear(); + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->internal_link_input = nullptr; + } + LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { + node->runtime->internal_links.append(link); + link->tosock->runtime->internal_link_input = link->fromsock; + } + } +} + +static void update_socket_vectors_and_owner_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.sockets.clear(); + tree_runtime.input_sockets.clear(); + tree_runtime.output_sockets.clear(); + for (bNode *node : tree_runtime.nodes) { + bNodeRuntime &node_runtime = *node->runtime; + node_runtime.inputs.clear(); + node_runtime.outputs.clear(); + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->runtime->index_in_node = node_runtime.inputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.input_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->runtime->index_in_node = node_runtime.outputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.output_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + } +} + +static void update_directly_linked_links_and_sockets(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + for (bNodeSocket *socket : node->runtime->inputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + node->runtime->has_linked_inputs = false; + node->runtime->has_linked_outputs = false; + } + for (bNodeLink *link : tree_runtime.links) { + link->fromsock->runtime->directly_linked_links.append(link); + link->fromsock->runtime->directly_linked_sockets.append(link->tosock); + link->tosock->runtime->directly_linked_links.append(link); + link->fromnode->runtime->has_linked_outputs = true; + link->tonode->runtime->has_linked_inputs = true; + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + if (socket->flag & SOCK_MULTI_INPUT) { + std::sort(socket->runtime->directly_linked_links.begin(), + socket->runtime->directly_linked_links.end(), + [&](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index > b->multi_input_socket_index; + }); + } + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + for (bNodeLink *link : socket->runtime->directly_linked_links) { + /* Do this after sorting the input links. */ + socket->runtime->directly_linked_sockets.append(link->fromsock); + } + } +} + +static void find_logical_origins_for_socket_recursive( + bNodeSocket &input_socket, + bool only_follow_first_input_link, + Vector &sockets_in_current_chain, + Vector &r_logical_origins, + Vector &r_skipped_origins) +{ + if (sockets_in_current_chain.contains(&input_socket)) { + /* Protect against reroute recursions. */ + return; + } + sockets_in_current_chain.append(&input_socket); + + Span links_to_check = input_socket.runtime->directly_linked_links; + if (only_follow_first_input_link) { + links_to_check = links_to_check.take_front(1); + } + for (bNodeLink *link : links_to_check) { + if (link->flag & NODE_LINK_MUTED) { + continue; + } + bNodeSocket &origin_socket = *link->fromsock; + bNode &origin_node = *link->fromnode; + if (!origin_socket.is_available()) { + /* Non available sockets are ignored. */ + continue; + } + if (origin_node.type == NODE_REROUTE) { + bNodeSocket &reroute_input = *origin_node.runtime->inputs[0]; + bNodeSocket &reroute_output = *origin_node.runtime->outputs[0]; + r_skipped_origins.append(&reroute_input); + r_skipped_origins.append(&reroute_output); + find_logical_origins_for_socket_recursive( + reroute_input, false, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + continue; + } + if (origin_node.is_muted()) { + if (bNodeSocket *mute_input = origin_socket.runtime->internal_link_input) { + r_skipped_origins.append(&origin_socket); + r_skipped_origins.append(mute_input); + find_logical_origins_for_socket_recursive( + *mute_input, true, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + } + continue; + } + r_logical_origins.append(&origin_socket); + } + + sockets_in_current_chain.pop_last(); +} + +static void update_logical_origins(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + bNode &node = *tree_runtime.nodes[i]; + for (bNodeSocket *socket : node.runtime->inputs) { + Vector sockets_in_current_chain; + find_logical_origins_for_socket_recursive( + *socket, + false, + sockets_in_current_chain, + socket->runtime->logically_linked_sockets, + socket->runtime->logically_linked_skipped_sockets); + } + } + }); +} + +static void update_nodes_by_type(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes_by_type.clear(); + for (bNode *node : tree_runtime.nodes) { + tree_runtime.nodes_by_type.add(node->typeinfo, node); + } +} + +static void update_sockets_by_identifier(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (bNode *node : tree_runtime.nodes.as_span().slice(range)) { + node->runtime->inputs_by_identifier.clear(); + node->runtime->outputs_by_identifier.clear(); + for (bNodeSocket *socket : node->runtime->inputs) { + node->runtime->inputs_by_identifier.add_new(socket->identifier, socket); + } + for (bNodeSocket *socket : node->runtime->outputs) { + node->runtime->outputs_by_identifier.add_new(socket->identifier, socket); + } + } + }); +} + +enum class ToposortDirection { + LeftToRight, + RightToLeft, +}; + +struct ToposortNodeState { + bool is_done = false; + bool is_in_stack = false; +}; + +static void toposort_from_start_node(const ToposortDirection direction, + bNode &start_node, + MutableSpan node_states, + Vector &r_sorted_nodes, + bool &r_cycle_detected) +{ + struct Item { + bNode *node; + int socket_index = 0; + int link_index = 0; + }; + + Stack nodes_to_check; + nodes_to_check.push({&start_node}); + while (!nodes_to_check.is_empty()) { + Item &item = nodes_to_check.peek(); + bNode &node = *item.node; + const Span sockets = (direction == ToposortDirection::LeftToRight) ? + node.runtime->inputs : + node.runtime->outputs; + while (true) { + if (item.socket_index == sockets.size()) { + /* All sockets have already been visited. */ + break; + } + bNodeSocket &socket = *sockets[item.socket_index]; + const Span linked_sockets = socket.runtime->directly_linked_sockets; + if (item.link_index == linked_sockets.size()) { + /* All links connected to this socket have already been visited. */ + item.socket_index++; + item.link_index = 0; + continue; + } + bNodeSocket &linked_socket = *linked_sockets[item.link_index]; + bNode &linked_node = *linked_socket.runtime->owner_node; + ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree]; + if (linked_node_state.is_done) { + /* The linked node has already been visited. */ + item.link_index++; + continue; + } + if (linked_node_state.is_in_stack) { + r_cycle_detected = true; + } + else { + nodes_to_check.push({&linked_node}); + linked_node_state.is_in_stack = true; + } + break; + } + + /* If no other element has been pushed, the current node can be pushed to the sorted list. */ + if (&item == &nodes_to_check.peek()) { + ToposortNodeState &node_state = node_states[node.runtime->index_in_tree]; + node_state.is_done = true; + node_state.is_in_stack = false; + r_sorted_nodes.append(&node); + nodes_to_check.pop(); + } + } +} + +static void update_toposort(const bNodeTree &ntree, + const ToposortDirection direction, + Vector &r_sorted_nodes, + bool &r_cycle_detected) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + r_sorted_nodes.clear(); + r_sorted_nodes.reserve(tree_runtime.nodes.size()); + r_cycle_detected = false; + + Array node_states(tree_runtime.nodes.size()); + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs : + node->runtime->has_linked_inputs) { + /* Ignore non-start nodes. */ + continue; + } + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + + if (r_sorted_nodes.size() < tree_runtime.nodes.size()) { + r_cycle_detected = true; + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + /* Start toposort at this node which is somewhere in the middle of a loop. */ + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + } + + BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size()); +} + +static void update_group_output_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + const bNodeType *node_type = nodeTypeFind("NodeGroupOutput"); + const Span group_output_nodes = tree_runtime.nodes_by_type.lookup(node_type); + if (group_output_nodes.is_empty()) { + tree_runtime.group_output_node = nullptr; + } + else if (group_output_nodes.size() == 1) { + tree_runtime.group_output_node = group_output_nodes[0]; + } + else { + for (bNode *group_output : group_output_nodes) { + if (group_output->flag & NODE_DO_OUTPUT) { + tree_runtime.group_output_node = group_output; + break; + } + } + } +} + +static void ensure_topology_cache(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + double_checked_lock_with_task_isolation( + tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() { + update_node_vector(ntree); + update_link_vector(ntree); + update_socket_vectors_and_owner_node(ntree); + update_internal_links(ntree); + update_directly_linked_links_and_sockets(ntree); + threading::parallel_invoke([&]() { update_logical_origins(ntree); }, + [&]() { update_nodes_by_type(ntree); }, + [&]() { update_sockets_by_identifier(ntree); }, + [&]() { + update_toposort(ntree, + ToposortDirection::LeftToRight, + tree_runtime.toposort_left_to_right, + tree_runtime.has_link_cycle); + }, + [&]() { + bool dummy; + update_toposort(ntree, + ToposortDirection::RightToLeft, + tree_runtime.toposort_right_to_left, + dummy); + }); + update_group_output_node(ntree); + tree_runtime.topology_cache_exists = true; + }); +} + +} // namespace blender::bke::node_tree_runtime + +void bNodeTree::ensure_topology_cache() const +{ + blender::bke::node_tree_runtime::ensure_topology_cache(*this); +} diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 58084226b00..716b8ce31d3 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -5,6 +5,7 @@ #include "BLI_noise.hh" #include "BLI_set.hh" #include "BLI_stack.hh" +#include "BLI_timeit.hh" #include "BLI_vector_set.hh" #include "DNA_anim_types.h" @@ -21,7 +22,6 @@ #include "MOD_nodes.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_texture.h" #include "DEG_depsgraph_query.h" @@ -50,6 +50,7 @@ enum eNodeTreeChangedFlag { static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) { ntree->runtime->changed_flag |= flag; + ntree->runtime->topology_cache_is_dirty = true; } static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) @@ -73,31 +74,32 @@ static bool is_field_socket_type(eNodeSocketDatatype type) return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); } -static bool is_field_socket_type(const SocketRef &socket) +static bool is_field_socket_type(const bNodeSocket &socket) { - return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); + return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo->type); } -static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, - const InputSocketRef &socket) +static InputSocketFieldType get_interface_input_field_type(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { return InputSocketFieldType::None; } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { return InputSocketFieldType::IsSupported; } - if (node.is_group_output_node()) { + if (node.type == NODE_GROUP_OUTPUT) { /* Outputs always support fields when the data type is correct. */ return InputSocketFieldType::IsSupported; } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return InputSocketFieldType::None; } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return InputSocketFieldType::None; } + /* TODO: Ensure declaration exists. */ const NodeDeclaration *node_decl = node.declaration(); /* Node declarations should be implemented for nodes involved here. */ @@ -116,25 +118,25 @@ static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, return field_type; } -static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, - const OutputSocketRef &socket) +static OutputFieldDependency get_interface_output_field_dependency(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { /* Non-field sockets always output data. */ return OutputFieldDependency::ForDataSource(); } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { /* The reroute just forwards what is passed in. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_group_input_node()) { + if (node.type == NODE_GROUP_INPUT) { /* Input nodes get special treatment in #determine_group_input_states. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return OutputFieldDependency::ForDataSource(); } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return OutputFieldDependency::ForDataSource(); } @@ -153,12 +155,13 @@ static OutputFieldDependency get_interface_output_field_dependency(const NodeRef return socket_decl.output_field_dependency(); } -static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_dummy_field_inferencing_interface(const bNode &node) { FieldInferencingInterface inferencing_interface; - inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); + inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, + node.input_sockets().size()); inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), - node.outputs().size()); + node.output_sockets().size()); return inferencing_interface; } @@ -167,11 +170,11 @@ static FieldInferencingInterface get_dummy_field_inferencing_interface(const Nod * In the future, this information can be stored in the node declaration. This would allow this * function to return a reference, making it more efficient. */ -static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_node_field_inferencing_interface(const bNode &node) { /* Node groups already reference all required information, so just return that. */ - if (node.is_group_node()) { - bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (node.is_group()) { + bNodeTree *group = (bNodeTree *)node.id; if (group == nullptr) { return FieldInferencingInterface(); } @@ -187,11 +190,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node } FieldInferencingInterface inferencing_interface; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); } - for (const OutputSocketRef *output_socket : node.outputs()) { + for (const bNodeSocket *output_socket : node.output_sockets()) { inferencing_interface.outputs.append( get_interface_output_field_dependency(node, *output_socket)); } @@ -215,11 +218,11 @@ struct SocketFieldState { bool requires_single = false; }; -static Vector gather_input_socket_dependencies( - const OutputFieldDependency &field_dependency, const NodeRef &node) +static Vector gather_input_socket_dependencies( + const OutputFieldDependency &field_dependency, const bNode &node) { const OutputSocketFieldType type = field_dependency.field_type(); - Vector input_sockets; + Vector input_sockets; switch (type) { case OutputSocketFieldType::FieldSource: case OutputSocketFieldType::None: { @@ -227,13 +230,13 @@ static Vector gather_input_socket_dependencies( } case OutputSocketFieldType::DependentField: { /* This output depends on all inputs. */ - input_sockets.extend(node.inputs()); + input_sockets.extend(node.input_sockets()); break; } case OutputSocketFieldType::PartiallyDependent: { /* This output depends only on a few inputs. */ for (const int i : field_dependency.linked_input_indices()) { - input_sockets.append(&node.input(i)); + input_sockets.append(&node.input_socket(i)); } break; } @@ -246,8 +249,7 @@ static Vector gather_input_socket_dependencies( * to figure out if it is always a field or if it depends on any group inputs. */ static OutputFieldDependency find_group_output_dependencies( - const InputSocketRef &group_output_socket, - const Span field_state_by_socket_id) + const bNodeSocket &group_output_socket, const Span field_state_by_socket_id) { if (!is_field_socket_type(group_output_socket)) { return OutputFieldDependency::ForDataSource(); @@ -255,8 +257,8 @@ static OutputFieldDependency find_group_output_dependencies( /* Use a Set here instead of an array indexed by socket id, because we my only need to look at * very few sockets. */ - Set handled_sockets; - Stack sockets_to_check; + Set handled_sockets; + Stack sockets_to_check; handled_sockets.add(&group_output_socket); sockets_to_check.push(&group_output_socket); @@ -265,20 +267,21 @@ static OutputFieldDependency find_group_output_dependencies( Vector linked_input_indices; while (!sockets_to_check.is_empty()) { - const InputSocketRef *input_socket = sockets_to_check.pop(); + const bNodeSocket *input_socket = sockets_to_check.pop(); if (!input_socket->is_directly_linked() && - !field_state_by_socket_id[input_socket->id()].is_single) { + !field_state_by_socket_id[input_socket->index_in_tree()].is_single) { /* This socket uses a field as input by default. */ return OutputFieldDependency::ForFieldSource(); } - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - const NodeRef &origin_node = origin_socket->node(); - const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + const bNode &origin_node = origin_socket->owner_node(); + const SocketFieldState &origin_state = + field_state_by_socket_id[origin_socket->index_in_tree()]; if (origin_state.is_field_source) { - if (origin_node.is_group_input_node()) { + if (origin_node.type == NODE_GROUP_INPUT) { /* Found a group input that the group output depends on. */ linked_input_indices.append_non_duplicates(origin_socket->index()); } @@ -294,12 +297,12 @@ static OutputFieldDependency find_group_output_dependencies( inferencing_interface.outputs[origin_socket->index()]; /* Propagate search further to the left. */ - for (const InputSocketRef *origin_input_socket : + for (const bNodeSocket *origin_input_socket : gather_input_socket_dependencies(field_dependency, origin_node)) { if (!origin_input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { + if (!field_state_by_socket_id[origin_input_socket->index_in_tree()].is_single) { if (handled_sockets.add(origin_input_socket)) { sockets_to_check.push(origin_input_socket); } @@ -312,17 +315,16 @@ static OutputFieldDependency find_group_output_dependencies( } static void propagate_data_requirements_from_right_to_left( - const NodeTreeRef &tree, const MutableSpan field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::RightToLeft); + const Span toposort_result = tree.toposort_right_to_left(); - for (const NodeRef *node : toposort_result.sorted_nodes) { + for (const bNode *node : toposort_result) { const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( *node); - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -338,17 +340,18 @@ static void propagate_data_requirements_from_right_to_left( /* The output is required to be a single value when it is connected to any input that does * not support fields. */ - for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { + for (const bNodeSocket *target_socket : output_socket->directly_linked_sockets()) { if (target_socket->is_available()) { - state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; + state.requires_single |= + field_state_by_socket_id[target_socket->index_in_tree()].requires_single; } } if (state.requires_single) { bool any_input_is_field_implicitly = false; - const Vector connected_inputs = gather_input_socket_dependencies( + const Vector connected_inputs = gather_input_socket_dependencies( field_dependency, *node); - for (const InputSocketRef *input_socket : connected_inputs) { + for (const bNodeSocket *input_socket : connected_inputs) { if (!input_socket->is_available()) { continue; } @@ -367,16 +370,16 @@ static void propagate_data_requirements_from_right_to_left( else { /* If the output is required to be a single value, the connected inputs in the same node * must not be fields as well. */ - for (const InputSocketRef *input_socket : connected_inputs) { - field_state_by_socket_id[input_socket->id()].requires_single = true; + for (const bNodeSocket *input_socket : connected_inputs) { + field_state_by_socket_id[input_socket->index_in_tree()].requires_single = true; } } } } /* Some inputs do not require fields independent of what the outputs are connected to. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { state.requires_single = true; state.is_always_single = true; @@ -386,14 +389,14 @@ static void propagate_data_requirements_from_right_to_left( } static void determine_group_input_states( - const NodeTreeRef &tree, + const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const MutableSpan field_state_by_socket_id) { { /* Non-field inputs never support fields. */ int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { + LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.inputs, index) { if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { new_inferencing_interface.inputs[index] = InputSocketFieldType::None; } @@ -401,18 +404,18 @@ static void determine_group_input_states( } /* Check if group inputs are required to be single values, because they are (indirectly) * connected to some socket that does not support fields. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; if (state.requires_single) { new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; } } } /* If an input does not support fields, this should be reflected in all Group Input nodes. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != InputSocketFieldType::None; if (supports_field) { @@ -423,19 +426,19 @@ static void determine_group_input_states( state.requires_single = true; } } - SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; + SocketFieldState &dummy_socket_state = + field_state_by_socket_id[node->output_sockets().last()->index_in_tree()]; dummy_socket_state.requires_single = true; } } static void propagate_field_status_from_left_to_right( - const NodeTreeRef &tree, const MutableSpan field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::LeftToRight); + const Span toposort_result = tree.toposort_left_to_right(); - for (const NodeRef *node : toposort_result.sorted_nodes) { - if (node->is_group_input_node()) { + for (const bNode *node : toposort_result) { + if (node->type == NODE_GROUP_INPUT) { continue; } @@ -443,22 +446,22 @@ static void propagate_field_status_from_left_to_right( *node); /* Update field state of input sockets, also taking into account linked origin sockets. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (state.is_always_single) { state.is_single = true; continue; } state.is_single = true; - if (input_socket->directly_linked_sockets().is_empty()) { + if (!input_socket->is_directly_linked()) { if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::Implicit) { state.is_single = false; } } else { - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - if (!field_state_by_socket_id[origin_socket->id()].is_single) { + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + if (!field_state_by_socket_id[origin_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -467,8 +470,8 @@ static void propagate_field_status_from_left_to_right( } /* Update field state of output sockets, also taking into account input sockets. */ - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -484,12 +487,12 @@ static void propagate_field_status_from_left_to_right( } case OutputSocketFieldType::PartiallyDependent: case OutputSocketFieldType::DependentField: { - for (const InputSocketRef *input_socket : + for (const bNodeSocket *input_socket : gather_input_socket_dependencies(field_dependency, *node)) { if (!input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[input_socket->id()].is_single) { + if (!field_state_by_socket_id[input_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -501,17 +504,18 @@ static void propagate_field_status_from_left_to_right( } } -static void determine_group_output_states(const NodeTreeRef &tree, +static void determine_group_output_states(const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const Span field_state_by_socket_id) { - for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + for (const bNode *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { /* Ignore inactive group output nodes. */ - if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + if (!(group_output_node->flag & NODE_DO_OUTPUT)) { continue; } /* Determine dependencies of all group outputs. */ - for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + for (const bNodeSocket *group_output_socket : + group_output_node->input_sockets().drop_back(1)) { OutputFieldDependency field_dependency = find_group_output_dependencies( *group_output_socket, field_state_by_socket_id); new_inferencing_interface.outputs[group_output_socket->index()] = std::move( @@ -521,7 +525,7 @@ static void determine_group_output_states(const NodeTreeRef &tree, } } -static void update_socket_shapes(const NodeTreeRef &tree, +static void update_socket_shapes(const bNodeTree &tree, const Span field_state_by_socket_id) { const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; @@ -541,32 +545,30 @@ static void update_socket_shapes(const NodeTreeRef &tree, return data_but_can_be_field_shape; }; - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_input_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast(socket)->display_shape = get_shape_for_state(state); } - for (const OutputSocketRef *socket : tree.output_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast(socket)->display_shape = get_shape_for_state(state); } } -static bool update_field_inferencing(const NodeTreeRef &tree) +static bool update_field_inferencing(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Create new inferencing interface for this node group. */ std::unique_ptr new_inferencing_interface = std::make_unique(); - new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), + new_inferencing_interface->inputs.resize(BLI_listbase_count(&tree.inputs), InputSocketFieldType::IsSupported); - new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), + new_inferencing_interface->outputs.resize(BLI_listbase_count(&tree.outputs), OutputFieldDependency::ForDataSource()); /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ - Array field_state_by_socket_id(tree.sockets().size()); + Array field_state_by_socket_id(tree.all_sockets().size()); propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); @@ -575,10 +577,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree) update_socket_shapes(tree, field_state_by_socket_id); /* Update the previous group interface. */ - const bool group_interface_changed = !btree.runtime->field_inferencing_interface || - *btree.runtime->field_inferencing_interface != + const bool group_interface_changed = !tree.runtime->field_inferencing_interface || + *tree.runtime->field_inferencing_interface != *new_inferencing_interface; - btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); + tree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); return group_interface_changed; } @@ -979,29 +981,22 @@ class NodeTreeMainUpdater { { TreeUpdateResult result; - /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology - * changes, which typically happens zero or one times during the entire update of the node - * tree. */ - std::unique_ptr tree_ref; - this->ensure_tree_ref(ntree, tree_ref); - - this->update_socket_link_and_use(*tree_ref); - this->update_individual_nodes(ntree, tree_ref); - this->update_internal_links(ntree, tree_ref); - this->update_generic_callback(ntree, tree_ref); + this->update_socket_link_and_use(ntree); + this->update_individual_nodes(ntree); + this->update_internal_links(ntree); + this->update_generic_callback(ntree); this->remove_unused_previews_when_necessary(ntree); - this->ensure_tree_ref(ntree, tree_ref); - this->propagate_runtime_flags(*tree_ref); + this->propagate_runtime_flags(ntree); if (ntree.type == NTREE_GEOMETRY) { - if (node_field_inferencing::update_field_inferencing(*tree_ref)) { + if (node_field_inferencing::update_field_inferencing(ntree)) { result.interface_changed = true; } } - result.output_changed = this->check_if_output_changed(*tree_ref); + result.output_changed = this->check_if_output_changed(ntree); - this->update_socket_link_and_use(*tree_ref); + this->update_socket_link_and_use(ntree); this->update_node_levels(ntree); this->update_link_validation(ntree); @@ -1021,86 +1016,69 @@ class NodeTreeMainUpdater { return result; } - void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr &tree_ref) - { - if (!tree_ref) { - tree_ref = std::make_unique(&ntree); - } - } - - void update_socket_link_and_use(const NodeTreeRef &tree) + void update_socket_link_and_use(bNodeTree &tree) { - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_input_sockets()) { if (socket->directly_linked_links().is_empty()) { - bsocket->link = nullptr; + socket->link = nullptr; } else { - bsocket->link = socket->directly_linked_links()[0]->blink(); + socket->link = socket->directly_linked_links()[0]; } } this->update_socket_used_tags(tree); } - void update_socket_used_tags(const NodeTreeRef &tree) + void update_socket_used_tags(bNodeTree &tree) { - for (const SocketRef *socket : tree.sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - bsocket->flag &= ~SOCK_IN_USE; - for (const LinkRef *link : socket->directly_linked_links()) { - if (!link->is_muted()) { - bsocket->flag |= SOCK_IN_USE; + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_sockets()) { + socket->flag &= ~SOCK_IN_USE; + for (const bNodeLink *link : socket->directly_linked_links()) { + if ((link->flag & NODE_LINK_MUTED) != 0) { + socket->flag |= SOCK_IN_USE; break; } } } } - void update_individual_nodes(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_individual_nodes(bNodeTree &ntree) { - /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after - * some update functions. */ - LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) { - this->ensure_tree_ref(ntree, tree_ref); - const NodeRef &node = *tree_ref->find_node(*bnode); - if (this->should_update_individual_node(node)) { - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - - /* This may set #ntree.runtime->changed_flag which is detected below. */ - this->update_individual_node(node); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update - * functions change the node. Typically zero or one nodes change after an update. */ - tree_ref.reset(); + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + if (this->should_update_individual_node(ntree, *node)) { + bNodeType &ntype = *node->typeinfo; + if (ntype.group_update_func) { + ntype.group_update_func(&ntree, node); + } + if (ntype.updatefunc) { + ntype.updatefunc(&ntree, node); } - ntree.runtime->changed_flag |= old_changed_flag; } } } - bool should_update_individual_node(const NodeRef &node) + bool should_update_individual_node(const bNodeTree &ntree, const bNode &node) { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } - if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + if (node.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { return true; } if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) { + ntree.ensure_topology_cache(); /* Node groups currently always rebuilt their sockets when they are updated. * So avoid calling the update method when no new link was added to it. */ - if (node.is_group_input_node()) { - if (node.outputs().last()->is_directly_linked()) { + if (node.type == NODE_GROUP_INPUT) { + if (node.output_sockets().last()->is_directly_linked()) { return true; } } - else if (node.is_group_output_node()) { - if (node.inputs().last()->is_directly_linked()) { + else if (node.type == NODE_GROUP_OUTPUT) { + if (node.input_sockets().last()->is_directly_linked()) { return true; } } @@ -1110,95 +1088,76 @@ class NodeTreeMainUpdater { } } if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) { - if (node.is_group_input_node() || node.is_group_output_node()) { + if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return true; } } return false; } - void update_individual_node(const NodeRef &node) - { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); - bNodeType &ntype = *bnode.typeinfo; - if (ntype.group_update_func) { - ntype.group_update_func(&ntree, &bnode); - } - if (ntype.updatefunc) { - ntype.updatefunc(&ntree, &bnode); - } - } - - void update_internal_links(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_internal_links(bNodeTree &ntree) { - bool any_internal_links_updated = false; - this->ensure_tree_ref(ntree, tree_ref); - for (const NodeRef *node : tree_ref->nodes()) { - if (!this->should_update_individual_node(*node)) { + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + ntree.ensure_topology_cache(); + for (bNode *node : ntree.all_nodes()) { + if (!this->should_update_individual_node(ntree, *node)) { continue; } /* Find all expected internal links. */ Vector> expected_internal_links; - for (const OutputSocketRef *output_socket : node->outputs()) { + for (const bNodeSocket *output_socket : node->output_sockets()) { if (!output_socket->is_available()) { continue; } if (!output_socket->is_directly_linked()) { continue; } - if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (output_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket); + const bNodeSocket *input_socket = this->find_internally_linked_input(output_socket); if (input_socket != nullptr) { - expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()}); + expected_internal_links.append( + {const_cast(input_socket), const_cast(output_socket)}); } } - /* rebuilt internal links if they have changed. */ - if (node->internal_links().size() != expected_internal_links.size()) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + /* Rebuilt internal links if they have changed. */ + if (node->internal_links_span().size() != expected_internal_links.size()) { + this->update_internal_links_in_node(ntree, *node, expected_internal_links); } else { for (auto &item : expected_internal_links) { const bNodeSocket *from_socket = item.first; const bNodeSocket *to_socket = item.second; bool found = false; - for (const InternalLinkRef *internal_link : node->internal_links()) { - if (from_socket == internal_link->from().bsocket() && - to_socket == internal_link->to().bsocket()) { + for (const bNodeLink *internal_link : node->internal_links_span()) { + if (from_socket == internal_link->fromsock && to_socket == internal_link->tosock) { found = true; } } if (!found) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + this->update_internal_links_in_node(ntree, *node, expected_internal_links); break; } } } } - - if (any_internal_links_updated) { - tree_ref.reset(); - } } - const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket) + const bNodeSocket *find_internally_linked_input(const bNodeSocket *output_socket) { - const InputSocketRef *selected_socket = nullptr; + const bNodeSocket *selected_socket = nullptr; int selected_priority = -1; bool selected_is_linked = false; - for (const InputSocketRef *input_socket : output_socket->node().inputs()) { + for (const bNodeSocket *input_socket : output_socket->owner_node().input_sockets()) { if (!input_socket->is_available()) { continue; } - if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (input_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo, - output_socket->bsocket()->typeinfo); + const int priority = get_internal_link_type_priority(input_socket->typeinfo, + output_socket->typeinfo); if (priority < 0) { continue; } @@ -1233,23 +1192,12 @@ class NodeTreeMainUpdater { BKE_ntree_update_tag_node_internal_link(&ntree, &node); } - void update_generic_callback(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_generic_callback(bNodeTree &ntree) { if (ntree.typeinfo->update == nullptr) { return; } - - /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */ - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - ntree.typeinfo->update(&ntree); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. */ - tree_ref.reset(); - } - ntree.runtime->changed_flag |= old_changed_flag; } void remove_unused_previews_when_necessary(bNodeTree &ntree) @@ -1264,25 +1212,26 @@ class NodeTreeMainUpdater { BKE_node_preview_remove_unused(&ntree); } - void propagate_runtime_flags(const NodeTreeRef &tree_ref) + void propagate_runtime_flags(const bNodeTree &ntree) { - bNodeTree &ntree = *tree_ref.btree(); + ntree.ensure_topology_cache(); + ntree.runtime->runtime_flag = 0; if (ntree.type != NTREE_SHADER) { return; } /* Check if a used node group has an animated image. */ - for (const NodeRef *group_node : tree_ref.nodes_by_type("ShaderNodeGroup")) { - const bNodeTree *group = reinterpret_cast(group_node->bnode()->id); + for (const bNode *group_node : ntree.nodes_by_type("ShaderNodeGroup")) { + const bNodeTree *group = reinterpret_cast(group_node->id); if (group != nullptr) { ntree.runtime->runtime_flag |= group->runtime->runtime_flag; } } /* Check if the tree itself has an animated image. */ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) { - for (const NodeRef *node : tree_ref.nodes_by_type(idname)) { - Image *image = reinterpret_cast(node->bnode()->id); + for (const bNode *node : ntree.nodes_by_type(idname)) { + Image *image = reinterpret_cast(node->id); if (image != nullptr && BKE_image_is_animated(image)) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; break; @@ -1294,7 +1243,7 @@ class NodeTreeMainUpdater { "ShaderNodeOutputLight", "ShaderNodeOutputWorld", "ShaderNodeOutputAOV"}) { - const Span nodes = tree_ref.nodes_by_type(idname); + const Span nodes = ntree.nodes_by_type(idname); if (!nodes.is_empty()) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT; break; @@ -1325,20 +1274,20 @@ class NodeTreeMainUpdater { } } - bool check_if_output_changed(const NodeTreeRef &tree) + bool check_if_output_changed(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Compute a hash that represents the node topology connected to the output. This always has to * be updated even if it is not used to detect changes right now. Otherwise * #btree.runtime.output_topology_hash will go out of date. */ - const Vector tree_output_sockets = this->find_output_sockets(tree); - const uint32_t old_topology_hash = btree.runtime->output_topology_hash; + const Vector tree_output_sockets = this->find_output_sockets(tree); + const uint32_t old_topology_hash = tree.runtime->output_topology_hash; const uint32_t new_topology_hash = this->get_combined_socket_topology_hash( tree, tree_output_sockets); - btree.runtime->output_topology_hash = new_topology_hash; + tree.runtime->output_topology_hash = new_topology_hash; - if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) { + if (const AnimData *adt = BKE_animdata_from_id(&tree.id)) { /* Drivers may copy values in the node tree around arbitrarily and may cause the output to * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can * be used without causing updates all the time currently. In the future we could try to @@ -1360,7 +1309,7 @@ class NodeTreeMainUpdater { } } - if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) { + if (tree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } @@ -1369,8 +1318,8 @@ class NodeTreeMainUpdater { } /* The topology hash can only be used when only topology-changing operations have been done. */ - if (btree.runtime->changed_flag == - (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { + if (tree.runtime->changed_flag == + (tree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { if (old_topology_hash == new_topology_hash) { return false; } @@ -1383,15 +1332,15 @@ class NodeTreeMainUpdater { return true; } - Vector find_output_sockets(const NodeTreeRef &tree) + Vector find_output_sockets(const bNodeTree &tree) { - Vector sockets; - for (const NodeRef *node : tree.nodes()) { + Vector sockets; + for (const bNode *node : tree.all_nodes()) { if (!this->is_output_node(*node)) { continue; } - for (const InputSocketRef *socket : node->inputs()) { - if (socket->idname() != "NodeSocketVirtual") { + for (const bNodeSocket *socket : node->input_sockets()) { + if (!STREQ(socket->idname, "NodeSocketVirtual")) { sockets.append(socket); } } @@ -1399,18 +1348,17 @@ class NodeTreeMainUpdater { return sockets; } - bool is_output_node(const NodeRef &node) const + bool is_output_node(const bNode &node) const { - const bNode &bnode = *node.bnode(); - if (bnode.typeinfo->nclass == NODE_CLASS_OUTPUT) { + if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) { return true; } - if (bnode.type == NODE_GROUP_OUTPUT) { + if (node.type == NODE_GROUP_OUTPUT) { return true; } /* Assume node groups without output sockets are outputs. */ - if (bnode.type == NODE_GROUP) { - const bNodeTree *node_group = reinterpret_cast(bnode.id); + if (node.type == NODE_GROUP) { + const bNodeTree *node_group = reinterpret_cast(node.id); if (node_group != nullptr && node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) { return true; @@ -1423,10 +1371,10 @@ class NodeTreeMainUpdater { * Computes a hash that changes when the node tree topology connected to an output node changes. * Adding reroutes does not have an effect on the hash. */ - uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree, - Span sockets) + uint32_t get_combined_socket_topology_hash(const bNodeTree &tree, + Span sockets) { - if (tree.has_link_cycles()) { + if (tree.has_link_cycle()) { /* Return dummy value when the link has any cycles. The algorithm below could be improved to * handle cycles more gracefully. */ return 0; @@ -1439,29 +1387,28 @@ class NodeTreeMainUpdater { return combined_hash; } - Array get_socket_topology_hashes(const NodeTreeRef &tree, - Span sockets) + Array get_socket_topology_hashes(const bNodeTree &tree, + Span sockets) { - BLI_assert(!tree.has_link_cycles()); - Array> hash_by_socket_id(tree.sockets().size()); - Stack sockets_to_check = sockets; + BLI_assert(!tree.has_link_cycle()); + Array> hash_by_socket_id(tree.all_sockets().size()); + Stack sockets_to_check = sockets; while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.peek(); - const NodeRef &node = in_out_socket.node(); + const bNodeSocket &socket = *sockets_to_check.peek(); + const bNode &node = socket.owner_node(); - if (hash_by_socket_id[in_out_socket.id()].has_value()) { + if (hash_by_socket_id[socket.index_in_tree()].has_value()) { sockets_to_check.pop(); /* Socket is handled already. */ continue; } - if (in_out_socket.is_input()) { + if (socket.is_input()) { /* For input sockets, first compute the hashes of all linked sockets. */ - const InputSocketRef &socket = in_out_socket.as_input(); bool all_origins_computed = true; - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - if (!hash_by_socket_id[origin_socket->id()].has_value()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + if (!hash_by_socket_id[origin_socket->index_in_tree()].has_value()) { sockets_to_check.push(origin_socket); all_origins_computed = false; } @@ -1471,22 +1418,21 @@ class NodeTreeMainUpdater { } /* When the hashes for the linked sockets are ready, combine them into a hash for the input * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, origin_socket_hash); } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } else { /* For output sockets, first compute the hashes of all available input sockets. */ - const OutputSocketRef &socket = in_out_socket.as_output(); bool all_available_inputs_computed = true; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - if (!hash_by_socket_id[input_socket->id()].has_value()) { + if (!hash_by_socket_id[input_socket->index_in_tree()].has_value()) { sockets_to_check.push(input_socket); all_available_inputs_computed = false; } @@ -1497,25 +1443,25 @@ class NodeTreeMainUpdater { } /* When all input socket hashes have been computed, combine them into a hash for the output * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()]; + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, input_socket_hash); } } /* The Image Texture node has a special case. The behavior of the color output changes * depending on whether the Alpha output is linked. */ - if (node.bnode()->type == SH_NODE_TEX_IMAGE && socket.index() == 0) { - BLI_assert(socket.name() == "Color"); - const OutputSocketRef &alpha_socket = node.output(1); - BLI_assert(alpha_socket.name() == "Alpha"); + if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { + BLI_assert(STREQ(socket.name, "Color")); + const bNodeSocket &alpha_socket = node.output_socket(1); + BLI_assert(STREQ(alpha_socket.name, "Alpha")); if (alpha_socket.is_directly_linked()) { socket_hash = noise::hash(socket_hash); } } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } } @@ -1523,7 +1469,7 @@ class NodeTreeMainUpdater { /* Create output array. */ Array hashes(sockets.size()); for (const int i : sockets.index_range()) { - hashes[i] = *hash_by_socket_id[sockets[i]->id()]; + hashes[i] = *hash_by_socket_id[sockets[i]->index_in_tree()]; } return hashes; } @@ -1532,37 +1478,34 @@ class NodeTreeMainUpdater { * Returns true when any of the provided sockets changed its values. A change is detected by * checking the #changed_flag on connected sockets and nodes. */ - bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree, - Span sockets) + bool check_if_socket_outputs_changed_based_on_flags(const bNodeTree &tree, + Span sockets) { /* Avoid visiting the same socket twice when multiple links point to the same socket. */ - Array pushed_by_socket_id(tree.sockets().size(), false); - Stack sockets_to_check = sockets; + Array pushed_by_socket_id(tree.all_sockets().size(), false); + Stack sockets_to_check = sockets; - for (const SocketRef *socket : sockets) { - pushed_by_socket_id[socket->id()] = true; + for (const bNodeSocket *socket : sockets) { + pushed_by_socket_id[socket->index_in_tree()] = true; } while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.pop(); - const NodeRef &node = in_out_socket.node(); - const bNode &bnode = *node.bnode(); - const bNodeSocket &bsocket = *in_out_socket.bsocket(); - if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bNodeSocket &socket = *sockets_to_check.pop(); + const bNode &node = socket.owner_node(); + if (socket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { return true; } - if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && - bnode.runtime->changed_flag == + if (node.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bool only_unused_internal_link_changed = !node.is_muted() && + node.runtime->changed_flag == NTREE_CHANGED_INTERNAL_LINK; if (!only_unused_internal_link_changed) { return true; } } - if (in_out_socket.is_input()) { - const InputSocketRef &socket = in_out_socket.as_input(); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - bool &pushed = pushed_by_socket_id[origin_socket->id()]; + if (socket.is_input()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(origin_socket); pushed = true; @@ -1570,10 +1513,9 @@ class NodeTreeMainUpdater { } } else { - const OutputSocketRef &socket = in_out_socket.as_output(); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - bool &pushed = pushed_by_socket_id[input_socket->id()]; + bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(input_socket); pushed = true; @@ -1582,11 +1524,11 @@ class NodeTreeMainUpdater { } /* The Normal node has a special case, because the value stored in the first output socket * is used as input in the node. */ - if (bnode.type == SH_NODE_NORMAL && socket.index() == 1) { - BLI_assert(socket.name() == "Dot"); - const OutputSocketRef &normal_output = node.output(0); - BLI_assert(normal_output.name() == "Normal"); - bool &pushed = pushed_by_socket_id[normal_output.id()]; + if (node.type == SH_NODE_NORMAL && socket.index() == 1) { + BLI_assert(STREQ(socket.name, "Dot")); + const bNodeSocket &normal_output = node.output_socket(0); + BLI_assert(STREQ(normal_output.name, "Normal")); + bool &pushed = pushed_by_socket_id[normal_output.index_in_tree()]; if (!pushed) { sockets_to_check.push(&normal_output); pushed = true; diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh index 4b6300c09aa..1fc5a797574 100644 --- a/source/blender/blenlib/BLI_multi_value_map.hh +++ b/source/blender/blenlib/BLI_multi_value_map.hh @@ -137,6 +137,11 @@ template class MultiValueMap { { return map_.values(); } + + void clear() + { + map_.clear(); + } }; } // namespace blender diff --git a/source/blender/compositor/realtime_compositor/COM_evaluator.hh b/source/blender/compositor/realtime_compositor/COM_evaluator.hh index fd6feb0948b..258a2a038c4 100644 --- a/source/blender/compositor/realtime_compositor/COM_evaluator.hh +++ b/source/blender/compositor/realtime_compositor/COM_evaluator.hh @@ -104,9 +104,6 @@ class Evaluator { Context &context_; /* A reference to the compositor node tree. */ bNodeTree &node_tree_; - /* The derived and reference node trees representing the compositor node tree. Those are - * initialized when the node tree is compiled and freed when the evaluator resets. */ - NodeTreeRefMap node_tree_reference_map_; std::unique_ptr derived_node_tree_; /* The compiled operations stream. This contains ordered pointers to the operations that were * compiled. This is initialized when the node tree is compiled and freed when the evaluator diff --git a/source/blender/compositor/realtime_compositor/COM_utilities.hh b/source/blender/compositor/realtime_compositor/COM_utilities.hh index 4bd61aab5cb..614384bd573 100644 --- a/source/blender/compositor/realtime_compositor/COM_utilities.hh +++ b/source/blender/compositor/realtime_compositor/COM_utilities.hh @@ -27,7 +27,7 @@ DSocket get_input_origin_socket(DInputSocket input); DOutputSocket get_output_linked_to_input(DInputSocket input); /* Get the result type that corresponds to the type of the given socket. */ -ResultType get_node_socket_result_type(const SocketRef *socket); +ResultType get_node_socket_result_type(const bNodeSocket *socket); /* Returns true if any of the nodes linked to the given output satisfies the given condition, and * false otherwise. */ @@ -46,7 +46,7 @@ bool is_shader_node(DNode node); bool is_node_supported(DNode node); /* Get the input descriptor of the given input socket. */ -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket); +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket); /* Dispatch the given compute shader in a 2D compute space such that the number of threads in both * dimensions is as small as possible but at least covers the entirety of threads_range assuming diff --git a/source/blender/compositor/realtime_compositor/intern/compile_state.cc b/source/blender/compositor/realtime_compositor/intern/compile_state.cc index 5b485224111..97c1e47e86e 100644 --- a/source/blender/compositor/realtime_compositor/intern/compile_state.cc +++ b/source/blender/compositor/realtime_compositor/intern/compile_state.cc @@ -46,7 +46,7 @@ Result &CompileState::get_result_from_output_socket(DOutputSocket output) * reference to the result from that operation using the output identifier. */ if (node_operations_.contains(output.node())) { NodeOperation *operation = node_operations_.lookup(output.node()); - return operation->get_result(output->identifier()); + return operation->get_result(output->identifier); } /* Otherwise, the output belongs to a node that was compiled into a shader operation, so @@ -113,17 +113,17 @@ Domain CompileState::compute_shader_node_domain(DNode node) /* Go over the inputs and find the domain of the non single value input with the highest domain * priority. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked, so skip * it. */ - const DOutputSocket output = get_output_linked_to_input(input); + const DOutputSocket output = get_output_linked_to_input(dinput); if (!output) { continue; } - const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_ref); + const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); /* If the output belongs to a node that is part of the shader compile unit, then the domain of * the input is the domain of the compile unit itself. */ diff --git a/source/blender/compositor/realtime_compositor/intern/evaluator.cc b/source/blender/compositor/realtime_compositor/intern/evaluator.cc index d358389f2e9..48457bec199 100644 --- a/source/blender/compositor/realtime_compositor/intern/evaluator.cc +++ b/source/blender/compositor/realtime_compositor/intern/evaluator.cc @@ -45,7 +45,6 @@ void Evaluator::reset() { operations_stream_.clear(); derived_node_tree_.reset(); - node_tree_reference_map_.clear(); is_compiled_ = false; } @@ -67,7 +66,7 @@ bool Evaluator::validate_node_tree() void Evaluator::compile_and_evaluate() { - derived_node_tree_ = std::make_unique(node_tree_, node_tree_reference_map_); + derived_node_tree_ = std::make_unique(node_tree_); if (!validate_node_tree()) { return; @@ -93,7 +92,7 @@ void Evaluator::compile_and_evaluate() void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state) { - NodeOperation *operation = node->typeinfo()->get_compositor_operation(context_, node); + NodeOperation *operation = node->typeinfo->get_compositor_operation(context_, node); compile_state.map_node_to_node_operation(node, operation); @@ -113,16 +112,16 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, NodeOperation *operation, CompileState &compile_state) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; - DSocket origin = get_input_origin_socket(input); + DSocket dorigin = get_input_origin_socket(dinput); /* The origin socket is an output, which means the input is linked. So map the input to the * result we get from the output. */ - if (origin->is_output()) { - Result &result = compile_state.get_result_from_output_socket(DOutputSocket(origin)); - operation->map_input_to_result(input->identifier(), &result); + if (dorigin->is_output()) { + Result &result = compile_state.get_result_from_output_socket(DOutputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &result); continue; } @@ -130,8 +129,8 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, * origin is the input socket itself or the input is connected to an unlinked input of a group * input node and the origin is the input of the group input node. So map the input to the * result of a newly created Input Single Value Operation. */ - auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(origin)); - operation->map_input_to_result(input->identifier(), &input_operation->get_result()); + auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &input_operation->get_result()); operations_stream_.append(std::unique_ptr(input_operation)); diff --git a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc index 0bdd40e3636..b3cc86b5f79 100644 --- a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc @@ -14,7 +14,7 @@ const StringRef InputSingleValueOperation::output_identifier_ = StringRef("Outpu InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSocket input_socket) : Operation(context), input_socket_(input_socket) { - const ResultType result_type = get_node_socket_result_type(input_socket_.socket_ref()); + const ResultType result_type = get_node_socket_result_type(input_socket_.bsocket()); Result result = Result(result_type, texture_pool()); /* The result of an input single value operation is guaranteed to have a single user. */ @@ -29,17 +29,19 @@ void InputSingleValueOperation::execute() Result &result = get_result(); result.allocate_single_value(); + const bNodeSocket *bsocket = input_socket_.bsocket(); + /* Set the value of the result to the default value of the input socket. */ switch (result.type()) { case ResultType::Float: - result.set_float_value(input_socket_->default_value()->value); + result.set_float_value(bsocket->default_value_typed()->value); break; case ResultType::Vector: result.set_vector_value( - float3(input_socket_->default_value()->value)); + float3(bsocket->default_value_typed()->value)); break; case ResultType::Color: - result.set_color_value(float4(input_socket_->default_value()->value)); + result.set_color_value(float4(bsocket->default_value_typed()->value)); break; } } diff --git a/source/blender/compositor/realtime_compositor/intern/node_operation.cc b/source/blender/compositor/realtime_compositor/intern/node_operation.cc index f02d0906447..1c20c967ddb 100644 --- a/source/blender/compositor/realtime_compositor/intern/node_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/node_operation.cc @@ -25,27 +25,27 @@ using namespace nodes::derived_node_tree_types; NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node) { - for (const OutputSocketRef *output : node->outputs()) { + for (const bNodeSocket *output : node->output_sockets()) { const ResultType result_type = get_node_socket_result_type(output); const Result result = Result(result_type, texture_pool()); - populate_result(output->identifier(), result); + populate_result(output->identifier, result); } - for (const InputSocketRef *input : node->inputs()) { + for (const bNodeSocket *input : node->input_sockets()) { const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); - declare_input_descriptor(input->identifier(), input_descriptor); + declare_input_descriptor(input->identifier, input_descriptor); } } void NodeOperation::compute_results_reference_counts(const Schedule &schedule) { - for (const OutputSocketRef *output_ref : node()->outputs()) { - const DOutputSocket output{node().context(), output_ref}; + for (const bNodeSocket *output : this->node()->output_sockets()) { + const DOutputSocket doutput{node().context(), output}; const int reference_count = number_of_inputs_linked_to_output_conditioned( - output, [&](DInputSocket input) { return schedule.contains(input.node()); }); + doutput, [&](DInputSocket input) { return schedule.contains(input.node()); }); - get_result(output->identifier()).set_initial_reference_count(reference_count); + get_result(doutput->identifier).set_initial_reference_count(reference_count); } } @@ -56,7 +56,7 @@ const DNode &NodeOperation::node() const const bNode &NodeOperation::bnode() const { - return *node_->bnode(); + return *node_; } bool NodeOperation::should_compute_output(StringRef identifier) diff --git a/source/blender/compositor/realtime_compositor/intern/scheduler.cc b/source/blender/compositor/realtime_compositor/intern/scheduler.cc index ce8b9330541..ac5cc55a73f 100644 --- a/source/blender/compositor/realtime_compositor/intern/scheduler.cc +++ b/source/blender/compositor/realtime_compositor/intern/scheduler.cc @@ -8,6 +8,8 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node_runtime.hh" + #include "COM_scheduler.hh" #include "COM_utilities.hh" @@ -21,22 +23,22 @@ using namespace nodes::derived_node_tree_types; * node will be returned. */ static DNode compute_output_node(DerivedNodeTree &tree) { - const NodeTreeRef &root_tree = tree.root_context().tree(); + const bNodeTree &root_tree = tree.root_context().btree(); - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeComposite")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } @@ -120,25 +122,25 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Go over the node dependencies connected to the inputs of the node and push them to the node * stack if they were not computed already. */ Set pushed_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The node dependency was already computed or pushed before, so skip it. */ - if (needed_buffers.contains(output.node()) || pushed_nodes.contains(output.node())) { + if (needed_buffers.contains(doutput.node()) || pushed_nodes.contains(doutput.node())) { continue; } /* The output node needs to be computed, push the node dependency to the node stack and * indicate that it was pushed. */ - node_stack.push(output.node()); - pushed_nodes.add_new(output.node()); + node_stack.push(doutput.node()); + pushed_nodes.add_new(doutput.node()); } /* If any of the node dependencies were pushed, that means that not all of them were computed @@ -154,26 +156,26 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) * buffers needed to compute the most demanding of the node dependencies. */ int number_of_input_buffers = 0; int buffers_needed_by_dependencies = 0; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs do not take a buffer, so skip those inputs. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* Since this input is linked, if the link is not between two shader nodes, it means that the * node takes a buffer through this input and so we increment the number of input buffers. */ - if (!is_shader_node(node) || !is_shader_node(output.node())) { + if (!is_shader_node(node) || !is_shader_node(doutput.node())) { number_of_input_buffers++; } /* If the number of buffers needed by the node dependency is more than the total number of * buffers needed by the dependencies, then update the latter to be the former. This is * computing the "d" in the aforementioned equation "max(n + m, d)". */ - const int buffers_needed_by_dependency = needed_buffers.lookup(output.node()); + const int buffers_needed_by_dependency = needed_buffers.lookup(doutput.node()); if (buffers_needed_by_dependency > buffers_needed_by_dependencies) { buffers_needed_by_dependencies = buffers_needed_by_dependency; } @@ -181,17 +183,18 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Compute the number of buffers that will be computed/output by this node. */ int number_of_output_buffers = 0; - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* The output is not linked, it outputs no buffer. */ - if (output->logically_linked_sockets().is_empty()) { + if (!output->is_logically_linked()) { continue; } /* If any of the links is not between two shader nodes, it means that the node outputs * a buffer through this output and so we increment the number of output buffers. */ - if (!is_output_linked_to_node_conditioned(output, is_shader_node) || !is_shader_node(node)) { + if (!is_output_linked_to_node_conditioned(doutput, is_shader_node) || + !is_shader_node(node)) { number_of_output_buffers++; } } @@ -255,24 +258,24 @@ Schedule compute_schedule(DerivedNodeTree &tree) * want the node with the highest number of needed buffers to be schedule first, but since * those are pushed to the traversal stack, we need to push them in reverse order. */ Vector sorted_dependency_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node, so skip it. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The dependency node was added before, so skip it. The number of dependency nodes is very * small, typically less than 3, so a linear search is okay. */ - if (sorted_dependency_nodes.contains(output.node())) { + if (sorted_dependency_nodes.contains(doutput.node())) { continue; } /* The dependency node was already schedule, so skip it. */ - if (schedule.contains(output.node())) { + if (schedule.contains(doutput.node())) { continue; } @@ -280,7 +283,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) * typically less than 3, so insertion sort is okay. */ int insertion_position = 0; for (int i = 0; i < sorted_dependency_nodes.size(); i++) { - if (needed_buffers.lookup(output.node()) > + if (needed_buffers.lookup(doutput.node()) > needed_buffers.lookup(sorted_dependency_nodes[i])) { insertion_position++; } @@ -288,7 +291,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) break; } } - sorted_dependency_nodes.insert(insertion_position, output.node()); + sorted_dependency_nodes.insert(insertion_position, doutput.node()); } /* Push the sorted dependency nodes to the node stack in order. */ diff --git a/source/blender/compositor/realtime_compositor/intern/shader_node.cc b/source/blender/compositor/realtime_compositor/intern/shader_node.cc index f23485cee96..9310de3cbf4 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_node.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_node.cc @@ -59,7 +59,7 @@ const DNode &ShaderNode::node() const bNode &ShaderNode::bnode() const { - return *node_->bnode(); + return const_cast(*node_); } static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) @@ -77,17 +77,17 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) } } -static void gpu_stack_vector_from_socket(float *vector, const SocketRef *socket) +static void gpu_stack_vector_from_socket(float *vector, const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: - vector[0] = socket->default_value()->value; + vector[0] = socket->default_value_typed()->value; return; case SOCK_VECTOR: - copy_v3_v3(vector, socket->default_value()->value); + copy_v3_v3(vector, socket->default_value_typed()->value); return; case SOCK_RGBA: - copy_v4_v4(vector, socket->default_value()->value); + copy_v4_v4(vector, socket->default_value_typed()->value); return; default: BLI_assert_unreachable(); @@ -101,8 +101,8 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) /* This will be initialized later by the GPU material compiler or the compile method. */ stack.link = nullptr; - stack.sockettype = socket->bsocket()->type; - stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->bsocket()->type); + stack.sockettype = socket->type; + stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->type); if (socket->is_input()) { const DInputSocket input(socket); @@ -117,10 +117,10 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) * unlinked input or an unlinked input of a group input node that the socket is linked to, * otherwise, get the value from the socket itself. */ if (origin->is_input()) { - gpu_stack_vector_from_socket(stack.vec, origin.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, origin.bsocket()); } else { - gpu_stack_vector_from_socket(stack.vec, socket.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, socket.bsocket()); } } else { @@ -132,10 +132,11 @@ void ShaderNode::populate_inputs() { /* Reserve a stack for each input in addition to an extra stack at the end to mark the end of the * array, as this is what the GPU module functions expect. */ - inputs_.resize(node_->inputs().size() + 1); + const int num_input_sockets = node_->input_sockets().size(); + inputs_.resize(num_input_sockets + 1); inputs_.last().end = true; - for (int i = 0; i < node_->inputs().size(); i++) { + for (int i = 0; i < num_input_sockets; i++) { populate_gpu_node_stack(node_.input(i), inputs_[i]); } } @@ -144,10 +145,11 @@ void ShaderNode::populate_outputs() { /* Reserve a stack for each output in addition to an extra stack at the end to mark the end of * the array, as this is what the GPU module functions expect. */ - outputs_.resize(node_->outputs().size() + 1); + const int num_output_sockets = node_->output_sockets().size(); + outputs_.resize(num_output_sockets + 1); outputs_.last().end = true; - for (int i = 0; i < node_->outputs().size(); i++) { + for (int i = 0; i < num_output_sockets; i++) { populate_gpu_node_stack(node_.output(i), outputs_[i]); } } diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index 5749d8c5f2e..8e52baf63ec 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -128,7 +128,7 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) { ShaderOperation *operation = static_cast(thunk); for (DNode node : operation->compile_unit_) { - ShaderNode *shader_node = node->typeinfo()->get_compositor_shader_node(node); + ShaderNode *shader_node = node->typeinfo->get_compositor_shader_node(node); operation->shader_nodes_.add_new(node, std::unique_ptr(shader_node)); operation->link_node_inputs(node, material); @@ -141,27 +141,27 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) void ShaderOperation::link_node_inputs(DNode node, GPUMaterial *material) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs are linked by the node compile method, so skip this here. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* If the origin node is part of the shader operation, then the link is internal to the GPU * material graph and is linked appropriately. */ - if (compile_unit_.contains(output.node())) { - link_node_input_internal(input, output); + if (compile_unit_.contains(doutput.node())) { + link_node_input_internal(dinput, doutput); continue; } /* Otherwise, the origin node is not part of the shader operation, then the link is external to * the GPU material graph and an input to the shader operation must be declared and linked to * the node input. */ - link_node_input_external(input, output, material); + link_node_input_external(dinput, doutput, material); } } @@ -169,10 +169,10 @@ void ShaderOperation::link_node_input_internal(DInputSocket input_socket, DOutputSocket output_socket) { ShaderNode &output_node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier()); + GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier); ShaderNode &input_node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier()); + GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier); input_stack.link = output_stack.link; } @@ -183,7 +183,7 @@ void ShaderOperation::link_node_input_external(DInputSocket input_socket, { ShaderNode &node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &stack = node.get_input(input_socket->identifier()); + GPUNodeStack &stack = node.get_input(input_socket->identifier); /* An input was already declared for that same output socket, so no need to declare it again. */ if (!output_to_material_attribute_map_.contains(output_socket)) { @@ -219,8 +219,8 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, /* Declare the input descriptor for this input and prefer to declare its type to be the same as * the type of the output socket because doing type conversion in the shader is much cheaper. */ - InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.socket_ref()); - input_descriptor.type = get_node_socket_result_type(output_socket.socket_ref()); + InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.bsocket()); + input_descriptor.type = get_node_socket_result_type(output_socket.bsocket()); declare_input_descriptor(input_identifier, input_descriptor); /* Add a new GPU attribute representing an input to the GPU material. Instead of using the @@ -242,16 +242,16 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *material) { - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* If any of the nodes linked to the output are not part of the shader operation, then an * output result needs to be populated for it. */ const bool need_to_populate_result = is_output_linked_to_node_conditioned( - output, [&](DNode node) { return !compile_unit_.contains(node); }); + doutput, [&](DNode node) { return !compile_unit_.contains(node); }); if (need_to_populate_result) { - populate_operation_result(output, material); + populate_operation_result(doutput, material); } } } @@ -276,7 +276,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU const unsigned int output_id = output_sockets_to_output_identifiers_map_.size(); std::string output_identifier = "output" + std::to_string(output_id); - const ResultType result_type = get_node_socket_result_type(output_socket.socket_ref()); + const ResultType result_type = get_node_socket_result_type(output_socket.bsocket()); const Result result = Result(result_type, texture_pool()); populate_result(output_identifier, result); @@ -284,7 +284,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU output_sockets_to_output_identifiers_map_.add_new(output_socket, output_identifier); ShaderNode &node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeLink *output_link = node.get_output(output_socket->identifier()).link; + GPUNodeLink *output_link = node.get_output(output_socket->identifier).link; /* Link the output node stack to an output storer storing in the appropriate result. The result * is identified by its index in the operation and the index is encoded as a float to be passed diff --git a/source/blender/compositor/realtime_compositor/intern/utilities.cc b/source/blender/compositor/realtime_compositor/intern/utilities.cc index 169ba70e9eb..2e1baec98a8 100644 --- a/source/blender/compositor/realtime_compositor/intern/utilities.cc +++ b/source/blender/compositor/realtime_compositor/intern/utilities.cc @@ -26,7 +26,7 @@ using TargetSocketPathInfo = DOutputSocket::TargetSocketPathInfo; DSocket get_input_origin_socket(DInputSocket input) { /* The input is unlinked. Return the socket itself. */ - if (input->logically_linked_sockets().is_empty()) { + if (!input->is_logically_linked()) { return input; } @@ -52,9 +52,9 @@ DOutputSocket get_output_linked_to_input(DInputSocket input) return DOutputSocket(origin); } -ResultType get_node_socket_result_type(const SocketRef *socket) +ResultType get_node_socket_result_type(const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: return ResultType::Float; case SOCK_VECTOR: @@ -95,21 +95,20 @@ int number_of_inputs_linked_to_output_conditioned(DOutputSocket output, bool is_shader_node(DNode node) { - return node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_shader_node; } bool is_node_supported(DNode node) { - return node->typeinfo()->get_compositor_operation || - node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_operation || node->typeinfo->get_compositor_shader_node; } -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket) +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket) { using namespace nodes; InputDescriptor input_descriptor; input_descriptor.type = get_node_socket_result_type(socket); - const NodeDeclaration *node_declaration = socket->node().declaration(); + const NodeDeclaration *node_declaration = socket->owner_node().declaration(); /* Not every node have a declaration, in which case, we assume the default values for the rest of * the properties. */ if (!node_declaration) { diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index d911e53be7f..3a8bb56bc5e 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -18,6 +18,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_screen.h" @@ -46,14 +47,11 @@ #include "BLT_translation.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" #include "node_intern.hh" /* own include */ -using namespace blender::nodes::node_tree_ref_types; - struct bNodeListItem { struct bNodeListItem *next, *prev; struct bNode *node; @@ -434,18 +432,18 @@ namespace viewer_linking { * \{ */ /* Depending on the node tree type, different socket types are supported by viewer nodes. */ -static bool socket_can_be_viewed(const OutputSocketRef &socket) +static bool socket_can_be_viewed(const bNodeSocket &socket) { - if (nodeSocketIsHidden(socket.bsocket())) { + if (nodeSocketIsHidden(&socket)) { return false; } - if (socket.idname() == "NodeSocketVirtual") { + if (STREQ(socket.idname, "NodeSocketVirtual")) { return false; } - if (socket.tree().btree()->type != NTREE_GEOMETRY) { + if (socket.owner_tree().type != NTREE_GEOMETRY) { return true; } - return ELEM(socket.typeinfo()->type, + return ELEM(socket.typeinfo->type, SOCK_GEOMETRY, SOCK_FLOAT, SOCK_VECTOR, @@ -502,15 +500,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return nullptr; } -static bool is_viewer_node(const NodeRef &node) +static bool is_viewer_node(const bNode &node) { - return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); + return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); } -static Vector find_viewer_nodes(const NodeTreeRef &tree) +static Vector find_viewer_nodes(const bNodeTree &tree) { - Vector viewer_nodes; - for (const NodeRef *node : tree.nodes()) { + Vector viewer_nodes; + for (const bNode *node : tree.all_nodes()) { if (is_viewer_node(*node)) { viewer_nodes.append(node); } @@ -518,20 +516,20 @@ static Vector find_viewer_nodes(const NodeTreeRef &tree) return viewer_nodes; } -static bool is_viewer_socket_in_viewer(const InputSocketRef &socket) +static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) { - const NodeRef &node = socket.node(); + const bNode &node = socket.owner_node(); BLI_assert(is_viewer_node(node)); - if (node.typeinfo()->type == GEO_NODE_VIEWER) { + if (node.typeinfo->type == GEO_NODE_VIEWER) { return true; } return socket.index() == 0; } -static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node) +static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node) { - for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) { - if (&target_socket->node() != &viewer_node) { + for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) { + if (&target_socket->owner_node() != &viewer_node) { continue; } if (!target_socket->is_available()) { @@ -561,39 +559,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode & } } -static const NodeRef *get_existing_viewer(const NodeTreeRef &tree) +static const bNode *get_existing_viewer(const bNodeTree &tree) { - Vector viewer_nodes = find_viewer_nodes(tree); + Vector viewer_nodes = find_viewer_nodes(tree); /* Check if there is already an active viewer node that should be used. */ - for (const NodeRef *viewer_node : viewer_nodes) { - if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *viewer_node : viewer_nodes) { + if (viewer_node->flag & NODE_DO_OUTPUT) { return viewer_node; } } /* If no active but non-active viewers exist, make one active. */ if (!viewer_nodes.is_empty()) { - viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT; + const_cast(viewer_nodes[0])->flag |= NODE_DO_OUTPUT; return viewer_nodes[0]; } return nullptr; } -static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node, - const NodeRef &node_to_view) +static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node, + const bNode &node_to_view) { /* Check if any of the output sockets is selected, which is the case when the user just clicked * on the socket. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { - if (output_socket->bsocket()->flag & SELECT) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { + if (output_socket->flag & SELECT) { return output_socket; } } - const OutputSocketRef *last_socket_linked_to_viewer = nullptr; + const bNodeSocket *last_socket_linked_to_viewer = nullptr; if (active_viewer_node != nullptr) { - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (!socket_can_be_viewed(*output_socket)) { continue; } @@ -604,7 +602,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } if (last_socket_linked_to_viewer == nullptr) { /* If no output is connected to a viewer, use the first output that can be viewed. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (socket_can_be_viewed(*output_socket)) { return output_socket; } @@ -612,10 +610,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } else { /* Pick the next socket to be linked to the viewer. */ - const int tot_outputs = node_to_view.outputs().size(); + const int tot_outputs = node_to_view.output_sockets().size(); for (const int offset : IndexRange(1, tot_outputs - 1)) { const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs; - const OutputSocketRef &output_socket = node_to_view.output(index); + const bNodeSocket &output_socket = node_to_view.output_socket(index); if (!socket_can_be_viewed(output_socket)) { continue; } @@ -682,20 +680,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) { SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree *btree = snode.edittree; + btree->ensure_topology_cache(); - const NodeTreeRef tree{btree}; - const NodeRef &node_to_view = *tree.find_node(bnode_to_view); - const NodeRef *active_viewer_node = get_existing_viewer(tree); - - const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node, - node_to_view); - if (socket_to_view == nullptr) { + bNode *active_viewer_bnode = const_cast(get_existing_viewer(*btree)); + bNodeSocket *bsocket_to_view = const_cast( + find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view)); + if (bsocket_to_view == nullptr) { return OPERATOR_FINISHED; } - - bNodeSocket &bsocket_to_view = *socket_to_view->bsocket(); - bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr; - return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); + return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view); } /** \} */ @@ -2048,7 +2041,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const nodes::NodeDeclaration *node_decl = node.runtime->declaration; + const nodes::NodeDeclaration *node_decl = node.declaration(); if (node_decl != nullptr) { Span socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : node_decl->outputs(); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index dafbca0f995..0b228ef8c37 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -6,6 +6,7 @@ #include "BKE_image.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BLI_map.hh" #include "BLI_math_vector.h" @@ -15,8 +16,6 @@ #include "DNA_material_types.h" #include "DNA_node_types.h" -#include "NOD_node_tree_ref.hh" - #include "obj_export_mesh.hh" #include "obj_export_mtl.hh" @@ -84,25 +83,25 @@ static void copy_property_from_node(const eNodeSocketDatatype property_type, * Collect all the source sockets linked to the destination socket in a destination node. */ static void linked_sockets_to_dest_id(const bNode *dest_node, - const nodes::NodeTreeRef &node_tree, + const bNodeTree &node_tree, const char *dest_socket_id, - Vector &r_linked_sockets) + Vector &r_linked_sockets) { r_linked_sockets.clear(); if (!dest_node) { return; } - Span object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); - Span dest_inputs = object_dest_nodes.first()->inputs(); - const nodes::InputSocketRef *dest_socket = nullptr; - for (const nodes::InputSocketRef *curr_socket : dest_inputs) { - if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id)) { + Span object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); + Span dest_inputs = object_dest_nodes.first()->input_sockets(); + const bNodeSocket *dest_socket = nullptr; + for (const bNodeSocket *curr_socket : dest_inputs) { + if (STREQ(curr_socket->identifier, dest_socket_id)) { dest_socket = curr_socket; break; } } if (dest_socket) { - Span linked_sockets = dest_socket->directly_linked_sockets(); + Span linked_sockets = dest_socket->directly_linked_sockets(); r_linked_sockets.resize(linked_sockets.size()); r_linked_sockets = linked_sockets; } @@ -111,13 +110,12 @@ static void linked_sockets_to_dest_id(const bNode *dest_node, /** * From a list of sockets, get the parent node which is of the given node type. */ -static const bNode *get_node_of_type(Span sockets_list, - const int node_type) +static const bNode *get_node_of_type(Span sockets_list, const int node_type) { - for (const nodes::SocketRef *socket : sockets_list) { - const bNode *parent_node = socket->bnode(); - if (parent_node->typeinfo->type == node_type) { - return parent_node; + for (const bNodeSocket *socket : sockets_list) { + const bNode &parent_node = socket->owner_node(); + if (parent_node.typeinfo->type == node_type) { + return &parent_node; } } return nullptr; @@ -153,16 +151,16 @@ static const char *get_image_filepath(const bNode *tex_node) * We only want one that feeds directly into a Material Output node * (that is the behavior of the legacy Python exporter). */ -static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) +static const bNode *find_bsdf_node(const bNodeTree *nodetree) { if (!nodetree) { return nullptr; } - for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { - const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0]; - for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) { - const nodes::NodeRef &in_node = out_sock->node(); - if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) { + for (const bNode *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { + const bNodeSocket &node_input_socket0 = node->input_socket(0); + for (const bNodeSocket *out_sock : node_input_socket0.directly_linked_sockets()) { + const bNode &in_node = out_sock->owner_node(); + if (in_node.typeinfo->type == SH_NODE_BSDF_PRINCIPLED) { return &in_node; } } @@ -173,55 +171,50 @@ static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) /** * Store properties found either in bNode or material into r_mtl_mat. */ -static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, +static void store_bsdf_properties(const bNode *bsdf_node, const Material *material, MTLMaterial &r_mtl_mat) { - const bNode *bnode = nullptr; - if (bsdf_node) { - bnode = bsdf_node->bnode(); - } - /* If p-BSDF is not present, fallback to #Object.Material. */ float roughness = material->roughness; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Roughness", {&roughness, 1}); } /* Empirical approximation. Importer should use the inverse of this method. */ float spec_exponent = (1.0f - roughness); spec_exponent *= spec_exponent * 1000.0f; float specular = material->spec; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular", {&specular, 1}); } float metallic = material->metallic; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Metallic", {&metallic, 1}); } float refraction_index = 1.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "IOR", {&refraction_index, 1}); } float dissolved = material->a; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&dissolved, 1}); } const bool transparent = dissolved != 1.0f; float3 diffuse_col = {material->r, material->g, material->b}; - if (bnode) { - copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_RGBA, bsdf_node, "Base Color", {diffuse_col, 3}); } float3 emission_col{0.0f}; float emission_strength = 0.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); - copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission", {emission_col, 3}); } mul_v3_fl(emission_col, emission_strength); @@ -265,8 +258,8 @@ static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, /** * Store image texture options and file-paths in `r_mtl_mat`. */ -static void store_image_textures(const nodes::NodeRef *bsdf_node, - const nodes::NodeTreeRef *node_tree, +static void store_image_textures(const bNode *bsdf_node, + const bNodeTree *node_tree, const Material *material, MTLMaterial &r_mtl_mat) { @@ -274,7 +267,6 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, /* No nodetree, no images, or no Principled BSDF node. */ return; } - const bNode *bnode = bsdf_node->bnode(); /* Normal Map Texture has two extra tasks of: * - finding a Normal Map node before finding a texture node. @@ -283,12 +275,12 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { MTLTexMap &value = r_mtl_mat.texture_maps[key]; - Vector linked_sockets; + Vector linked_sockets; const bNode *normal_map_node{nullptr}; if (key == (int)MTLTexMapType::bump) { /* Find sockets linked to destination "Normal" socket in P-BSDF node. */ - linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets); + linked_sockets_to_dest_id(bsdf_node, *node_tree, "Normal", linked_sockets); /* Among the linked sockets, find Normal Map shader node. */ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP); @@ -299,13 +291,15 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, /* Skip emission map if emission strength is zero. */ if (key == (int)MTLTexMapType::Ke) { float emission_strength = 0.0f; - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node( + SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); if (emission_strength == 0.0f) { continue; } } /* Find sockets linked to the destination socket of interest, in P-BSDF node. */ - linked_sockets_to_dest_id(bnode, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); + linked_sockets_to_dest_id( + bsdf_node, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); } /* Among the linked sockets, find Image Texture shader node. */ @@ -341,14 +335,14 @@ MTLMaterial mtlmaterial_for_material(const Material *material) MTLMaterial mtlmat; mtlmat.name = std::string(material->id.name + 2); std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_'); - const nodes::NodeTreeRef *nodetree = nullptr; - if (material->nodetree) { - nodetree = new nodes::NodeTreeRef(material->nodetree); + const bNodeTree *nodetree = material->nodetree; + if (nodetree != nullptr) { + nodetree->ensure_topology_cache(); } - const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree); + + const bNode *bsdf_node = find_bsdf_node(nodetree); store_bsdf_properties(bsdf_node, material, mtlmat); store_image_textures(bsdf_node, nodetree, material, mtlmat); - delete nodetree; return mtlmat; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4ae06d0a5e4..92cc35908f2 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -12,8 +12,33 @@ #include "DNA_scene_types.h" /* for #ImageFormatData */ #include "DNA_vec_types.h" /* for #rctf */ +/** Workaround to forward-declare C++ type in C header. */ #ifdef __cplusplus -extern "C" { +namespace blender { +template class Span; +class StringRef; +class StringRefNull; +} // namespace blender +namespace blender::nodes { +class NodeDeclaration; +class SocketDeclaration; +} // namespace blender::nodes +namespace blender::bke { +class bNodeTreeRuntime; +class bNodeRuntime; +class bNodeSocketRuntime; +} // namespace blender::bke +using NodeDeclarationHandle = blender::nodes::NodeDeclaration; +using SocketDeclarationHandle = blender::nodes::SocketDeclaration; +using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; +using bNodeRuntimeHandle = blender::bke::bNodeRuntime; +using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; +#else +typedef struct NodeDeclarationHandle NodeDeclarationHandle; +typedef struct SocketDeclarationHandle SocketDeclarationHandle; +typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; +typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; +typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; #endif struct AnimData; @@ -30,6 +55,7 @@ struct bNodeLink; struct bNodePreview; struct bNodeTreeExec; struct bNodeType; +struct bNode; struct uiBlock; #define NODE_MAXSTR 64 @@ -65,30 +91,6 @@ typedef struct bNodeStack { #define NS_CR_FIT 4 #define NS_CR_STRETCH 5 -/** Workaround to forward-declare C++ type in C header. */ -#ifdef __cplusplus -namespace blender::nodes { -class NodeDeclaration; -class SocketDeclaration; -} // namespace blender::nodes -namespace blender::bke { -class bNodeTreeRuntime; -class bNodeRuntime; -class bNodeSocketRuntime; -} // namespace blender::bke -using NodeDeclarationHandle = blender::nodes::NodeDeclaration; -using SocketDeclarationHandle = blender::nodes::SocketDeclaration; -using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; -using bNodeRuntimeHandle = blender::bke::bNodeRuntime; -using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; -#else -typedef struct NodeDeclarationHandle NodeDeclarationHandle; -typedef struct SocketDeclarationHandle SocketDeclarationHandle; -typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; -typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; -typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; -#endif - typedef struct bNodeSocket { struct bNodeSocket *next, *prev; @@ -181,6 +183,49 @@ typedef struct bNodeSocket { bNodeStack ns DNA_DEPRECATED; bNodeSocketRuntimeHandle *runtime; + +#ifdef __cplusplus + bool is_available() const; + bool is_multi_input() const; + bool is_input() const; + bool is_output() const; + + /** Utility to access the value of the socket. */ + template const T *default_value_typed() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** Zero based index for every input and output socket. */ + int index() const; + /** Socket index in the entire node tree. Inputs and outputs share the same index space. */ + int index_in_tree() const; + /** Node this socket belongs to. */ + bNode &owner_node(); + const bNode &owner_node() const; + /** Node tree this socket belongs to. */ + const bNodeTree &owner_tree() const; + + /** Links which are incident to this socket. */ + blender::Span directly_linked_links(); + blender::Span directly_linked_links() const; + /** Sockets which are connected to this socket with a link. */ + blender::Span directly_linked_sockets() const; + bool is_directly_linked() const; + /** + * Sockets which are connected to this socket when reroutes and muted nodes are taken into + * account. + */ + blender::Span logically_linked_sockets() const; + bool is_logically_linked() const; + + /** + * For output sockets, this is the corresponding input socket the value of which should be + * forwarded when the node is muted. + */ + const bNodeSocket *internal_link_input() const; + +#endif } bNodeSocket; /** #bNodeSocket.type & #bNodeSocketType.type */ @@ -333,6 +378,38 @@ typedef struct bNode { char iter_flag; bNodeRuntimeHandle *runtime; + +#ifdef __cplusplus + blender::StringRefNull label_or_name() const; + bool is_muted() const; + bool is_reroute() const; + bool is_frame() const; + bool is_group() const; + bool is_group_input() const; + bool is_group_output() const; + const blender::nodes::NodeDeclaration *declaration() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all input sockets of the node (including unavailable sockets). */ + blender::Span input_sockets(); + blender::Span input_sockets() const; + /** A span containing all output sockets of the node (including unavailable sockets). */ + blender::Span output_sockets(); + blender::Span output_sockets() const; + /** Utility to get an input socket by its index. */ + bNodeSocket &input_socket(int index); + const bNodeSocket &input_socket(int index) const; + /** Utility to get an output socket by its index. */ + bNodeSocket &output_socket(int index); + const bNodeSocket &output_socket(int index) const; + /** A span containing all internal links when the node is muted. */ + blender::Span internal_links_span() const; + /** Lookup socket of this node by its identifier. */ + const bNodeSocket &input_by_identifier(blender::StringRef identifier) const; + const bNodeSocket &output_by_identifier(blender::StringRef identifier) const; +#endif } bNode; /* node->flag */ @@ -422,6 +499,11 @@ typedef struct bNodeLink { int flag; int multi_input_socket_index; + +#ifdef __cplusplus + bool is_muted() const; +#endif + } bNodeLink; /* link->flag */ @@ -535,6 +617,50 @@ typedef struct bNodeTree { struct PreviewImage *preview; bNodeTreeRuntimeHandle *runtime; + +#ifdef __cplusplus + /** + * Update a run-time cache for the node tree based on it's current state. This makes many methods + * available which allow efficient lookup for topology information (like neighboring sockets). + */ + void ensure_topology_cache() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all nodes in the node tree. */ + blender::Span all_nodes(); + blender::Span all_nodes() const; + /** A span containing all input sockets in the node tree. */ + blender::Span all_input_sockets(); + blender::Span all_input_sockets() const; + /** A span containing all output sockets in the node tree. */ + blender::Span all_output_sockets(); + blender::Span all_output_sockets() const; + /** A span containing all sockets in the node tree. */ + blender::Span all_sockets(); + blender::Span all_sockets() const; + /** Efficient lookup of all nodes with a specific type. */ + blender::Span nodes_by_type(blender::StringRefNull type_idname); + blender::Span nodes_by_type(blender::StringRefNull type_idname) const; + /** + * Cached toposort of all nodes. If there are cycles, the returned array is not actually a + * toposort. However, if a connected component does not contain a cycle, this component is sorted + * correctly. Use #has_link_cycle to check for cycles. + */ + blender::Span toposort_left_to_right() const; + blender::Span toposort_right_to_left() const; + /** True when there are any cycles in the node tree. */ + bool has_link_cycle() const; + /** + * True when there are nodes or sockets in the node tree that don't use a known type. This can + * happen when nodes don't exist in the current Blender version that existed in the version where + * this node tree was saved. + */ + bool has_undefined_nodes_or_sockets() const; + /** Get the active group output node. */ + const bNode *group_output_node() const; +#endif } bNodeTree; /** #NodeTree.type, index */ @@ -2210,7 +2336,3 @@ typedef enum NodeCombSepColorMode { NODE_COMBSEP_COLOR_HSV = 1, NODE_COMBSEP_COLOR_HSL = 2, } NodeCombSepColorMode; - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 806513009be..36abe970b31 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -506,6 +506,54 @@ static short *add_struct(int namecode) return sp; } +/* Copied from `BLI_str_startswith` string.c + * to avoid complicating the compilation process of makesdna. */ +static bool str_startswith(const char *__restrict str, const char *__restrict start) +{ + for (; *str && *start; str++, start++) { + if (*str != *start) { + return false; + } + } + + return (*start == '\0'); +} + +/** + * Check if `str` is a preprocessor string that starts with `start`. + * The `start` doesn't need the `#` prefix. + * `ifdef VALUE` will match `#ifdef VALUE` as well as `# ifdef VALUE`. + */ +static bool match_preproc_prefix(const char *__restrict str, const char *__restrict start) +{ + if (*str != '#') { + return false; + } + str++; + while (*str == ' ') { + str++; + } + return str_startswith(str, start); +} + +/** + * \return The point in `str` that starts with `start` or NULL when not found. + * + */ +static char *match_preproc_strstr(char *__restrict str, const char *__restrict start) +{ + while ((str = strchr(str, '#'))) { + str++; + while (*str == ' ') { + str++; + } + if (str_startswith(str, start)) { + return str; + } + } + return NULL; +} + static int preprocess_include(char *maindata, const int maindata_len) { /* NOTE: len + 1, last character is a dummy to prevent @@ -533,6 +581,10 @@ static int preprocess_include(char *maindata, const int maindata_len) cp++; } + /* No need for leading '#' character. */ + const char *cpp_block_start = "ifdef __cplusplus"; + const char *cpp_block_end = "endif"; + /* data from temp copy to maindata, remove comments and double spaces */ cp = temp; char *md = maindata; @@ -577,6 +629,18 @@ static int preprocess_include(char *maindata, const int maindata_len) skip_until_closing_brace = false; } } + else if (match_preproc_prefix(cp, cpp_block_start)) { + char *end_ptr = match_preproc_strstr(cp, cpp_block_end); + + if (end_ptr == NULL) { + fprintf(stderr, "Error: '%s' block must end with '%s'\n", cpp_block_start, cpp_block_end); + } + else { + const int skip_offset = end_ptr - cp + strlen(cpp_block_end); + a -= skip_offset; + cp += skip_offset; + } + } else { md[0] = cp[0]; md++; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 56967e62d8a..2908fbf5597 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -756,18 +756,18 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) } static void initialize_group_input(NodesModifierData &nmd, - const OutputSocketRef &socket, + const bNodeSocket &socket, void *r_value) { - const bNodeSocketType &socket_type = *socket.typeinfo(); - const bNodeSocket &bsocket = *socket.bsocket(); + const bNodeSocketType &socket_type = *socket.typeinfo; + const bNodeSocket &bsocket = socket; const eNodeSocketDatatype socket_data_type = static_cast(bsocket.type); if (nmd.settings.properties == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; } const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties, - socket.identifier().c_str()); + socket.identifier); if (property == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; @@ -777,15 +777,15 @@ static void initialize_group_input(NodesModifierData &nmd, return; } - if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) { + if (!input_has_attribute_toggle(*nmd.node_group, socket.runtime->index_in_node)) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; } const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str()); + nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str()); const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str()); + nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str()); if (property_use_attribute == nullptr || property_attribute_name == nullptr) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; @@ -867,11 +867,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe const DTreeContext *context = &tree.root_context(); for (SpreadsheetContextNode *node_context : nested_group_contexts) { - const NodeTreeRef &tree_ref = context->tree(); - const NodeRef *found_node = nullptr; - for (const NodeRef *node_ref : tree_ref.nodes()) { - if (node_ref->name() == node_context->node_name) { - found_node = node_ref; + const bNodeTree &btree = context->btree(); + const bNode *found_node = nullptr; + for (const bNode *bnode : btree.all_nodes()) { + if (STREQ(bnode->name, node_context->node_name)) { + found_node = bnode; break; } } @@ -884,11 +884,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe } } - const NodeTreeRef &tree_ref = context->tree(); - for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) { - if (node_ref->name() == last_context->node_name) { - const DNode viewer_node{context, node_ref}; - for (const InputSocketRef *input_socket : node_ref->inputs()) { + const bNodeTree &btree = context->btree(); + for (const bNode *bnode : btree.nodes_by_type("GeometryNodeViewer")) { + if (STREQ(bnode->name, last_context->node_name)) { + const DNode viewer_node{context, bnode}; + for (const bNodeSocket *input_socket : bnode->input_sockets()) { if (input_socket->is_available() && input_socket->is_logically_linked()) { r_sockets_to_preview.add(DSocket{context, input_socket}); } @@ -937,15 +937,15 @@ struct OutputAttributeToStore { * can be evaluated together. */ static MultiValueMap find_output_attributes_to_store( - const NodesModifierData &nmd, const NodeRef &output_node, Span output_values) + const NodesModifierData &nmd, const bNode &output_node, Span output_values) { MultiValueMap outputs_by_domain; - for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { - if (!socket_type_has_attribute_toggle(*socket->bsocket())) { + for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) { + if (!socket_type_has_attribute_toggle(*socket)) { continue; } - const std::string prop_name = socket->identifier() + attribute_name_suffix; + const std::string prop_name = socket->identifier + attribute_name_suffix; const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str()); if (prop == nullptr) { continue; @@ -965,7 +965,7 @@ static MultiValueMap find_output_attributes_to const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink( - &nmd.node_group->outputs, socket->index()); + &nmd.node_group->outputs, index); const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain; OutputAttributeInfo output_info; output_info.field = std::move(field); @@ -1064,7 +1064,7 @@ static void store_computed_output_attributes( static void store_output_attributes(GeometrySet &geometry, const NodesModifierData &nmd, - const NodeRef &output_node, + const bNode &output_node, Span output_values) { /* All new attribute values have to be computed before the geometry is actually changed. This is @@ -1080,8 +1080,8 @@ static void store_output_attributes(GeometrySet &geometry, * Evaluate a node group to compute the output geometry. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span group_input_nodes, - const NodeRef &output_node, + Span group_input_nodes, + const bNode &output_node, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1093,18 +1093,19 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Map group_inputs; const DTreeContext *root_context = &tree.root_context(); - for (const NodeRef *group_input_node : group_input_nodes) { - Span group_input_sockets = group_input_node->outputs().drop_back(1); + for (const bNode *group_input_node : group_input_nodes) { + Span group_input_sockets = group_input_node->output_sockets().drop_back( + 1); if (group_input_sockets.is_empty()) { continue; } - Span remaining_input_sockets = group_input_sockets; + Span remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const OutputSocketRef *first_input_socket = group_input_sockets[0]; - if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { + const bNodeSocket *first_input_socket = group_input_sockets[0]; + if (first_input_socket->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = allocator.construct(input_geometry_set).release(); group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); @@ -1112,8 +1113,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } /* Initialize remaining group inputs. */ - for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; + for (const bNodeSocket *socket : remaining_input_sockets) { + const CPPType &cpp_type = *socket->typeinfo->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); @@ -1121,7 +1122,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } Vector group_outputs; - for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) { + for (const bNodeSocket *socket_ref : output_node.input_sockets().drop_back(1)) { group_outputs.append({root_context, socket_ref}); } @@ -1226,8 +1227,8 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - NodeTreeRefMap tree_refs; - DerivedNodeTree tree{*nmd->node_group, tree_refs}; + const bNodeTree &root_tree_ref = *nmd->node_group; + DerivedNodeTree tree{root_tree_ref}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); @@ -1235,25 +1236,24 @@ static void modifyGeometry(ModifierData *md, return; } - const NodeTreeRef &root_tree_ref = tree.root_context().tree(); - Span input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); - Span output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); + Span input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (output_nodes.size() != 1) { BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node"); geometry_set.clear(); return; } - const NodeRef &output_node = *output_nodes[0]; - Span group_outputs = output_node.inputs().drop_back(1); + const bNode &output_node = *output_nodes[0]; + Span group_outputs = output_node.input_sockets().drop_back(1); if (group_outputs.is_empty()) { BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket"); geometry_set.clear(); return; } - const InputSocketRef *first_output_socket = group_outputs[0]; - if (first_output_socket->idname() != "NodeSocketGeometry") { + const bNodeSocket *first_output_socket = group_outputs[0]; + if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) { BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry"); geometry_set.clear(); return; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 5cf4e21ea68..dd7c87ca499 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -2,6 +2,7 @@ #include "MOD_nodes_evaluator.hh" +#include "BKE_node.h" #include "BKE_type_conversions.hh" #include "NOD_geometry_exec.hh" @@ -319,9 +320,9 @@ class LockedNode : NonCopyable, NonMovable { } }; -static const CPPType *get_socket_cpp_type(const SocketRef &socket) +static const CPPType *get_socket_cpp_type(const bNodeSocket &socket) { - const bNodeSocketType *typeinfo = socket.typeinfo(); + const bNodeSocketType *typeinfo = socket.typeinfo; if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } @@ -338,24 +339,24 @@ static const CPPType *get_socket_cpp_type(const SocketRef &socket) static const CPPType *get_socket_cpp_type(const DSocket socket) { - return get_socket_cpp_type(*socket.socket_ref()); + return get_socket_cpp_type(*socket); } /** * \note This is not supposed to be a long term solution. Eventually we want that nodes can * specify more complex defaults (other than just single values) in their socket declarations. */ -static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) +static bool get_implicit_socket_input(const bNodeSocket &socket, void *r_value) { - const NodeRef &node = socket.node(); - const nodes::NodeDeclaration *node_declaration = node.declaration(); + const bNode &node = socket.owner_node(); + const nodes::NodeDeclaration *node_declaration = node.runtime->declaration; if (node_declaration == nullptr) { return false; } const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()]; if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) { - const bNode &bnode = *socket.bnode(); - if (socket.typeinfo()->type == SOCK_VECTOR) { + const bNode &bnode = socket.owner_node(); + if (socket.typeinfo->type == SOCK_VECTOR) { if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) { StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode == GEO_NODE_CURVE_HANDLE_LEFT ? @@ -372,7 +373,7 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) new (r_value) ValueOrField(bke::AttributeFieldInput::Create("position")); return true; } - if (socket.typeinfo()->type == SOCK_INT) { + if (socket.typeinfo->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { new (r_value) ValueOrField(Field(std::make_shared())); @@ -385,19 +386,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) return false; } -static void get_socket_value(const SocketRef &socket, void *r_value) +static void get_socket_value(const bNodeSocket &socket, void *r_value) { if (get_implicit_socket_input(socket, r_value)) { return; } - const bNodeSocketType *typeinfo = socket.typeinfo(); - typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value); + const bNodeSocketType *typeinfo = socket.typeinfo; + typeinfo->get_geometry_nodes_cpp_value(socket, r_value); } static bool node_supports_laziness(const DNode node) { - return node->typeinfo()->geometry_node_execute_supports_laziness; + return node->typeinfo->geometry_node_execute_supports_laziness; } struct NodeTaskRunState { @@ -516,9 +517,9 @@ class GeometryNodesEvaluator { node_states_.add_new({node, &node_state}); /* Push all linked origins on the stack. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; - input.foreach_origin_socket( + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; + dinput.foreach_origin_socket( [&](const DSocket origin) { nodes_to_check.push(origin.node()); }); } } @@ -546,11 +547,11 @@ class GeometryNodesEvaluator { void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator) { /* Construct arrays of the correct size. */ - node_state.inputs = allocator.construct_array(node->inputs().size()); - node_state.outputs = allocator.construct_array(node->outputs().size()); + node_state.inputs = allocator.construct_array(node->input_sockets().size()); + node_state.outputs = allocator.construct_array(node->output_sockets().size()); /* Initialize input states. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; const DInputSocket socket = node.input(i); if (!socket->is_available()) { @@ -567,7 +568,7 @@ class GeometryNodesEvaluator { continue; } /* Construct the correct struct that can hold the input(s). */ - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { input_state.value.multi = allocator.construct().release(); MultiInputValue &multi_value = *input_state.value.multi; /* Count how many values should be added until the socket is complete. */ @@ -583,7 +584,7 @@ class GeometryNodesEvaluator { } } /* Initialize output states. */ - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket = node.output(i); if (!socket->is_available()) { @@ -629,13 +630,13 @@ class GeometryNodesEvaluator { void destruct_node_state(const DNode node, NodeState &node_state) { /* Need to destruct stuff manually, because it's allocated by a custom allocator. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; if (input_state.type == nullptr) { continue; } - const InputSocketRef &socket_ref = node->input(i); - if (socket_ref.is_multi_input_socket()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (bsocket.is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *value : multi_value.values) { if (value != nullptr) { @@ -756,7 +757,7 @@ class GeometryNodesEvaluator { { /* These nodes are sometimes scheduled. We could also check for them in other places, but * it's the easiest to do it here. */ - if (node->is_group_input_node() || node->is_group_output_node()) { + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return; } @@ -837,7 +838,7 @@ class GeometryNodesEvaluator { /* If there are no remaining outputs, all the inputs can be destructed and/or can become * unused. This can also trigger a chain reaction where nodes to the left become finished * too. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { const DInputSocket socket = locked_node.node.input(i); InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.usage == ValueUsage::Maybe) { @@ -883,7 +884,7 @@ class GeometryNodesEvaluator { return; } /* Nodes that don't support laziness require all inputs. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.type == nullptr) { /* Ignore unavailable/non-data sockets. */ @@ -915,7 +916,7 @@ class GeometryNodesEvaluator { continue; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; /* Checks if all the linked sockets have been provided already. */ if (multi_value.all_values_available()) { @@ -949,7 +950,7 @@ class GeometryNodesEvaluator { */ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; if (node_state.has_been_executed) { if (!node_supports_laziness(node)) { @@ -978,7 +979,7 @@ class GeometryNodesEvaluator { void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { using Clock = std::chrono::steady_clock; - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; NodeParamsProvider params_provider{*this, node, node_state, run_state}; GeoNodeExecParams params{params_provider}; @@ -1002,12 +1003,12 @@ class GeometryNodesEvaluator { bool any_input_is_field = false; Vector input_values; Vector input_types; - for (const int i : node->inputs().index_range()) { - const InputSocketRef &socket_ref = node->input(i); - if (!socket_ref.is_available()) { + for (const int i : node->input_sockets().index_range()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (!bsocket.is_available()) { continue; } - BLI_assert(!socket_ref.is_multi_input_socket()); + BLI_assert(!bsocket.is_multi_input()); InputState &input_state = node_state.inputs[i]; BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; @@ -1055,15 +1056,15 @@ class GeometryNodesEvaluator { } int output_index = 0; - for (const int i : node->outputs().index_range()) { - const OutputSocketRef &socket_ref = node->output(i); - if (!socket_ref.is_available()) { + for (const int i : node->output_sockets().index_range()) { + const bNodeSocket &bsocket = node->output_socket(i); + if (!bsocket.is_available()) { continue; } OutputState &output_state = node_state.outputs[i]; - const DOutputSocket socket{node.context(), &socket_ref}; + const DOutputSocket socket{node.context(), &bsocket}; const ValueOrFieldCPPType *cpp_type = static_cast( - get_socket_cpp_type(socket_ref)); + get_socket_cpp_type(bsocket)); GField new_field{operation, output_index}; void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); cpp_type->construct_from_field(buffer, std::move(new_field)); @@ -1091,7 +1092,7 @@ class GeometryNodesEvaluator { } Vector output_buffers; - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { const DOutputSocket socket = node.output(i); if (!socket->is_available()) { output_buffers.append({}); @@ -1128,7 +1129,7 @@ class GeometryNodesEvaluator { void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { LinearAllocator<> &allocator = local_allocators_.local(); - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (!socket->is_available()) { continue; } @@ -1182,8 +1183,8 @@ class GeometryNodesEvaluator { const bool supports_laziness = node_supports_laziness(locked_node.node); /* Iterating over sockets instead of the states directly, because that makes it easier to * figure out which socket is missing when one of the asserts is hit. */ - for (const OutputSocketRef *socket_ref : locked_node.node->outputs()) { - OutputState &output_state = locked_node.node_state.outputs[socket_ref->index()]; + for (const bNodeSocket *bsocket : locked_node.node->output_sockets()) { + OutputState &output_state = locked_node.node_state.outputs[bsocket->index()]; if (supports_laziness) { /* Expected that at least all required sockets have been computed. If more outputs become * required later, the node will be executed again. */ @@ -1208,7 +1209,7 @@ class GeometryNodesEvaluator { { for (const DInputSocket &socket : params_.output_sockets) { BLI_assert(socket->is_available()); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); const DNode node = socket.node(); NodeState &node_state = this->get_node_state(node); @@ -1255,7 +1256,7 @@ class GeometryNodesEvaluator { /* Count how many values still have to be added to this input until it is "complete". */ int missing_values = 0; - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; missing_values = multi_value.missing_values(); } @@ -1402,52 +1403,51 @@ class GeometryNodesEvaluator { Vector forward_original_value_sockets; log_original_value_sockets.append(from_socket); - from_socket.foreach_target_socket( - [&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) { - if (!this->should_forward_to_socket(to_socket)) { - return; - } - BLI_assert(to_socket == path_info.sockets.last()); - GMutablePointer current_value = value_to_forward; - for (const DSocket &next_socket : path_info.sockets) { - const DNode next_node = next_socket.node(); - const bool is_last_socket = to_socket == next_socket; - const bool do_conversion_if_necessary = is_last_socket || - next_node->is_group_output_node() || - (next_node->is_group_node() && - !next_node->is_muted()); - if (do_conversion_if_necessary) { - const CPPType &next_type = *get_socket_cpp_type(next_socket); - if (*current_value.type() != next_type) { - void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); - this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); - if (current_value.get() != value_to_forward.get()) { - current_value.destruct(); - } - current_value = {next_type, buffer}; - } - } - if (current_value.get() == value_to_forward.get()) { - /* Log the original value at the current socket. */ - log_original_value_sockets.append(next_socket); - } - else { - /* Multi-input sockets are logged when all values are available. */ - if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) { - /* Log the converted value at the socket. */ - this->log_socket_value({next_socket}, current_value); - } + from_socket.foreach_target_socket([&](const DInputSocket to_socket, + const DOutputSocket::TargetSocketPathInfo &path_info) { + if (!this->should_forward_to_socket(to_socket)) { + return; + } + BLI_assert(to_socket == path_info.sockets.last()); + GMutablePointer current_value = value_to_forward; + for (const DSocket &next_socket : path_info.sockets) { + const DNode next_node = next_socket.node(); + const bool is_last_socket = to_socket == next_socket; + const bool do_conversion_if_necessary = is_last_socket || + next_node->type == NODE_GROUP_OUTPUT || + (next_node->is_group() && !next_node->is_muted()); + if (do_conversion_if_necessary) { + const CPPType &next_type = *get_socket_cpp_type(next_socket); + if (*current_value.type() != next_type) { + void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); + this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); + if (current_value.get() != value_to_forward.get()) { + current_value.destruct(); } + current_value = {next_type, buffer}; } - if (current_value.get() == value_to_forward.get()) { - /* The value has not been converted, so forward the original value. */ - forward_original_value_sockets.append(to_socket); - } - else { - /* The value has been converted. */ - this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + if (current_value.get() == value_to_forward.get()) { + /* Log the original value at the current socket. */ + log_original_value_sockets.append(next_socket); + } + else { + /* Multi-input sockets are logged when all values are available. */ + if (!(next_socket->is_input() && next_socket->is_multi_input())) { + /* Log the converted value at the socket. */ + this->log_socket_value({next_socket}, current_value); } - }); + } + } + if (current_value.get() == value_to_forward.get()) { + /* The value has not been converted, so forward the original value. */ + forward_original_value_sockets.append(to_socket); + } + else { + /* The value has been converted. */ + this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + }); this->log_socket_value(log_original_value_sockets, value_to_forward); this->forward_to_sockets_with_same_type( allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state); @@ -1512,7 +1512,7 @@ class GeometryNodesEvaluator { InputState &input_state = node_state.inputs[socket->index()]; this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) { - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { /* Add a new value to the multi-input. */ MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin, value.get()); @@ -1555,7 +1555,7 @@ class GeometryNodesEvaluator { UNUSED_VARS(locked_node); GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type); - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin_socket, value.get()); if (multi_value.all_values_available()) { @@ -1580,7 +1580,7 @@ class GeometryNodesEvaluator { void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket) { InputState &input_state = locked_node.node_state.inputs[socket->index()]; - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *&value : multi_value.values) { if (value != nullptr) { @@ -1605,7 +1605,7 @@ class GeometryNodesEvaluator { const CPPType &type = *get_socket_cpp_type(socket); void *buffer = allocator.allocate(type.size(), type.alignment()); - get_socket_value(*socket.socket_ref(), buffer); + get_socket_value(*socket.bsocket(), buffer); if (type == required_type) { return {type, buffer}; @@ -1762,7 +1762,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const return false; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; return multi_value.all_values_available(); } @@ -1783,7 +1783,7 @@ GMutablePointer NodeParamsProvider::extract_input(StringRef identifier) { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1797,7 +1797,7 @@ Vector NodeParamsProvider::extract_multi_input(StringRef identi { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(socket->is_multi_input_socket()); + BLI_assert(socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1816,7 +1816,7 @@ GPointer NodeParamsProvider::get_input(StringRef identifier) const { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1901,7 +1901,7 @@ void NodeParamsProvider::set_default_remaining_outputs() { LinearAllocator<> &allocator = evaluator_.local_allocators_.local(); - for (const int i : this->dnode->outputs().index_range()) { + for (const int i : this->dnode->output_sockets().index_range()) { OutputState &output_state = node_state_.outputs[i]; if (output_state.has_been_computed) { continue; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index ae31fd7ff5f..ff8bd27f8d7 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -49,7 +49,6 @@ set(SRC intern/node_multi_function.cc intern/node_socket.cc intern/node_socket_declarations.cc - intern/node_tree_ref.cc intern/node_util.c intern/socket_search_link.cc @@ -63,7 +62,6 @@ set(SRC NOD_math_functions.hh NOD_multi_function.hh NOD_node_declaration.hh - NOD_node_tree_ref.hh NOD_shader.h NOD_socket.h NOD_socket_declarations.hh diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index b0799d90dcd..b3775e729da 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -5,16 +5,17 @@ /** \file * \ingroup nodes * - * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more - * convenient and safe. It does so by pairing nodes and sockets with a context. The context - * contains information about the current "instance" of the node or socket. A node might be - * "instanced" multiple times when it is in a node group that is used multiple times. + * DerivedNodeTree makes working with (nested) node groups more convenient and safe. It does so by + * pairing nodes and sockets with a context. The context contains information about the current + * "instance" of the node or socket. A node might be "instanced" multiple times when it is in a + * node group that is used multiple times. */ #include "BLI_function_ref.hh" +#include "BLI_linear_allocator.hh" #include "BLI_vector_set.hh" -#include "NOD_node_tree_ref.hh" +#include "BKE_node_runtime.hh" namespace blender::nodes { @@ -40,20 +41,20 @@ class DTreeContext { DTreeContext *parent_context_; /* Null when this context is for the root node group. Otherwise it points to the group node in * the parent node group that contains this context. */ - const NodeRef *parent_node_; + const bNode *parent_node_; /* The current node tree. */ - const NodeTreeRef *tree_; + const bNodeTree *btree_; /* All the children contexts of this context. */ - Map children_; + Map children_; DerivedNodeTree *derived_tree_; friend DerivedNodeTree; public: - const NodeTreeRef &tree() const; + const bNodeTree &btree() const; const DTreeContext *parent_context() const; - const NodeRef *parent_node() const; - const DTreeContext *child_context(const NodeRef &node) const; + const bNode *parent_node() const; + const DTreeContext *child_context(const bNode &node) const; const DerivedNodeTree &derived_tree() const; bool is_root() const; }; @@ -65,15 +66,16 @@ class DTreeContext { class DNode { private: const DTreeContext *context_ = nullptr; - const NodeRef *node_ref_ = nullptr; + const bNode *bnode_ = nullptr; public: DNode() = default; - DNode(const DTreeContext *context, const NodeRef *node); + DNode(const DTreeContext *context, const bNode *node); const DTreeContext *context() const; - const NodeRef *node_ref() const; - const NodeRef *operator->() const; + const bNode *bnode() const; + const bNode *operator->() const; + const bNode &operator*() const; friend bool operator==(const DNode &a, const DNode &b); friend bool operator!=(const DNode &a, const DNode &b); @@ -98,17 +100,18 @@ class DNode { class DSocket { protected: const DTreeContext *context_ = nullptr; - const SocketRef *socket_ref_ = nullptr; + const bNodeSocket *bsocket_ = nullptr; public: DSocket() = default; - DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DTreeContext *context, const bNodeSocket *socket); DSocket(const DInputSocket &input_socket); DSocket(const DOutputSocket &output_socket); const DTreeContext *context() const; - const SocketRef *socket_ref() const; - const SocketRef *operator->() const; + const bNodeSocket *bsocket() const; + const bNodeSocket *operator->() const; + const bNodeSocket &operator*() const; friend bool operator==(const DSocket &a, const DSocket &b); friend bool operator!=(const DSocket &a, const DSocket &b); @@ -123,12 +126,9 @@ class DSocket { class DInputSocket : public DSocket { public: DInputSocket() = default; - DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + DInputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DInputSocket(const DSocket &base_socket); - const InputSocketRef *socket_ref() const; - const InputSocketRef *operator->() const; - DOutputSocket get_corresponding_group_node_output() const; Vector get_corresponding_group_input_sockets() const; @@ -144,12 +144,9 @@ class DInputSocket : public DSocket { class DOutputSocket : public DSocket { public: DOutputSocket() = default; - DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + DOutputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DOutputSocket(const DSocket &base_socket); - const OutputSocketRef *socket_ref() const; - const OutputSocketRef *operator->() const; - DInputSocket get_corresponding_group_node_input() const; DInputSocket get_active_corresponding_group_output_socket() const; @@ -177,7 +174,7 @@ class DerivedNodeTree { private: LinearAllocator<> allocator_; DTreeContext *root_context_; - VectorSet used_node_tree_refs_; + VectorSet used_btrees_; public: /** @@ -186,11 +183,11 @@ class DerivedNodeTree { * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the * derived node tree. */ - DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(const bNodeTree &btree); ~DerivedNodeTree(); const DTreeContext &root_context() const; - Span used_node_tree_refs() const; + Span used_btrees() const; /** * \return True when there is a link cycle. Unavailable sockets are ignored. @@ -205,9 +202,8 @@ class DerivedNodeTree { private: DTreeContext &construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs); + const bNode *parent_node, + const bNodeTree &btree); void destruct_context_recursively(DTreeContext *context); void foreach_node_in_context_recursive(const DTreeContext &context, @@ -215,7 +211,6 @@ class DerivedNodeTree { }; namespace derived_node_tree_types { -using namespace node_tree_ref_types; using nodes::DerivedNodeTree; using nodes::DInputSocket; using nodes::DNode; @@ -228,9 +223,9 @@ using nodes::DTreeContext; /** \name #DTreeContext Inline Methods * \{ */ -inline const NodeTreeRef &DTreeContext::tree() const +inline const bNodeTree &DTreeContext::btree() const { - return *tree_; + return *btree_; } inline const DTreeContext *DTreeContext::parent_context() const @@ -238,12 +233,12 @@ inline const DTreeContext *DTreeContext::parent_context() const return parent_context_; } -inline const NodeRef *DTreeContext::parent_node() const +inline const bNode *DTreeContext::parent_node() const { return parent_node_; } -inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const +inline const DTreeContext *DTreeContext::child_context(const bNode &node) const { return children_.lookup_default(&node, nullptr); } @@ -264,10 +259,10 @@ inline bool DTreeContext::is_root() const /** \name #DNode Inline Methods * \{ */ -inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) - : context_(context), node_ref_(node_ref) +inline DNode::DNode(const DTreeContext *context, const bNode *bnode) + : context_(context), bnode_(bnode) { - BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); + BLI_assert(bnode == nullptr || bnode->runtime->owner_tree == &context->btree()); } inline const DTreeContext *DNode::context() const @@ -275,14 +270,14 @@ inline const DTreeContext *DNode::context() const return context_; } -inline const NodeRef *DNode::node_ref() const +inline const bNode *DNode::bnode() const { - return node_ref_; + return bnode_; } inline bool operator==(const DNode &a, const DNode &b) { - return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; + return a.context_ == b.context_ && a.bnode_ == b.bnode_; } inline bool operator!=(const DNode &a, const DNode &b) @@ -292,37 +287,43 @@ inline bool operator!=(const DNode &a, const DNode &b) inline DNode::operator bool() const { - return node_ref_ != nullptr; + return bnode_ != nullptr; +} + +inline const bNode *DNode::operator->() const +{ + return bnode_; } -inline const NodeRef *DNode::operator->() const +inline const bNode &DNode::operator*() const { - return node_ref_; + BLI_assert(bnode_ != nullptr); + return *bnode_; } inline uint64_t DNode::hash() const { - return get_default_hash_2(context_, node_ref_); + return get_default_hash_2(context_, bnode_); } inline DInputSocket DNode::input(int index) const { - return {context_, &node_ref_->input(index)}; + return {context_, &bnode_->input_socket(index)}; } inline DOutputSocket DNode::output(int index) const { - return {context_, &node_ref_->output(index)}; + return {context_, &bnode_->output_socket(index)}; } inline DInputSocket DNode::input_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->input_by_identifier(identifier)}; + return {context_, &bnode_->input_by_identifier(identifier)}; } inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->output_by_identifier(identifier)}; + return {context_, &bnode_->output_by_identifier(identifier)}; } /** \} */ @@ -331,19 +332,20 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const /** \name #DSocket Inline Methods * \{ */ -inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) - : context_(context), socket_ref_(socket_ref) +inline DSocket::DSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : context_(context), bsocket_(bsocket) { - BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); + BLI_assert(bsocket == nullptr || + bsocket->runtime->owner_node->runtime->owner_tree == &context->btree()); } inline DSocket::DSocket(const DInputSocket &input_socket) - : DSocket(input_socket.context_, input_socket.socket_ref_) + : DSocket(input_socket.context_, input_socket.bsocket_) { } inline DSocket::DSocket(const DOutputSocket &output_socket) - : DSocket(output_socket.context_, output_socket.socket_ref_) + : DSocket(output_socket.context_, output_socket.bsocket_) { } @@ -352,14 +354,14 @@ inline const DTreeContext *DSocket::context() const return context_; } -inline const SocketRef *DSocket::socket_ref() const +inline const bNodeSocket *DSocket::bsocket() const { - return socket_ref_; + return bsocket_; } inline bool operator==(const DSocket &a, const DSocket &b) { - return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; + return a.context_ == b.context_ && a.bsocket_ == b.bsocket_; } inline bool operator!=(const DSocket &a, const DSocket &b) @@ -369,23 +371,29 @@ inline bool operator!=(const DSocket &a, const DSocket &b) inline DSocket::operator bool() const { - return socket_ref_ != nullptr; + return bsocket_ != nullptr; } -inline const SocketRef *DSocket::operator->() const +inline const bNodeSocket *DSocket::operator->() const { - return socket_ref_; + return bsocket_; +} + +inline const bNodeSocket &DSocket::operator*() const +{ + BLI_assert(bsocket_ != nullptr); + return *bsocket_; } inline uint64_t DSocket::hash() const { - return get_default_hash_2(context_, socket_ref_); + return get_default_hash_2(context_, bsocket_); } inline DNode DSocket::node() const { - BLI_assert(socket_ref_ != nullptr); - return {context_, &socket_ref_->node()}; + BLI_assert(bsocket_ != nullptr); + return {context_, bsocket_->runtime->owner_node}; } /** \} */ @@ -394,8 +402,8 @@ inline DNode DSocket::node() const /** \name #DInputSocket Inline Methods * \{ */ -inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DInputSocket::DInputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -404,24 +412,14 @@ inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_soc BLI_assert(base_socket->is_input()); } -inline const InputSocketRef *DInputSocket::socket_ref() const -{ - return (const InputSocketRef *)socket_ref_; -} - -inline const InputSocketRef *DInputSocket::operator->() const -{ - return (const InputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name #DOutputSocket Inline Methods * \{ */ -inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -430,16 +428,6 @@ inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_s BLI_assert(base_socket->is_output()); } -inline const OutputSocketRef *DOutputSocket::socket_ref() const -{ - return (const OutputSocketRef *)socket_ref_; -} - -inline const OutputSocketRef *DOutputSocket::operator->() const -{ - return (const OutputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -451,9 +439,9 @@ inline const DTreeContext &DerivedNodeTree::root_context() const return *root_context_; } -inline Span DerivedNodeTree::used_node_tree_refs() const +inline Span DerivedNodeTree::used_btrees() const { - return used_node_tree_refs_; + return used_btrees_; } /** \} */ diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index a7f5fbf1926..b5ffd3a317c 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -283,7 +283,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *provider_->dnode->bnode(); + return *provider_->dnode; } const Object *self_object() const diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh index b6d51578b1c..21a94d9192b 100644 --- a/source/blender/nodes/NOD_multi_function.hh +++ b/source/blender/nodes/NOD_multi_function.hh @@ -19,15 +19,15 @@ class NodeMultiFunctions; */ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { private: - bNode &node_; - bNodeTree &tree_; + const bNode &node_; + const bNodeTree &tree_; std::shared_ptr owned_built_fn_; const MultiFunction *built_fn_ = nullptr; friend NodeMultiFunctions; public: - NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree); + NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree); /** * Assign a multi-function for the current node. The input and output parameters of the function @@ -42,8 +42,8 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { */ template void construct_and_set_matching_fn(Args &&...args); - bNode &node(); - bNodeTree &tree(); + const bNode &node(); + const bNodeTree &tree(); }; /** @@ -69,17 +69,17 @@ class NodeMultiFunctions { /** \name #NodeMultiFunctionBuilder Inline Methods * \{ */ -inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree) +inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree) : node_(node), tree_(tree) { } -inline bNode &NodeMultiFunctionBuilder::node() +inline const bNode &NodeMultiFunctionBuilder::node() { return node_; } -inline bNodeTree &NodeMultiFunctionBuilder::tree() +inline const bNodeTree &NodeMultiFunctionBuilder::tree() { return tree_; } @@ -110,7 +110,7 @@ inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...ar inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const { static Item empty_item; - const Item *item = map_.lookup_ptr(node->bnode()); + const Item *item = map_.lookup_ptr(node.bnode()); if (item == nullptr) { return empty_item; } diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh deleted file mode 100644 index 257aa5f4110..00000000000 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ /dev/null @@ -1,760 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup nodes - * - * NodeTreeRef makes querying information about a bNodeTree more efficient. It is an immutable data - * structure. It should not be used after anymore, after the underlying node tree changed. - * - * The following queries are supported efficiently: - * - socket -> index of socket - * - socket -> directly linked sockets - * - socket -> directly linked links - * - socket -> linked sockets when skipping reroutes - * - socket -> node - * - socket/node -> rna pointer - * - node -> inputs/outputs - * - node -> tree - * - tree -> all nodes - * - tree -> all (input/output) sockets - * - idname -> nodes - * - * Every socket has an id. The id-space is shared between input and output sockets. - * When storing data per socket, it is often better to use the id as index into an array, instead - * of a hash table. - * - * Every node has an id as well. The same rule regarding hash tables applies. - * - * There is an utility to export this data structure as graph in dot format. - */ - -#include "BLI_array.hh" -#include "BLI_function_ref.hh" -#include "BLI_linear_allocator.hh" -#include "BLI_map.hh" -#include "BLI_multi_value_map.hh" -#include "BLI_string_ref.hh" -#include "BLI_timeit.hh" -#include "BLI_utility_mixins.hh" -#include "BLI_vector.hh" - -#include "BKE_node.h" -#include "BKE_node_runtime.hh" - -#include "DNA_node_types.h" - -#include "RNA_access.h" - -namespace blender::nodes { - -class SocketRef; -class InputSocketRef; -class OutputSocketRef; -class NodeRef; -class NodeTreeRef; -class LinkRef; -class InternalLinkRef; - -using SocketIndexByIdentifierMap = Map; - -class SocketRef : NonCopyable, NonMovable { - protected: - NodeRef *node_; - bNodeSocket *bsocket_; - bool is_input_; - int id_; - int index_; - Vector directly_linked_links_; - - /* These sockets are linked directly, i.e. with a single link in between. */ - MutableSpan directly_linked_sockets_; - /* These sockets are linked when reroutes, muted links and muted nodes have been taken into - * account. */ - MutableSpan logically_linked_sockets_; - /* These are the sockets that have been skipped when searching for logically linked sockets. - * That includes for example the input and output socket of an intermediate reroute node. */ - MutableSpan logically_linked_skipped_sockets_; - - friend NodeTreeRef; - - public: - Span logically_linked_sockets() const; - Span logically_linked_skipped_sockets() const; - Span directly_linked_sockets() const; - Span directly_linked_links() const; - - bool is_directly_linked() const; - bool is_logically_linked() const; - - const NodeRef &node() const; - const NodeTreeRef &tree() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const SocketRef &as_base() const; - const InputSocketRef &as_input() const; - const OutputSocketRef &as_output() const; - - PointerRNA rna() const; - - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - bNodeSocket *bsocket() const; - bNode *bnode() const; - bNodeTree *btree() const; - - bool is_available() const; - bool is_undefined() const; - - void *default_value() const; - template T *default_value() const; -}; - -class InputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span logically_linked_sockets() const; - Span directly_linked_sockets() const; - - bool is_multi_input_socket() const; - - private: - void foreach_logical_origin(FunctionRef origin_fn, - FunctionRef skipped_fn, - bool only_follow_first_input_link, - Vector &seen_sockets_stack) const; -}; - -class OutputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span logically_linked_sockets() const; - Span directly_linked_sockets() const; - - private: - void foreach_logical_target(FunctionRef target_fn, - FunctionRef skipped_fn, - Vector &seen_sockets_stack) const; -}; - -class NodeRef : NonCopyable, NonMovable { - private: - NodeTreeRef *tree_; - bNode *bnode_; - int id_; - Vector inputs_; - Vector outputs_; - Vector internal_links_; - SocketIndexByIdentifierMap *input_index_by_identifier_; - SocketIndexByIdentifierMap *output_index_by_identifier_; - - friend NodeTreeRef; - - public: - const NodeTreeRef &tree() const; - - Span inputs() const; - Span outputs() const; - Span internal_links() const; - Span sockets(eNodeSocketInOut in_out) const; - - const InputSocketRef &input(int index) const; - const OutputSocketRef &output(int index) const; - - const InputSocketRef &input_by_identifier(StringRef identifier) const; - const OutputSocketRef &output_by_identifier(StringRef identifier) const; - - bool any_input_is_directly_linked() const; - bool any_output_is_directly_linked() const; - bool any_socket_is_directly_linked(eNodeSocketInOut in_out) const; - - bNode *bnode() const; - bNodeTree *btree() const; - - PointerRNA rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull label() const; - StringRefNull label_or_name() const; - bNodeType *typeinfo() const; - const NodeDeclaration *declaration() const; - - int id() const; - - bool is_reroute_node() const; - bool is_group_node() const; - bool is_group_input_node() const; - bool is_group_output_node() const; - bool is_muted() const; - bool is_frame() const; - bool is_undefined() const; - - void *storage() const; - template T *storage() const; -}; - -class LinkRef : NonCopyable, NonMovable { - private: - OutputSocketRef *from_; - InputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const OutputSocketRef &from() const; - const InputSocketRef &to() const; - - bNodeLink *blink() const; - - bool is_muted() const; -}; - -class InternalLinkRef : NonCopyable, NonMovable { - private: - InputSocketRef *from_; - OutputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const InputSocketRef &from() const; - const OutputSocketRef &to() const; - - bNodeLink *blink() const; -}; - -class NodeTreeRef : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - bNodeTree *btree_; - Vector nodes_by_id_; - Vector sockets_by_id_; - Vector input_sockets_; - Vector output_sockets_; - Vector links_; - MultiValueMap nodes_by_type_; - Vector> owned_identifier_maps_; - const NodeRef *group_output_node_ = nullptr; - - public: - NodeTreeRef(bNodeTree *btree); - ~NodeTreeRef(); - - Span nodes() const; - Span nodes_by_type(StringRefNull idname) const; - Span nodes_by_type(const bNodeType *nodetype) const; - - Span sockets() const; - Span input_sockets() const; - Span output_sockets() const; - - Span links() const; - - const NodeRef *find_node(const bNode &bnode) const; - - /** - * This is the active group output node if there are multiple. - */ - const NodeRef *group_output_node() const; - - /** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ - bool has_link_cycles() const; - bool has_undefined_nodes_or_sockets() const; - - enum class ToposortDirection { - LeftToRight, - RightToLeft, - }; - - struct ToposortResult { - Vector sorted_nodes; - /** - * There can't be a correct topological sort of the nodes when there is a cycle. The nodes will - * still be sorted to some degree. The caller has to decide whether it can handle non-perfect - * sorts or not. - */ - bool has_cycle = false; - }; - - /** - * Sort nodes topologically from left to right or right to left. - * In the future the result if this could be cached on #NodeTreeRef. - */ - ToposortResult toposort(ToposortDirection direction) const; - - bNodeTree *btree() const; - StringRefNull name() const; - - std::string to_dot() const; - - private: - /* Utility functions used during construction. */ - InputSocketRef &find_input_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - OutputSocketRef &find_output_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - - void create_linked_socket_caches(); - void create_socket_identifier_maps(); -}; - -using NodeTreeRefMap = Map>; - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree); - -namespace node_tree_ref_types { -using nodes::InputSocketRef; -using nodes::NodeRef; -using nodes::NodeTreeRef; -using nodes::NodeTreeRefMap; -using nodes::OutputSocketRef; -using nodes::SocketRef; -} // namespace node_tree_ref_types - -/* -------------------------------------------------------------------- */ -/** \name #SocketRef Inline Methods - * \{ */ - -inline Span SocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_; -} - -inline Span SocketRef::logically_linked_skipped_sockets() const -{ - return logically_linked_skipped_sockets_; -} - -inline Span SocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_; -} - -inline Span SocketRef::directly_linked_links() const -{ - return directly_linked_links_; -} - -inline bool SocketRef::is_directly_linked() const -{ - return directly_linked_sockets_.size() > 0; -} - -inline bool SocketRef::is_logically_linked() const -{ - return logically_linked_sockets_.size() > 0; -} - -inline const NodeRef &SocketRef::node() const -{ - return *node_; -} - -inline const NodeTreeRef &SocketRef::tree() const -{ - return node_->tree(); -} - -inline int SocketRef::id() const -{ - return id_; -} - -inline int SocketRef::index() const -{ - return index_; -} - -inline bool SocketRef::is_input() const -{ - return is_input_; -} - -inline bool SocketRef::is_output() const -{ - return !is_input_; -} - -inline const SocketRef &SocketRef::as_base() const -{ - return *this; -} - -inline const InputSocketRef &SocketRef::as_input() const -{ - BLI_assert(this->is_input()); - return static_cast(*this); -} - -inline const OutputSocketRef &SocketRef::as_output() const -{ - BLI_assert(this->is_output()); - return static_cast(*this); -} - -inline StringRefNull SocketRef::idname() const -{ - return bsocket_->idname; -} - -inline StringRefNull SocketRef::name() const -{ - return bsocket_->name; -} - -inline StringRefNull SocketRef::identifier() const -{ - return bsocket_->identifier; -} - -inline bNodeSocketType *SocketRef::typeinfo() const -{ - return bsocket_->typeinfo; -} - -inline bNodeSocket *SocketRef::bsocket() const -{ - return bsocket_; -} - -inline bNode *SocketRef::bnode() const -{ - return node_->bnode(); -} - -inline bNodeTree *SocketRef::btree() const -{ - return node_->btree(); -} - -inline bool SocketRef::is_available() const -{ - return (bsocket_->flag & SOCK_UNAVAIL) == 0; -} - -inline bool SocketRef::is_undefined() const -{ - return bsocket_->typeinfo == &NodeSocketTypeUndefined; -} - -inline void *SocketRef::default_value() const -{ - return bsocket_->default_value; -} - -template inline T *SocketRef::default_value() const -{ - return (T *)bsocket_->default_value; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InputSocketRef Inline Methods - * \{ */ - -inline Span InputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast(); -} - -inline Span InputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast(); -} - -inline bool InputSocketRef::is_multi_input_socket() const -{ - return bsocket_->flag & SOCK_MULTI_INPUT; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #OutputSocketRef Inline Methods - * \{ */ - -inline Span OutputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast(); -} - -inline Span OutputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeRef Inline Methods - * \{ */ - -inline const NodeTreeRef &NodeRef::tree() const -{ - return *tree_; -} - -inline Span NodeRef::inputs() const -{ - return inputs_; -} - -inline Span NodeRef::outputs() const -{ - return outputs_; -} - -inline Span NodeRef::sockets(const eNodeSocketInOut in_out) const -{ - return in_out == SOCK_IN ? inputs_.as_span().cast() : - outputs_.as_span().cast(); -} - -inline Span NodeRef::internal_links() const -{ - return internal_links_; -} - -inline const InputSocketRef &NodeRef::input(int index) const -{ - return *inputs_[index]; -} - -inline const OutputSocketRef &NodeRef::output(int index) const -{ - return *outputs_[index]; -} - -inline const InputSocketRef &NodeRef::input_by_identifier(StringRef identifier) const -{ - const int index = input_index_by_identifier_->lookup_as(identifier); - return this->input(index); -} - -inline const OutputSocketRef &NodeRef::output_by_identifier(StringRef identifier) const -{ - const int index = output_index_by_identifier_->lookup_as(identifier); - return this->output(index); -} - -inline bNode *NodeRef::bnode() const -{ - return bnode_; -} - -inline bNodeTree *NodeRef::btree() const -{ - return tree_->btree(); -} - -inline StringRefNull NodeRef::idname() const -{ - return bnode_->idname; -} - -inline StringRefNull NodeRef::name() const -{ - return bnode_->name; -} - -inline StringRefNull NodeRef::label() const -{ - return bnode_->label; -} - -inline StringRefNull NodeRef::label_or_name() const -{ - const StringRefNull label = this->label(); - if (!label.is_empty()) { - return label; - } - return this->name(); -} - -inline bNodeType *NodeRef::typeinfo() const -{ - return bnode_->typeinfo; -} - -/* Returns a pointer because not all nodes have declarations currently. */ -inline const NodeDeclaration *NodeRef::declaration() const -{ - nodeDeclarationEnsure(this->tree().btree(), bnode_); - return bnode_->runtime->declaration; -} - -inline int NodeRef::id() const -{ - return id_; -} - -inline bool NodeRef::is_reroute_node() const -{ - return bnode_->type == NODE_REROUTE; -} - -inline bool NodeRef::is_group_node() const -{ - return bnode_->type == NODE_GROUP || bnode_->type == NODE_CUSTOM_GROUP; -} - -inline bool NodeRef::is_group_input_node() const -{ - return bnode_->type == NODE_GROUP_INPUT; -} - -inline bool NodeRef::is_group_output_node() const -{ - return bnode_->type == NODE_GROUP_OUTPUT; -} - -inline bool NodeRef::is_frame() const -{ - return bnode_->type == NODE_FRAME; -} - -inline bool NodeRef::is_undefined() const -{ - return bnode_->typeinfo == &NodeTypeUndefined; -} - -inline bool NodeRef::is_muted() const -{ - return (bnode_->flag & NODE_MUTED) != 0; -} - -inline void *NodeRef::storage() const -{ - return bnode_->storage; -} - -template inline T *NodeRef::storage() const -{ - return (T *)bnode_->storage; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #LinkRef Inline Methods - * \{ */ - -inline const OutputSocketRef &LinkRef::from() const -{ - return *from_; -} - -inline const InputSocketRef &LinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *LinkRef::blink() const -{ - return blink_; -} - -inline bool LinkRef::is_muted() const -{ - return blink_->flag & NODE_LINK_MUTED; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InternalLinkRef Inline Methods - * \{ */ - -inline const InputSocketRef &InternalLinkRef::from() const -{ - return *from_; -} - -inline const OutputSocketRef &InternalLinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *InternalLinkRef::blink() const -{ - return blink_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeTreeRef Inline Methods - * \{ */ - -inline Span NodeTreeRef::nodes() const -{ - return nodes_by_id_; -} - -inline Span NodeTreeRef::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span NodeTreeRef::sockets() const -{ - return sockets_by_id_; -} - -inline Span NodeTreeRef::input_sockets() const -{ - return input_sockets_; -} - -inline Span NodeTreeRef::output_sockets() const -{ - return output_sockets_; -} - -inline Span NodeTreeRef::links() const -{ - return links_; -} - -inline const NodeRef *NodeTreeRef::group_output_node() const -{ - return group_output_node_; -} - -inline bNodeTree *NodeTreeRef::btree() const -{ - return btree_; -} - -inline StringRefNull NodeTreeRef::name() const -{ - return btree_->id.name + 2; -} - -/** \} */ - -} // namespace blender::nodes diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index d8852e9333f..b6bd263b150 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -457,8 +457,8 @@ class ImageOperation : public NodeOperation { update_image_frame_number(); - for (const OutputSocketRef *output : node()->outputs()) { - compute_output(output->identifier()); + for (const bNodeSocket *output : this->node()->output_sockets()) { + compute_output(output->identifier); } } @@ -488,12 +488,12 @@ class ImageOperation : public NodeOperation { /* Allocate all needed outputs as invalid. This should be called when is_valid returns false. */ void allocate_invalid() { - for (const OutputSocketRef *output : node()->outputs()) { - if (!should_compute_output(output->identifier())) { + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!should_compute_output(output->identifier)) { continue; } - Result &result = get_result(output->identifier()); + Result &result = get_result(output->identifier); result.allocate_invalid(); } } @@ -594,7 +594,7 @@ class ImageOperation : public NodeOperation { const char *get_pass_name(StringRef identifier) { DOutputSocket output = node().output_by_identifier(identifier); - return static_cast(output->bsocket()->storage)->pass_name; + return static_cast(output->storage)->pass_name; } /* Get the index of the pass with the given name in the selected render layer's passes list @@ -850,9 +850,9 @@ class RenderLayerOperation : public NodeOperation { alpha_result.unbind_as_image(); /* Other output passes are not supported for now, so allocate them as invalid. */ - for (const OutputSocketRef *output : node()->outputs()) { - if (output->identifier() != "Image" && output->identifier() != "Alpha") { - get_result(output->identifier()).allocate_invalid(); + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!STREQ(output->identifier, "Image") && !STREQ(output->identifier, "Alpha")) { + get_result(output->identifier).allocate_invalid(); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc index f61ace01cfd..a1a6303e21b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc @@ -51,9 +51,12 @@ class NormalShaderNode : public ShaderNode { } /* The vector value is stored in the default value of the output socket. */ - float *get_vector_value() + const float *get_vector_value() { - return node().output_by_identifier("Normal")->default_value()->value; + return node() + .output_by_identifier("Normal") + ->default_value_typed() + ->value; } }; diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index fd0b6c31b1d..059b2f9bc17 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -23,4 +23,6 @@ #include "FN_multi_function_builder.hh" +#include "RNA_access.h" + void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc index 7d08d57c503..e5c89567d44 100644 --- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc @@ -190,7 +190,7 @@ class MF_AlignEulerToVector : public fn::MultiFunction { static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn(node.custom1, node.custom2); } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b6d7e6c9a5f..5fc28509a49 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -68,7 +68,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SI_SO and_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc index c5fd3ce38a1..450cd166e78 100644 --- a/source/blender/nodes/function/nodes/node_fn_combine_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc @@ -49,7 +49,7 @@ static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { const NodeCombSepColor &storage = node_storage(bnode); diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc index e3f13dc7d6b..122d1a3c93e 100644 --- a/source/blender/nodes/function/nodes/node_fn_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_compare.cc @@ -167,7 +167,7 @@ static float component_average(float3 a) return (a.x + a.y + a.z) / 3.0f; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage; diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 9c9d8620a7e..aad2f532d20 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -39,7 +39,7 @@ static void node_float_to_int_label(const bNodeTree *UNUSED(ntree), BLI_strncpy(label, IFACE_(name), maxlen); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SO round_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc index 5ced719627f..717f4d1ac6b 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc @@ -22,7 +22,7 @@ static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), Poi static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputBool *node_storage = static_cast(bnode.storage); builder.construct_and_set_matching_fn>(node_storage->boolean); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc index 46787f7575d..cdad1542c66 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc @@ -23,7 +23,7 @@ static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), Po static void fn_node_input_color_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputColor *node_storage = static_cast(bnode.storage); blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color; builder.construct_and_set_matching_fn>(color); diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc index 1e5dcd5ae7a..16506b5f9b8 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc @@ -22,7 +22,7 @@ static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), Poin static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputInt *node_storage = static_cast(bnode.storage); builder.construct_and_set_matching_fn>(node_storage->integer); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index 124a8572f78..129d19f4f04 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -20,7 +20,7 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputString *node_storage = static_cast(bnode.storage); std::string string = std::string((node_storage->string) ? node_storage->string : ""); builder.construct_and_set_matching_fn>(std::move(string)); diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc index 898c19e92f0..de894a4038d 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -22,7 +22,7 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputVector *node_storage = static_cast(bnode.storage); float3 vector(node_storage->vector); builder.construct_and_set_matching_fn>(vector); diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index a4fc1a6bfd1..299c0f7a932 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -52,7 +52,7 @@ static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static fn::CustomMF_SI_SI_SO obj_euler_rot{ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) { diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index a4af608a40e..4db4d8bb097 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -20,6 +20,8 @@ #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" +#include "RNA_access.h" + #include "node_util.h" void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e589da09b16..e8e0f0fa61c 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -2,38 +2,38 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node.h" + #include "BLI_dot_export.hh" namespace blender::nodes { -DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) +DerivedNodeTree::DerivedNodeTree(const bNodeTree &btree) { /* Construct all possible contexts immediately. This is significantly cheaper than inlining all * node groups. If it still becomes a performance issue in the future, contexts could be * constructed lazily when they are needed. */ - root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree); } DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs) + const bNode *parent_node, + const bNodeTree &btree) { + btree.ensure_topology_cache(); DTreeContext &context = *allocator_.construct().release(); context.parent_context_ = parent_context; context.parent_node_ = parent_node; context.derived_tree_ = this; - context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); - used_node_tree_refs_.add(context.tree_); + context.btree_ = &btree; + used_btrees_.add(context.btree_); - for (const NodeRef *node : context.tree_->nodes()) { - if (node->is_group_node()) { - bNode *bnode = node->bnode(); + for (const bNode *bnode : context.btree_->all_nodes()) { + if (bnode->is_group()) { bNodeTree *child_btree = reinterpret_cast(bnode->id); if (child_btree != nullptr) { - DTreeContext &child = this->construct_context_recursively( - &context, node, *child_btree, node_tree_refs); - context.children_.add_new(node, &child); + DTreeContext &child = this->construct_context_recursively(&context, bnode, *child_btree); + context.children_.add_new(bnode, &child); } } } @@ -57,8 +57,8 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) bool DerivedNodeTree::has_link_cycles() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_link_cycles()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_link_cycle()) { return true; } } @@ -67,8 +67,8 @@ bool DerivedNodeTree::has_link_cycles() const bool DerivedNodeTree::has_undefined_nodes_or_sockets() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_undefined_nodes_or_sockets()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_undefined_nodes_or_sockets()) { return true; } } @@ -83,8 +83,8 @@ void DerivedNodeTree::foreach_node(FunctionRef callback) const void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, FunctionRef callback) const { - for (const NodeRef *node_ref : context.tree_->nodes()) { - callback(DNode(&context, node_ref)); + for (const bNode *bnode : context.btree_->all_nodes()) { + callback(DNode(&context, bnode)); } for (const DTreeContext *child_context : context.children_.values()) { this->foreach_node_in_context_recursive(*child_context, callback); @@ -94,32 +94,32 @@ void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &cont DOutputSocket DInputSocket::get_corresponding_group_node_output() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_output_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_output()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().input_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->output(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->output_socket(socket_index)}; } Vector DInputSocket::get_corresponding_group_input_sockets() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); BLI_assert(child_context != nullptr); - const NodeTreeRef &child_tree = child_context->tree(); - Span group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); - const int socket_index = socket_ref_->index(); + const bNodeTree &child_tree = child_context->btree(); + Span group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = bsocket_->index(); Vector sockets; - for (const NodeRef *group_input_node : group_input_nodes) { - sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); + for (const bNode *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output_socket(socket_index))); } return sockets; } @@ -127,36 +127,36 @@ Vector DInputSocket::get_corresponding_group_input_sockets() cons DInputSocket DOutputSocket::get_corresponding_group_node_input() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_input_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_input()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().output_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->input(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->input_socket(socket_index)}; } DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); if (child_context == nullptr) { /* Can happen when the group node references a non-existent group (e.g. when the group is * linked but the original file is not found). */ return {}; } - const NodeTreeRef &child_tree = child_context->tree(); - Span group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); - const int socket_index = socket_ref_->index(); - for (const NodeRef *group_output_node : group_output_nodes) { - if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { - return {child_context, &group_output_node->input(socket_index)}; + const bNodeTree &child_tree = child_context->btree(); + Span group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = bsocket_->index(); + for (const bNode *group_output_node : group_output_nodes) { + if (group_output_node->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input_socket(socket_index)}; } } return {}; @@ -165,11 +165,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const void DInputSocket::foreach_origin_socket(FunctionRef origin_fn) const { BLI_assert(*this); - for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) { - const NodeRef &linked_node = linked_socket->node(); + for (const bNodeSocket *linked_socket : bsocket_->logically_linked_sockets()) { + const bNode &linked_node = linked_socket->owner_node(); DOutputSocket linked_dsocket{context_, linked_socket}; - if (linked_node.is_group_input_node()) { + if (linked_node.is_group_input()) { if (context_->is_root()) { /* This is a group input in the root node group. */ origin_fn(linked_dsocket); @@ -187,7 +187,7 @@ void DInputSocket::foreach_origin_socket(FunctionRef origin_fn) c } } } - else if (linked_node.is_group_node()) { + else if (linked_node.is_group()) { DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); if (socket_in_group) { if (socket_in_group->is_logically_linked()) { @@ -217,16 +217,16 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, TargetSocketPathInfo &path_info) const { - for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) { + for (const bNodeLink *link : bsocket_->directly_linked_links()) { if (link->is_muted()) { continue; } - const DInputSocket &linked_socket{context_, &link->to()}; + const DInputSocket &linked_socket{context_, link->tosock}; if (!linked_socket->is_available()) { continue; } const DNode linked_node = linked_socket.node(); - if (linked_node->is_reroute_node()) { + if (linked_node->is_reroute()) { const DInputSocket reroute_input = linked_socket; const DOutputSocket reroute_output = linked_node.output(0); path_info.sockets.append(reroute_input); @@ -236,18 +236,18 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } else if (linked_node->is_muted()) { - for (const InternalLinkRef *internal_link : linked_node->internal_links()) { - if (&internal_link->from() != linked_socket.socket_ref()) { + for (const bNodeLink *internal_link : linked_node->internal_links_span()) { + if (internal_link->fromsock != linked_socket.bsocket()) { continue; } /* The internal link only forwards the first incoming link. */ - if (linked_socket->is_multi_input_socket()) { + if (linked_socket->is_multi_input()) { if (linked_socket->directly_linked_links()[0] != link) { continue; } } const DInputSocket mute_input = linked_socket; - const DOutputSocket mute_output{context_, &internal_link->to()}; + const DOutputSocket mute_output{context_, internal_link->tosock}; path_info.sockets.append(mute_input); path_info.sockets.append(mute_output); mute_output.foreach_target_socket(target_fn, path_info); @@ -255,8 +255,8 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_output_node()) { - if (linked_node.node_ref() != context_->tree().group_output_node()) { + else if (linked_node->is_group_output()) { + if (linked_node.bnode() != context_->btree().group_output_node()) { continue; } if (context_->is_root()) { @@ -276,7 +276,7 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_node()) { + else if (linked_node->is_group()) { /* Follow the links within the nested node group. */ path_info.sockets.append(linked_socket); const Vector sockets_in_group = @@ -310,7 +310,8 @@ static dot::Cluster *get_dot_cluster_for_context( } dot::Cluster *parent_cluster = get_dot_cluster_for_context( digraph, parent_context, dot_clusters); - std::string cluster_name = context->tree().name() + " / " + context->parent_node()->name(); + std::string cluster_name = StringRef(context->btree().id.name + 2) + " / " + + context->parent_node()->name; dot::Cluster &cluster = digraph.new_cluster(cluster_name); cluster.set_parent_cluster(parent_cluster); return &cluster; @@ -328,11 +329,11 @@ std::string DerivedNodeTree::to_dot() const this->foreach_node([&](DNode node) { /* Ignore nodes that should not show up in the final output. */ - if (node->is_muted() || node->is_group_node() || node->is_reroute_node() || node->is_frame()) { + if (node->is_muted() || node->is_group() || node->is_reroute() || node->is_frame()) { return; } if (!node.context()->is_root()) { - if (node->is_group_input_node() || node->is_group_output_node()) { + if (node->is_group_input() || node->is_group_output()) { return; } } @@ -345,22 +346,22 @@ std::string DerivedNodeTree::to_dot() const Vector input_names; Vector output_names; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { - input_names.append(socket->name()); + input_names.append(socket->name); } } - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { - output_names.append(socket->name()); + output_names.append(socket->name); } } dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef( - dot_node, node->name(), input_names, output_names); + dot_node, node->name, input_names, output_names); int input_index = 0; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { dot_input_sockets.add_new(DInputSocket{node.context(), socket}, dot_node_with_sockets.input(input_index)); @@ -368,7 +369,7 @@ std::string DerivedNodeTree::to_dot() const } } int output_index = 0; - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { dot_output_sockets.add_new(DOutputSocket{node.context(), socket}, dot_node_with_sockets.output(output_index)); @@ -392,7 +393,7 @@ std::string DerivedNodeTree::to_dot() const } } dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() { - dot::Node &dot_node = digraph.new_node(from_socket->name()); + dot::Node &dot_node = digraph.new_node(from_socket->name); dot_node.set_background_color("white"); dot_node.set_shape(dot::Attr_shape::Ellipse); dot_node.set_parent_cluster( diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 55930dcb1ee..89bfa5834e8 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -89,17 +89,17 @@ TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_conte destruct_ptr owned_tree_log = allocator_.construct(); tree_log = owned_tree_log.get(); log_by_tree_context.add_new(&tree_context, tree_log); - parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log)); + parent_log.child_logs_.add_new(tree_context.parent_node()->name, std::move(owned_tree_log)); return *tree_log; } NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node) { TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context()); - NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() { + NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name, [&]() { destruct_ptr node_log = allocator_.construct(); - node_log->input_logs_.resize(node->inputs().size()); - node_log->output_logs_.resize(node->outputs().size()); + node_log->input_logs_.resize(node->input_sockets().size()); + node_log->output_logs_.resize(node->output_sockets().size()); return node_log; }); return node_log; diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index c6ebc22c43c..953dce035c2 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -38,7 +38,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { const SocketDeclaration &decl = - *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration; + *provider_->dnode->input_by_identifier(identifier).runtime->declaration; const decl::Geometry *geo_decl = dynamic_cast(&decl); if (geo_decl == nullptr) { return; @@ -118,9 +118,9 @@ void GeoNodeExecParams::check_output_geometry_set(const GeometrySet &geometry_se const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->is_available() && socket->name() == name) { - return socket->bsocket(); + for (const bNodeSocket *socket : provider_->dnode->runtime->inputs) { + if (socket->is_available() && socket->name == name) { + return socket; } } @@ -140,10 +140,10 @@ void GeoNodeExecParams::set_default_remaining_outputs() void GeoNodeExecParams::check_input_access(StringRef identifier, const CPPType *requested_type) const { - bNodeSocket *found_socket = nullptr; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -151,9 +151,9 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; @@ -182,10 +182,10 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const { - bNodeSocket *found_socket = nullptr; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -193,9 +193,9 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (!(socket->flag & SOCK_UNAVAIL)) { + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; diff --git a/source/blender/nodes/intern/node_multi_function.cc b/source/blender/nodes/intern/node_multi_function.cc index 13bfdfbfac1..1f8397923e9 100644 --- a/source/blender/nodes/intern/node_multi_function.cc +++ b/source/blender/nodes/intern/node_multi_function.cc @@ -2,14 +2,14 @@ #include "NOD_multi_function.hh" +#include "BKE_node.h" + namespace blender::nodes { NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree) { - for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) { - bNodeTree *btree = tree_ref->btree(); - for (const NodeRef *node : tree_ref->nodes()) { - bNode *bnode = node->bnode(); + for (const bNodeTree *btree : tree.used_btrees()) { + for (const bNode *bnode : btree->all_nodes()) { if (bnode->typeinfo->build_multi_function == nullptr) { continue; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc deleted file mode 100644 index 05e7fe33776..00000000000 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ /dev/null @@ -1,679 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include - -#include "NOD_node_tree_ref.hh" - -#include "BLI_dot_export.hh" -#include "BLI_stack.hh" - -#include "RNA_prototypes.h" - -namespace blender::nodes { - -NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) -{ - Map node_mapping; - - LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) { - NodeRef &node = *allocator_.construct().release(); - - node.tree_ = this; - node.bnode_ = bnode; - node.id_ = nodes_by_id_.append_and_get_index(&node); - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) { - InputSocketRef &socket = *allocator_.construct().release(); - socket.node_ = &node; - socket.index_ = node.inputs_.append_and_get_index(&socket); - socket.is_input_ = true; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) { - OutputSocketRef &socket = *allocator_.construct().release(); - socket.node_ = &node; - socket.index_ = node.outputs_.append_and_get_index(&socket); - socket.is_input_ = false; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { - InternalLinkRef &internal_link = *allocator_.construct().release(); - internal_link.blink_ = blink; - for (InputSocketRef *socket_ref : node.inputs_) { - if (socket_ref->bsocket_ == blink->fromsock) { - internal_link.from_ = socket_ref; - break; - } - } - for (OutputSocketRef *socket_ref : node.outputs_) { - if (socket_ref->bsocket_ == blink->tosock) { - internal_link.to_ = socket_ref; - break; - } - } - BLI_assert(internal_link.from_ != nullptr); - BLI_assert(internal_link.to_ != nullptr); - node.internal_links_.append(&internal_link); - } - - input_sockets_.extend(node.inputs_.as_span()); - output_sockets_.extend(node.outputs_.as_span()); - - node_mapping.add_new(bnode, &node); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &btree->links) { - OutputSocketRef &from_socket = this->find_output_socket( - node_mapping, blink->fromnode, blink->fromsock); - InputSocketRef &to_socket = this->find_input_socket( - node_mapping, blink->tonode, blink->tosock); - - LinkRef &link = *allocator_.construct().release(); - link.from_ = &from_socket; - link.to_ = &to_socket; - link.blink_ = blink; - - links_.append(&link); - - from_socket.directly_linked_links_.append(&link); - to_socket.directly_linked_links_.append(&link); - } - - for (InputSocketRef *input_socket : input_sockets_) { - if (input_socket->is_multi_input_socket()) { - std::sort(input_socket->directly_linked_links_.begin(), - input_socket->directly_linked_links_.end(), - [&](const LinkRef *a, const LinkRef *b) -> bool { - int index_a = a->blink()->multi_input_socket_index; - int index_b = b->blink()->multi_input_socket_index; - return index_a > index_b; - }); - } - } - - this->create_socket_identifier_maps(); - this->create_linked_socket_caches(); - - for (NodeRef *node : nodes_by_id_) { - const bNodeType *nodetype = node->bnode_->typeinfo; - nodes_by_type_.add(nodetype, node); - } - - const Span group_output_nodes = this->nodes_by_type("NodeGroupOutput"); - if (group_output_nodes.is_empty()) { - group_output_node_ = nullptr; - } - else if (group_output_nodes.size() == 1) { - group_output_node_ = group_output_nodes.first(); - } - else { - for (const NodeRef *group_output : group_output_nodes) { - if (group_output->bnode_->flag & NODE_DO_OUTPUT) { - group_output_node_ = group_output; - break; - } - } - } -} - -NodeTreeRef::~NodeTreeRef() -{ - /* The destructor has to be called manually, because these types are allocated in a linear - * allocator. */ - for (NodeRef *node : nodes_by_id_) { - node->~NodeRef(); - } - for (InputSocketRef *socket : input_sockets_) { - socket->~InputSocketRef(); - } - for (OutputSocketRef *socket : output_sockets_) { - socket->~OutputSocketRef(); - } - for (LinkRef *link : links_) { - link->~LinkRef(); - } -} - -InputSocketRef &NodeTreeRef::find_input_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (InputSocketRef *socket : node->inputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->inputs_[0]; -} - -OutputSocketRef &NodeTreeRef::find_output_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (OutputSocketRef *socket : node->outputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->outputs_[0]; -} - -void NodeTreeRef::create_linked_socket_caches() -{ - for (InputSocketRef *socket : input_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->from_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector logically_linked_sockets; - Vector logically_linked_skipped_sockets; - Vector seen_sockets_stack; - socket->foreach_logical_origin( - [&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - false, - seen_sockets_stack); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } - - for (OutputSocketRef *socket : output_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->to_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector logically_linked_sockets; - Vector logically_linked_skipped_sockets; - Vector handled_sockets; - socket->foreach_logical_target( - [&](const InputSocketRef &target) { logically_linked_sockets.append(&target); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - handled_sockets); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } -} - -void InputSocketRef::foreach_logical_origin( - FunctionRef origin_fn, - FunctionRef skipped_fn, - bool only_follow_first_input_link, - Vector &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - Span links_to_check = this->directly_linked_links(); - if (only_follow_first_input_link) { - links_to_check = links_to_check.take_front(1); - } - for (const LinkRef *link : links_to_check) { - if (link->is_muted()) { - continue; - } - const OutputSocketRef &origin = link->from(); - const NodeRef &origin_node = origin.node(); - if (!origin.is_available()) { - /* Non available sockets are ignored. */ - } - else if (origin_node.is_reroute_node()) { - const InputSocketRef &reroute_input = origin_node.input(0); - const OutputSocketRef &reroute_output = origin_node.output(0); - skipped_fn.call_safe(reroute_input); - skipped_fn.call_safe(reroute_output); - reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false, seen_sockets_stack); - } - else if (origin_node.is_muted()) { - for (const InternalLinkRef *internal_link : origin_node.internal_links()) { - if (&internal_link->to() == &origin) { - const InputSocketRef &mute_input = internal_link->from(); - skipped_fn.call_safe(origin); - skipped_fn.call_safe(mute_input); - mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack); - } - } - } - else { - origin_fn(origin); - } - } - - seen_sockets_stack.pop_last(); -} - -void OutputSocketRef::foreach_logical_target( - FunctionRef target_fn, - FunctionRef skipped_fn, - Vector &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - for (const LinkRef *link : this->directly_linked_links()) { - if (link->is_muted()) { - continue; - } - const InputSocketRef &target = link->to(); - const NodeRef &target_node = target.node(); - if (!target.is_available()) { - /* Non available sockets are ignored. */ - } - else if (target_node.is_reroute_node()) { - const OutputSocketRef &reroute_output = target_node.output(0); - skipped_fn.call_safe(target); - skipped_fn.call_safe(reroute_output); - reroute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - else if (target_node.is_muted()) { - skipped_fn.call_safe(target); - for (const InternalLinkRef *internal_link : target_node.internal_links()) { - if (&internal_link->from() == &target) { - /* The internal link only forwards the first incoming link. */ - if (target.is_multi_input_socket()) { - if (target.directly_linked_links()[0] != link) { - continue; - } - } - const OutputSocketRef &mute_output = internal_link->to(); - skipped_fn.call_safe(target); - skipped_fn.call_safe(mute_output); - mute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - } - } - else { - target_fn(target); - } - } - - seen_sockets_stack.pop_last(); -} - -namespace { -struct SocketByIdentifierMap { - SocketIndexByIdentifierMap *map = nullptr; - std::unique_ptr owned_map; -}; -} // namespace - -static std::unique_ptr create_identifier_map(const ListBase &sockets) -{ - std::unique_ptr map = std::make_unique(); - int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) { - map->add_new(socket->identifier, index); - } - return map; -} - -/* This function is not threadsafe. */ -static SocketByIdentifierMap get_or_create_identifier_map( - const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template) -{ - SocketByIdentifierMap map; - if (sockets_template == nullptr) { - if (BLI_listbase_is_empty(&sockets)) { - static SocketIndexByIdentifierMap empty_map; - map.map = &empty_map; - } - else if (node.type == NODE_REROUTE) { - if (&node.inputs == &sockets) { - static SocketIndexByIdentifierMap reroute_input_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Input", 0); - return map; - }(); - map.map = &reroute_input_map; - } - else { - static SocketIndexByIdentifierMap reroute_output_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Output", 0); - return map; - }(); - map.map = &reroute_output_map; - } - } - else { - /* The node has a dynamic amount of sockets. Therefore we need to create a new map. */ - map.owned_map = create_identifier_map(sockets); - map.map = &*map.owned_map; - } - } - else { - /* Cache only one map for nodes that have the same sockets. */ - static Map> maps; - map.map = &*maps.lookup_or_add_cb(sockets_template, - [&]() { return create_identifier_map(sockets); }); - } - return map; -} - -void NodeTreeRef::create_socket_identifier_maps() -{ - /* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */ - static std::mutex mutex; - std::lock_guard lock{mutex}; - - for (NodeRef *node : nodes_by_id_) { - bNode &bnode = *node->bnode_; - SocketByIdentifierMap inputs_map = get_or_create_identifier_map( - bnode, bnode.inputs, bnode.typeinfo->inputs); - SocketByIdentifierMap outputs_map = get_or_create_identifier_map( - bnode, bnode.outputs, bnode.typeinfo->outputs); - node->input_index_by_identifier_ = inputs_map.map; - node->output_index_by_identifier_ = outputs_map.map; - if (inputs_map.owned_map) { - owned_identifier_maps_.append(std::move(inputs_map.owned_map)); - } - if (outputs_map.owned_map) { - owned_identifier_maps_.append(std::move(outputs_map.owned_map)); - } - } -} - -static bool has_link_cycles_recursive(const NodeRef &node, - MutableSpan visited, - MutableSpan is_in_stack) -{ - const int node_id = node.id(); - if (is_in_stack[node_id]) { - return true; - } - if (visited[node_id]) { - return false; - } - - visited[node_id] = true; - is_in_stack[node_id] = true; - - for (const OutputSocketRef *from_socket : node.outputs()) { - if (!from_socket->is_available()) { - continue; - } - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - if (!to_socket->is_available()) { - continue; - } - const NodeRef &to_node = to_socket->node(); - if (has_link_cycles_recursive(to_node, visited, is_in_stack)) { - return true; - } - } - } - - is_in_stack[node_id] = false; - return false; -} - -bool NodeTreeRef::has_link_cycles() const -{ - const int node_amount = nodes_by_id_.size(); - Array visited(node_amount, false); - Array is_in_stack(node_amount, false); - - for (const NodeRef *node : nodes_by_id_) { - if (has_link_cycles_recursive(*node, visited, is_in_stack)) { - return true; - } - } - return false; -} - -bool NodeTreeRef::has_undefined_nodes_or_sockets() const -{ - for (const NodeRef *node : nodes_by_id_) { - if (node->is_undefined()) { - return true; - } - } - for (const SocketRef *socket : sockets_by_id_) { - if (socket->is_undefined()) { - return true; - } - } - return false; -} - -bool NodeRef::any_input_is_directly_linked() const -{ - for (const SocketRef *socket : inputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_output_is_directly_linked() const -{ - for (const SocketRef *socket : outputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const -{ - if (in_out == SOCK_IN) { - return this->any_input_is_directly_linked(); - } - return this->any_output_is_directly_linked(); -} - -struct ToposortNodeState { - bool is_done = false; - bool is_in_stack = false; -}; - -static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction, - const NodeRef &start_node, - MutableSpan node_states, - NodeTreeRef::ToposortResult &result) -{ - struct Item { - const NodeRef *node; - /* Index of the next socket that is checked in the depth-first search. */ - int socket_index = 0; - /* Link index in the next socket that is checked in the depth-first search. */ - int link_index = 0; - }; - - /* Do a depth-first search to sort nodes topologically. */ - Stack nodes_to_check; - nodes_to_check.push({&start_node}); - node_states[start_node.id()].is_in_stack = true; - while (!nodes_to_check.is_empty()) { - Item &item = nodes_to_check.peek(); - const NodeRef &node = *item.node; - const Span sockets = node.sockets( - direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT); - - while (true) { - if (item.socket_index == sockets.size()) { - /* All sockets have already been visited. */ - break; - } - const SocketRef &socket = *sockets[item.socket_index]; - const Span linked_sockets = socket.directly_linked_sockets(); - if (item.link_index == linked_sockets.size()) { - /* All links connected to this socket have already been visited. */ - item.socket_index++; - item.link_index = 0; - continue; - } - const SocketRef &linked_socket = *linked_sockets[item.link_index]; - const NodeRef &linked_node = linked_socket.node(); - ToposortNodeState &linked_node_state = node_states[linked_node.id()]; - if (linked_node_state.is_done) { - /* The linked node has already been visited. */ - item.link_index++; - continue; - } - if (linked_node_state.is_in_stack) { - result.has_cycle = true; - } - else { - nodes_to_check.push({&linked_node}); - linked_node_state.is_in_stack = true; - } - break; - } - - /* If no other element has been pushed, the current node can be pushed to the sorted list. */ - if (&item == &nodes_to_check.peek()) { - ToposortNodeState &node_state = node_states[node.id()]; - node_state.is_done = true; - node_state.is_in_stack = false; - result.sorted_nodes.append(&node); - nodes_to_check.pop(); - } - } -} - -NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const -{ - ToposortResult result; - result.sorted_nodes.reserve(nodes_by_id_.size()); - - Array node_states(nodes_by_id_.size()); - - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - if (node->any_socket_is_directly_linked( - direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) { - /* Ignore non-start nodes. */ - continue; - } - - toposort_from_start_node(direction, *node, node_states, result); - } - - /* Check if the loop above forgot some nodes because there is a cycle. */ - if (result.sorted_nodes.size() < nodes_by_id_.size()) { - result.has_cycle = true; - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - /* Start toposort at this node which is somewhere in the middle of a loop. */ - toposort_from_start_node(direction, *node, node_states, result); - } - } - - BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size()); - return result; -} - -const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const -{ - for (const NodeRef *node : this->nodes_by_type(bnode.typeinfo)) { - if (node->bnode_ == &bnode) { - return node; - } - } - return nullptr; -} - -std::string NodeTreeRef::to_dot() const -{ - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map dot_nodes; - - for (const NodeRef *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector input_names; - Vector output_names; - for (const InputSocketRef *socket : node->inputs()) { - input_names.append(socket->name()); - } - for (const OutputSocketRef *socket : node->outputs()) { - output_names.append(socket->name()); - } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - } - - for (const OutputSocketRef *from_socket : output_sockets_) { - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node()); - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node()); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); - } - } - - return digraph.to_dot_string(); -} - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree) -{ - return *node_tree_refs.lookup_or_add_cb(&btree, - [&]() { return std::make_unique(&btree); }); -} - -PointerRNA NodeRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&tree_->btree()->id, &RNA_Node, bnode_, &rna); - return rna; -} - -PointerRNA SocketRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&this->tree().btree()->id, &RNA_NodeSocket, bsocket_, &rna); - return rna; -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index d5f54d9cac9..38220634695 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -59,6 +59,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +#include "RNA_access.h" + bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index 3723480ffa3..d73ffd89288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -125,7 +125,7 @@ class ColorBandFunction : public fn::MultiFunction { static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); const ColorBand *color_band = (const ColorBand *)bnode.storage; builder.construct_and_set_matching_fn(*color_band); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index eb47059063d..4725aef5991 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -95,7 +95,7 @@ class CurveVecFunction : public fn::MultiFunction { static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -237,7 +237,7 @@ class CurveRGBFunction : public fn::MultiFunction { static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -356,7 +356,7 @@ class CurveFloatFunction : public fn::MultiFunction { static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 73ee6fb3f85..bd83f8dac37 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -102,7 +102,7 @@ static int gpu_shader_math(GPUMaterial *mat, return 0; } -static const fn::MultiFunction *get_base_multi_function(bNode &node) +static const fn::MultiFunction *get_base_multi_function(const bNode &node) { const int mode = node.custom1; const fn::MultiFunction *base_fn = nullptr; diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc index 05aad262af8..918d9b747d5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -344,7 +344,7 @@ class MixColorFunction : public fn::MultiFunction { } }; -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { const NodeShaderMix *data = (NodeShaderMix *)node.storage; bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM; diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index edbded43acf..46ac8f05803 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -136,7 +136,7 @@ class MixRGBFunction : public fn::MultiFunction { static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); bool clamp = node.custom2 & SHD_MIXRGB_CLAMP; int mix_type = node.custom1; builder.construct_and_set_matching_fn(clamp, mix_type); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc index cad9e1b33f2..a1c51a440d0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc @@ -261,7 +261,7 @@ class BrickFunction : public fn::MultiFunction { static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexBrick *tex = (NodeTexBrick *)node.storage; builder.construct_and_set_matching_fn( diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index 8478cbd406b..37c72ec1f17 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -139,7 +139,7 @@ class GradientFunction : public fn::MultiFunction { static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexGradient *tex = (NodeTexGradient *)node.storage; builder.construct_and_set_matching_fn(tex->gradient_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc index 95c4a8b8e46..205d3b89016 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc @@ -161,7 +161,7 @@ class MagicFunction : public fn::MultiFunction { static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMagic *tex = (NodeTexMagic *)node.storage; builder.construct_and_set_matching_fn(tex->depth); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index c13ce3c3df3..a2241c2327f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -516,7 +516,7 @@ class MusgraveFunction : public fn::MultiFunction { static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage; builder.construct_and_set_matching_fn(tex->dimensions, tex->musgrave_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index ad24224dc7f..8475101dbaf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -206,7 +206,7 @@ class WaveFunction : public fn::MultiFunction { static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexWave *tex = (NodeTexWave *)node.storage; builder.construct_and_set_matching_fn( tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 6d4c491046b..64075a903ab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -176,7 +176,7 @@ class WhiteNoiseFunction : public fn::MultiFunction { static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn((int)node.custom1); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 21f5c44c640..d01e03f9d71 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -225,7 +225,7 @@ static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) } } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1); diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index b35f686e331..a036fc52d84 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -96,7 +96,7 @@ static float3 sh_node_vector_rotate_euler(const float3 &vector, return result + center; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { bool invert = node.custom2; const int mode = node.custom1; -- cgit v1.2.3 From d210ab90d4b7b0d2ce472493a697b1e868e36e78 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 31 Aug 2022 12:36:54 +0200 Subject: Fix crash in liboverride operations from the Outliner. Checks for 'invalid' selected IDs that need to be skipped were incomplete, and one was missing the actual return statement. --- source/blender/editors/space_outliner/outliner_tools.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index d6305c836ff..847b9e0963b 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -1274,7 +1274,7 @@ static void id_override_library_reset_fn(bContext *C, OutlinerLibOverrideData *data = reinterpret_cast(user_data); const bool do_hierarchy = data->do_hierarchy; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name); return; } @@ -1302,7 +1302,7 @@ static void id_override_library_clear_single_fn(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); ID *id = tselem->id; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) { BKE_reportf(reports, RPT_WARNING, "Cannot clear embedded library override id '%s', only overrides of real " @@ -1350,8 +1350,9 @@ static void id_override_library_resync_fn(bContext *UNUSED(C), ID *id_root = tselem->id; OutlinerLibOverrideData *data = reinterpret_cast(user_data); - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name); + return; } if (id_root->override_library->hierarchy_root != nullptr) { @@ -1399,7 +1400,7 @@ static void id_override_library_delete_hierarchy_fn(bContext *UNUSED(C), BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); return; } -- cgit v1.2.3 From d3f07998eded607049666d6157f7d32120b51e46 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 13:55:21 +0200 Subject: Cleanup: simplify debugging This makes it easy to set breakpoints where false is returned. --- source/blender/blenkernel/BKE_node_runtime.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 64325959ce5..4c13f73848c 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -172,7 +172,10 @@ inline bool topology_cache_is_available(const bNodeTree &tree) if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) { return true; } - return !tree.runtime->topology_cache_is_dirty; + if (tree.runtime->topology_cache_is_dirty) { + return false; + } + return true; } inline bool topology_cache_is_available(const bNode &node) -- cgit v1.2.3 From 627e8ad6826ac355148a5b2d2b3bf130b96cc2fb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 13:56:56 +0200 Subject: Fix: missing vector clear Otherwise, these vectors are never cleared, leading to crashes down the line. --- source/blender/blenkernel/intern/node_runtime.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc index 20ee3c41534..0c78c0f09d1 100644 --- a/source/blender/blenkernel/intern/node_runtime.cc +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -195,6 +195,8 @@ static void update_logical_origins(const bNodeTree &ntree) bNode &node = *tree_runtime.nodes[i]; for (bNodeSocket *socket : node.runtime->inputs) { Vector sockets_in_current_chain; + socket->runtime->logically_linked_sockets.clear(); + socket->runtime->logically_linked_skipped_sockets.clear(); find_logical_origins_for_socket_recursive( *socket, false, -- cgit v1.2.3 From 4b9d7b71e0075e0b590c5e8d8f9bb67cb6a1e2de Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 14:41:57 +0200 Subject: Fix: incorrect detection of used sockets --- source/blender/blenkernel/intern/node_tree_update.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 716b8ce31d3..a9097bcb94a 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -1037,7 +1037,7 @@ class NodeTreeMainUpdater { for (bNodeSocket *socket : tree.all_sockets()) { socket->flag &= ~SOCK_IN_USE; for (const bNodeLink *link : socket->directly_linked_links()) { - if ((link->flag & NODE_LINK_MUTED) != 0) { + if (!link->is_muted()) { socket->flag |= SOCK_IN_USE; break; } -- cgit v1.2.3 From 24fe659224b281ceca64f71f372f12f5905f6a77 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 31 Aug 2022 14:44:55 +0200 Subject: LibOverride: Replace linked objects by their overrides when created from 3DView. From the 3DView code has basically no knowledge of collection hierarchy, so we can either not remap any local usage of linked objects that are being overridden, or remap them in all their local collections. The second behavior makes most sense in the vast majority of cases. Note that this was only an issue when directly linking and overriding objects, not when doing so through collections. --- source/blender/editors/object/object_relations.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 22f777c0846..a33cc60cddc 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2356,6 +2356,25 @@ static int make_override_library_exec(bContext *C, wmOperator *op) BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* For the time being, replace selected linked objects by their overrides in all collections. + * While this may not be the absolute best behavior in all cases, in most common one this should + * match the expected result. */ + if (user_overrides_objects_uids != NULL) { + LISTBASE_FOREACH (Collection *, coll_iter, &bmain->collections) { + if (ID_IS_LINKED(coll_iter)) { + continue; + } + LISTBASE_FOREACH (CollectionObject *, coll_ob_iter, &coll_iter->gobject) { + if (BLI_gset_haskey(user_overrides_objects_uids, + POINTER_FROM_UINT(coll_ob_iter->ob->id.session_uuid))) { + /* Tag for remapping when creating overrides. */ + coll_iter->id.tag |= LIB_TAG_DOIT; + break; + } + } + } + } + ID *id_root_override; const bool success = BKE_lib_override_library_create(bmain, scene, -- cgit v1.2.3