From 988f23cec3912dac96595c652a5f4e427d7550c8 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 14 Apr 2023 16:08:05 +0200 Subject: [PATCH] Attributes: Add 2D integer vector attribute type This type will be used to store mesh edges in #106638, but it could be used for anything else too. This commit adds support for: - The new type in the Python API - Editing the type in the edit mode "Attribute Set" operator - Rendering the type in EEVEE and Cycles for all geometry types - Geometry nodes attribute interpolation and mixing - Viewing the type in the spreadsheet and using row filters The attribute uses the `blender::int2` type in most code, and the `vec2i` DNA type in C code when necessary. The enum names are based on `INT32_2D` for consistency with `INT8` and `INT32`. Pull Request: https://projects.blender.org/blender/blender/pulls/106677 --- intern/cycles/blender/curves.cpp | 10 +++ intern/cycles/blender/mesh.cpp | 13 +++ intern/cycles/blender/pointcloud.cpp | 10 +++ .../blender/blenkernel/BKE_attribute_math.hh | 30 ++++++- .../blenkernel/intern/attribute_access.cc | 12 +-- .../blender/blenkernel/intern/customdata.cc | 9 +- source/blender/blenkernel/intern/mesh.cc | 10 +++ .../blenkernel/intern/type_conversions.cc | 82 +++++++++++++++++++ source/blender/blenlib/BLI_math_base.hh | 17 +++- source/blender/blenlib/intern/cpp_types.cc | 2 + source/blender/draw/intern/draw_attributes.cc | 3 +- .../draw/intern/draw_cache_impl_mesh.cc | 1 + .../extract_mesh_vbo_attributes.cc | 6 ++ .../editors/mesh/editmesh_attribute.cc | 18 ++++ .../node_geometry_attribute_search.cc | 1 + .../space_spreadsheet/space_spreadsheet.cc | 1 + .../space_spreadsheet/spreadsheet_column.cc | 3 + .../space_spreadsheet/spreadsheet_layout.cc | 34 ++++++++ .../spreadsheet_row_filter.cc | 30 +++++++ .../spreadsheet_row_filter_ui.cc | 9 ++ source/blender/functions/intern/cpp_types.cc | 2 + .../blender/makesdna/DNA_customdata_types.h | 6 +- source/blender/makesdna/DNA_space_types.h | 2 + source/blender/makesdna/DNA_vec_types.h | 4 +- .../blender/makesrna/intern/rna_attribute.c | 44 +++++++++- source/blender/makesrna/intern/rna_space.c | 5 ++ 26 files changed, 347 insertions(+), 17 deletions(-) diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp index f98719ff4f0..411eb16cd9d 100644 --- a/intern/cycles/blender/curves.cpp +++ b/intern/cycles/blender/curves.cpp @@ -803,6 +803,16 @@ static void attr_create_generic(Scene *scene, num_curves, num_keys, data, element, [&](int i) { return float(src[i]); }); break; } + case BL::Attribute::data_type_INT32_2D: { + BL::Int2Attribute b_int2_attribute{b_attribute}; + const int2 *src = static_cast(b_int2_attribute.data[0].ptr.data); + Attribute *attr = attributes.add(name, TypeFloat2, element); + float2 *data = attr->data_float2(); + fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) { + return make_float2(float(src[i][0]), float(src[i][1])); + }); + break; + } case BL::Attribute::data_type_FLOAT_VECTOR: { BL::FloatVectorAttribute b_vector_attribute{b_attribute}; const float(*src)[3] = static_cast(b_vector_attribute.data[0].ptr.data); diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index 7e1b73ea40b..8692e84debe 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -528,6 +528,19 @@ static void attr_create_generic(Scene *scene, }); break; } + case BL::Attribute::data_type_INT32_2D: { + BL::Int2Attribute b_int2_attribute{b_attribute}; + if (b_int2_attribute.data.length() == 0) { + continue; + } + const int2 *src = static_cast(b_int2_attribute.data[0].ptr.data); + Attribute *attr = attributes.add(name, TypeFloat2, element); + float2 *data = attr->data_float2(); + fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) { + return make_float2(float(src[i][0]), float(src[i][1])); + }); + break; + } default: /* Not supported. */ break; diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp index f8b656ce688..32caebc0358 100644 --- a/intern/cycles/blender/pointcloud.cpp +++ b/intern/cycles/blender/pointcloud.cpp @@ -102,6 +102,16 @@ static void copy_attributes(PointCloud *pointcloud, } break; } + case BL::Attribute::data_type_INT32_2D: { + BL::Int2Attribute b_int2_attribute{b_attribute}; + const int2 *src = static_cast(b_int2_attribute.data[0].ptr.data); + Attribute *attr = attributes.add(name, TypeFloat2, element); + float2 *data = attr->data_float2(); + for (int i = 0; i < num_points; i++) { + data[i] = make_float2(float(src[i][0]), float(src[i][1])); + } + break; + } case BL::Attribute::data_type_FLOAT_VECTOR: { BL::FloatVectorAttribute b_vector_attribute{b_attribute}; const float(*src)[3] = static_cast(b_vector_attribute.data[0].ptr.data); diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index ef0744f21a6..8b576f4f586 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -23,6 +23,7 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func) float2, float3, int, + int2, bool, int8_t, ColorGeometry4f, @@ -68,6 +69,11 @@ template<> inline int mix2(const float factor, const int &a, const int &b) return int(std::round((1.0f - factor) * a + factor * b)); } +template<> inline int2 mix2(const float factor, const int2 &a, const int2 &b) +{ + return math::interpolate(a, b, factor); +} + template<> inline float mix2(const float factor, const float &a, const float &b) { return (1.0f - factor) * a + factor * b; @@ -121,6 +127,11 @@ template<> inline int mix3(const float3 &weights, const int &v0, const int &v1, return int(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2)); } +template<> inline int2 mix3(const float3 &weights, const int2 &v0, const int2 &v1, const int2 &v2) +{ + return int2(weights.x * float2(v0) + weights.y * float2(v1) + weights.z * float2(v2)); +} + template<> inline float mix3(const float3 &weights, const float &v0, const float &v1, const float &v2) { @@ -194,6 +205,14 @@ inline int mix4(const float4 &weights, const int &v0, const int &v1, const int & return int(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3)); } +template<> +inline int2 mix4( + const float4 &weights, const int2 &v0, const int2 &v1, const int2 &v2, const int2 &v3) +{ + return int2(weights.x * float2(v0) + weights.y * float2(v1) + weights.z * float2(v2) + + weights.w * float2(v3)); +} + template<> inline float mix4( const float4 &weights, const float &v0, const float &v1, const float &v2, const float &v3) @@ -382,7 +401,7 @@ class SimpleMixerWithAccumulationType { private: struct Item { /* Store both values together, because they are accessed together. */ - AccumulationT value = {0}; + AccumulationT value = AccumulationT(0); float weight = 0.0f; }; @@ -517,6 +536,15 @@ template<> struct DefaultMixerStruct { * uses double instead of float so that it is accurate for all 32 bit integers. */ using type = SimpleMixerWithAccumulationType; }; +template<> struct DefaultMixerStruct { + static int2 double_to_int(const double2 &value) + { + return int2(math::round(value)); + } + /* Store interpolated ints in a double temporarily, so that weights are handled correctly. It + * uses double instead of float so that it is accurate for all 32 bit integers. */ + using type = SimpleMixerWithAccumulationType; +}; template<> struct DefaultMixerStruct { static bool float_to_bool(const float &value) { diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 55739083f1e..f016ed52fe7 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -92,17 +92,19 @@ static int attribute_data_type_complexity(const eCustomDataType data_type) return 2; case CD_PROP_FLOAT: return 3; - case CD_PROP_FLOAT2: + case CD_PROP_INT32_2D: return 4; - case CD_PROP_FLOAT3: + case CD_PROP_FLOAT2: return 5; - case CD_PROP_BYTE_COLOR: + case CD_PROP_FLOAT3: return 6; - case CD_PROP_COLOR: + case CD_PROP_BYTE_COLOR: return 7; + case CD_PROP_COLOR: + return 8; #if 0 /* These attribute types are not supported yet. */ case CD_PROP_STRING: - return 6; + return 9; #endif default: /* Only accept "generic" custom data types used by the attribute system. */ diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 28ae7bfa145..eda5e0482c0 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -1892,8 +1892,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 45: CD_PROP_INT8 */ {sizeof(int8_t), "MInt8Property", 1, N_("Int8"), nullptr, nullptr, nullptr, nullptr, nullptr}, - /* 46: CD_HAIRMAPPING */ /* UNUSED */ - {-1, "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, + /* 46: CD_PROP_INT32_2D */ + {sizeof(vec2i), "vec2i", 1, N_("Int 2D"), nullptr, nullptr, nullptr, nullptr, nullptr}, /* 47: CD_PROP_COLOR */ {sizeof(MPropCol), "MPropCol", @@ -5360,6 +5360,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type) return &CPPType::get(); case CD_PROP_INT32: return &CPPType::get(); + case CD_PROP_INT32_2D: + return &CPPType::get(); case CD_PROP_COLOR: return &CPPType::get(); case CD_PROP_BOOL: @@ -5389,6 +5391,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) if (type.is()) { return CD_PROP_INT32; } + if (type.is()) { + return CD_PROP_INT32_2D; + } if (type.is()) { return CD_PROP_COLOR; } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index b1ed15eb31b..253266c69c8 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -616,6 +616,16 @@ static int customdata_compare( BLI_edgehash_free(eh, nullptr); break; } + case CD_PROP_INT32_2D: { + const blender::int2 *l1_data = static_cast(l1->data); + const blender::int2 *l2_data = static_cast(l2->data); + for (int i = 0; i < total_length; i++) { + if (l1_data[i] != l2_data[i]) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + } + break; + } case CD_PROP_BYTE_COLOR: { MLoopCol *lp1 = (MLoopCol *)l1->data; MLoopCol *lp2 = (MLoopCol *)l2->data; diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc index f1dea155225..094fb628698 100644 --- a/source/blender/blenkernel/intern/type_conversions.cc +++ b/source/blender/blenkernel/intern/type_conversions.cc @@ -51,6 +51,10 @@ static int32_t float_to_int(const float &a) { return int32_t(a); } +static int2 float_to_int2(const float &a) +{ + return int2(a); +} static bool float_to_bool(const float &a) { return a > 0.0f; @@ -81,6 +85,10 @@ static int float2_to_int(const float2 &a) { return int32_t((a.x + a.y) / 2.0f); } +static int2 float2_to_int2(const float2 &a) +{ + return int2(a.x, a.y); +} static bool float2_to_bool(const float2 &a) { return !math::is_zero(a); @@ -114,6 +122,10 @@ static int float3_to_int(const float3 &a) { return int((a.x + a.y + a.z) / 3.0f); } +static int2 float3_to_int2(const float3 &a) +{ + return int2(a.x, a.y); +} static float2 float3_to_float2(const float3 &a) { return float2(a); @@ -136,6 +148,10 @@ static int8_t int_to_int8(const int32_t &a) return std::clamp( a, int(std::numeric_limits::min()), int(std::numeric_limits::max())); } +static int2 int_to_int2(const int32_t &a) +{ + return int2(a); +} static float int_to_float(const int32_t &a) { return float(a); @@ -157,6 +173,39 @@ static ColorGeometry4b int_to_byte_color(const int32_t &a) return int_to_color(a).encode(); } +static bool int2_to_bool(const int2 &a) +{ + return !math::is_zero(a); +} +static float2 int2_to_float2(const int2 &a) +{ + return float2(a); +} +static int int2_to_int(const int2 &a) +{ + return math::midpoint(a.x, a.y); +} +static int8_t int2_to_int8(const int2 &a) +{ + return int_to_int8(int2_to_int(a)); +} +static float int2_to_float(const int2 &a) +{ + return float2_to_float(float2(a)); +} +static float3 int2_to_float3(const int2 &a) +{ + return float3(float(a.x), float(a.y), 0.0f); +} +static ColorGeometry4f int2_to_color(const int2 &a) +{ + return ColorGeometry4f(float(a.x), float(a.y), 0.0f, 1.0f); +} +static ColorGeometry4b int2_to_byte_color(const int2 &a) +{ + return int2_to_color(a).encode(); +} + static bool int8_to_bool(const int8_t &a) { return a > 0; @@ -165,6 +214,10 @@ static int int8_to_int(const int8_t &a) { return int(a); } +static int2 int8_to_int2(const int8_t &a) +{ + return int2(a); +} static float int8_to_float(const int8_t &a) { return float(a); @@ -198,6 +251,10 @@ static int32_t bool_to_int(const bool &a) { return int32_t(a); } +static int2 bool_to_int2(const bool &a) +{ + return int2(a); +} static float2 bool_to_float2(const bool &a) { return (a) ? float2(1.0f) : float2(0.0f); @@ -227,6 +284,10 @@ static int32_t color_to_int(const ColorGeometry4f &a) { return int(rgb_to_grayscale(a)); } +static int2 color_to_int2(const ColorGeometry4f &a) +{ + return int2(a.r, a.g); +} static int8_t color_to_int8(const ColorGeometry4f &a) { return int_to_int8(color_to_int(a)); @@ -256,6 +317,10 @@ static int32_t byte_color_to_int(const ColorGeometry4b &a) { return color_to_int(a.decode()); } +static int2 byte_color_to_int2(const ColorGeometry4b &a) +{ + return int2(a.r, a.g); +} static int8_t byte_color_to_int8(const ColorGeometry4b &a) { return color_to_int8(a.decode()); @@ -280,6 +345,7 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); @@ -288,6 +354,7 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); @@ -297,20 +364,32 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); @@ -320,6 +399,7 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); @@ -329,6 +409,7 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); @@ -337,6 +418,7 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); + add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); add_implicit_conversion(conversions); diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh index 87280eead3a..9ea04d604e4 100644 --- a/source/blender/blenlib/BLI_math_base.hh +++ b/source/blender/blenlib/BLI_math_base.hh @@ -194,11 +194,22 @@ inline T interpolate(const T &a, const T &b, const FactorT &t) template inline T midpoint(const T &a, const T &b) { - auto result = (a + b) * T(0.5); if constexpr (std::is_integral_v) { - result = std::round(result); + /** See std::midpoint from C++20. */ + using Unsigned = std::make_unsigned_t; + int sign = 1; + Unsigned smaller = a; + Unsigned larger = b; + if (a > b) { + sign = -1; + smaller = b; + larger = a; + } + return a + sign * T(Unsigned(larger - smaller) / 2); + } + else { + return (a + b) * T(0.5); } - return result; } } // namespace blender::math diff --git a/source/blender/blenlib/intern/cpp_types.cc b/source/blender/blenlib/intern/cpp_types.cc index 083869c409d..573feff49b0 100644 --- a/source/blender/blenlib/intern/cpp_types.cc +++ b/source/blender/blenlib/intern/cpp_types.cc @@ -52,6 +52,7 @@ BLI_CPP_TYPE_MAKE(blender::float4x4, CPPTypeFlags::BasicType) BLI_CPP_TYPE_MAKE(int8_t, CPPTypeFlags::BasicType) BLI_CPP_TYPE_MAKE(int16_t, CPPTypeFlags::BasicType) BLI_CPP_TYPE_MAKE(int32_t, CPPTypeFlags::BasicType) +BLI_CPP_TYPE_MAKE(blender::int2, CPPTypeFlags::BasicType) BLI_CPP_TYPE_MAKE(int64_t, CPPTypeFlags::BasicType) BLI_CPP_TYPE_MAKE(uint8_t, CPPTypeFlags::BasicType) @@ -80,6 +81,7 @@ void register_cpp_types() BLI_CPP_TYPE_REGISTER(int8_t); BLI_CPP_TYPE_REGISTER(int16_t); BLI_CPP_TYPE_REGISTER(int32_t); + BLI_CPP_TYPE_REGISTER(blender::int2); BLI_CPP_TYPE_REGISTER(int64_t); BLI_CPP_TYPE_REGISTER(uint8_t); diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc index 7d2e7a7fa2d..a6755c6adea 100644 --- a/source/blender/draw/intern/draw_attributes.cc +++ b/source/blender/draw/intern/draw_attributes.cc @@ -80,9 +80,10 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data, int *r_layer_index, eCustomDataType *r_type) { - const eCustomDataType possible_attribute_types[8] = { + const eCustomDataType possible_attribute_types[9] = { CD_PROP_BOOL, CD_PROP_INT8, + CD_PROP_INT32_2D, CD_PROP_INT32, CD_PROP_FLOAT, CD_PROP_FLOAT2, diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index 484810bb8a8..5cc568fe2ab 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -395,6 +395,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, case CD_PROP_BOOL: case CD_PROP_INT8: case CD_PROP_INT32: + case CD_PROP_INT32_2D: case CD_PROP_FLOAT: case CD_PROP_FLOAT2: { if (layer != -1 && domain.has_value()) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 62c4273afc5..dc1c5335763 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -100,6 +100,7 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type) * comment #extract_attr_init. */ return 3; case CD_PROP_FLOAT2: + case CD_PROP_INT32_2D: return 2; case CD_PROP_FLOAT3: return 3; @@ -116,6 +117,7 @@ static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type) switch (type) { case CD_PROP_INT8: case CD_PROP_INT32: + case CD_PROP_INT32_2D: return GPU_FETCH_INT_TO_FLOAT; case CD_PROP_BYTE_COLOR: return GPU_FETCH_INT_TO_FLOAT_UNIT; @@ -128,6 +130,7 @@ static GPUVertCompType get_comp_type_for_type(eCustomDataType type) { switch (type) { case CD_PROP_INT8: + case CD_PROP_INT32_2D: case CD_PROP_INT32: return GPU_COMP_I32; case CD_PROP_BYTE_COLOR: @@ -299,6 +302,9 @@ static void extract_attr(const MeshRenderData *mr, case CD_PROP_INT32: extract_attr_generic(mr, vbo, request); break; + case CD_PROP_INT32_2D: + extract_attr_generic(mr, vbo, request); + break; case CD_PROP_FLOAT: extract_attr_generic(mr, vbo, request); break; diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index f9a8d551abd..8385c6194d6 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -102,6 +102,8 @@ static StringRefNull rna_property_name_for_type(const eCustomDataType type) case CD_PROP_INT8: case CD_PROP_INT32: return "value_int"; + case CD_PROP_INT32_2D: + return "value_int_vector_2d"; default: BLI_assert_unreachable(); return ""; @@ -208,6 +210,9 @@ static int mesh_set_attribute_exec(bContext *C, wmOperator *op) case CD_PROP_INT32: *static_cast(buffer) = RNA_int_get(op->ptr, prop_name.c_str()); break; + case CD_PROP_INT32_2D: + RNA_int_get_array(op->ptr, prop_name.c_str(), static_cast(buffer)); + break; default: BLI_assert_unreachable(); } @@ -320,6 +325,9 @@ static int mesh_set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent case CD_PROP_INT32: RNA_property_int_set(op->ptr, prop, *active_value.get()); break; + case CD_PROP_INT32_2D: + RNA_property_int_set_array(op->ptr, prop, *active_value.get()); + break; default: BLI_assert_unreachable(); } @@ -385,6 +393,16 @@ void MESH_OT_attribute_set(wmOperatorType *ot) -FLT_MAX, FLT_MAX); RNA_def_int(ot->srna, "value_int", 0, INT_MIN, INT_MAX, "Value", "", INT_MIN, INT_MAX); + RNA_def_int_array(ot->srna, + "value_int_vector_2d", + 2, + nullptr, + INT_MIN, + INT_MAX, + "Value", + "", + INT_MIN, + INT_MAX); RNA_def_float_color( ot->srna, "value_color", 4, color_default, -FLT_MAX, FLT_MAX, "Value", "", 0.0f, 1.0f); RNA_def_boolean(ot->srna, "value_bool", false, "Value", ""); diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 982ea27374f..01f08e1f969 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -144,6 +144,7 @@ static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType t /* Unsupported currently. */ return CD_PROP_FLOAT; case CD_PROP_FLOAT2: + case CD_PROP_INT32_2D: /* No 2D vector sockets currently. */ return CD_PROP_FLOAT3; case CD_PROP_INT8: diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 52c1fa7a3ec..3c4bb00730f 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -335,6 +335,7 @@ static float get_default_column_width(const ColumnValues &values) return float_width; case SPREADSHEET_VALUE_TYPE_FLOAT: return float_width; + case SPREADSHEET_VALUE_TYPE_INT32_2D: case SPREADSHEET_VALUE_TYPE_FLOAT2: return 2.0f * float_width; case SPREADSHEET_VALUE_TYPE_FLOAT3: diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index 078fa3c1c02..d0327cfc990 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -30,6 +30,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type) if (type.is()) { return SPREADSHEET_VALUE_TYPE_INT32; } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_INT32_2D; + } if (type.is()) { return SPREADSHEET_VALUE_TYPE_FLOAT; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 2f5ff624540..cd9fb6f5167 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -138,6 +138,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } + else if (data.type().is()) { + const int2 value = data.get(real_index); + this->draw_int_vector(params, Span(&value.x, 2)); + } else if (data.type().is()) { const float value = data.get(real_index); std::stringstream ss; @@ -311,6 +315,36 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { } } + void draw_int_vector(const CellDrawParams ¶ms, const Span values) const + { + BLI_assert(!values.is_empty()); + const float segment_width = float(params.width) / values.size(); + for (const int i : values.index_range()) { + std::stringstream ss; + const int value = values[i]; + ss << " " << value; + const std::string value_str = ss.str(); + uiBut *but = uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_NONE, + value_str.c_str(), + params.xmin + i * segment_width, + params.ymin, + segment_width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + /* Right-align Floats. */ + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); + } + } + void draw_byte_color(const CellDrawParams ¶ms, const ColorGeometry4b color) const { const ColorGeometry4f float_color = color.decode(); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 303d3f1a688..79b58c07fe8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -140,6 +140,36 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter, } } } + else if (column_data.type().is()) { + const int2 value = row_filter.value_int2; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = pow2f(row_filter.threshold); + apply_filter_operation( + column_data.typed(), + [&](const int2 cell) { return math::distance_squared(cell, value) <= threshold_sq; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed(), + [&](const int2 cell) { return cell.x > value.x && cell.y > value.y; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed(), + [&](const int2 cell) { return cell.x < value.x && cell.y < value.y; }, + prev_mask, + new_indices); + break; + } + } + } else if (column_data.type().is()) { const float2 value = row_filter.value_float2; switch (row_filter.operation) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index fa22da4f26a..5007e859a0f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -68,6 +68,11 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, result << std::fixed << row_filter.value_float; return result.str(); } + case SPREADSHEET_VALUE_TYPE_INT32_2D: { + std::ostringstream result; + result << "(" << row_filter.value_int2[0] << ", " << row_filter.value_int2[1] << ")"; + return result.str(); + } case SPREADSHEET_VALUE_TYPE_FLOAT2: { std::ostringstream result; result.precision(3); @@ -198,6 +203,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE); break; + case SPREADSHEET_VALUE_TYPE_INT32_2D: + uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); + uiItemR(layout, filter_ptr, "value_int2", 0, IFACE_("Value"), ICON_NONE); + break; case SPREADSHEET_VALUE_TYPE_FLOAT: uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE); uiItemR(layout, filter_ptr, "value_float", 0, IFACE_("Value"), ICON_NONE); diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index e7abe7899a2..e11ed0b56e1 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -17,6 +17,7 @@ FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4b); FN_FIELD_CPP_TYPE_MAKE(bool); FN_FIELD_CPP_TYPE_MAKE(int8_t); FN_FIELD_CPP_TYPE_MAKE(int32_t); +FN_FIELD_CPP_TYPE_MAKE(blender::int2); FN_FIELD_CPP_TYPE_MAKE(std::string); BLI_VECTOR_CPP_TYPE_MAKE(blender::fn::ValueOrField); @@ -31,6 +32,7 @@ void FN_register_cpp_types() FN_FIELD_CPP_TYPE_REGISTER(bool); FN_FIELD_CPP_TYPE_REGISTER(int8_t); FN_FIELD_CPP_TYPE_REGISTER(int32_t); + FN_FIELD_CPP_TYPE_REGISTER(blender::int2); FN_FIELD_CPP_TYPE_REGISTER(std::string); BLI_VECTOR_CPP_TYPE_REGISTER(blender::fn::ValueOrField); diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 4d15fbea542..305c8ecfc1d 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -165,7 +165,8 @@ typedef enum eCustomDataType { /* CD_LOCATION = 43, */ /* UNUSED */ /* CD_RADIUS = 44, */ /* UNUSED */ CD_PROP_INT8 = 45, - /* CD_HAIRMAPPING = 46, */ /* UNUSED, can be reused. */ + /* Two 32-bit signed integers. */ + CD_PROP_INT32_2D = 46, CD_PROP_COLOR = 47, CD_PROP_FLOAT3 = 48, @@ -218,6 +219,7 @@ typedef enum eCustomDataType { #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) #define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) #define CD_MASK_PROP_INT8 (1ULL << CD_PROP_INT8) +#define CD_MASK_PROP_INT32_2D (1ULL << CD_PROP_INT32_2D) #define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH) @@ -231,7 +233,7 @@ typedef enum eCustomDataType { #define CD_MASK_PROP_ALL \ (CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \ CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_PROP_BYTE_COLOR | CD_MASK_PROP_BOOL | \ - CD_MASK_PROP_INT8) + CD_MASK_PROP_INT8 | CD_MASK_PROP_INT32_2D) /* All color attributes */ #define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 2bdb3f09583..d52e265b65e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1980,6 +1980,7 @@ typedef struct SpreadsheetRowFilter { char _pad0[2]; int value_int; + int value_int2[2]; char *value_string; float value_float; float threshold; @@ -2025,6 +2026,7 @@ typedef enum eSpreadsheetColumnValueType { SPREADSHEET_VALUE_TYPE_STRING = 7, SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8, SPREADSHEET_VALUE_TYPE_INT8 = 9, + SPREADSHEET_VALUE_TYPE_INT32_2D = 10, } eSpreadsheetColumnValueType; /** diff --git a/source/blender/makesdna/DNA_vec_types.h b/source/blender/makesdna/DNA_vec_types.h index f053efff2b4..f9294ffe314 100644 --- a/source/blender/makesdna/DNA_vec_types.h +++ b/source/blender/makesdna/DNA_vec_types.h @@ -23,12 +23,12 @@ typedef struct vec2f { float x, y; } vec2f; -/* not used at the moment */ -/* typedef struct vec2i { int x, y; } vec2i; +/* not used at the moment */ +/* typedef struct vec2d { double x, y; } vec2d; diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 3aedc92a248..b669ac0c888 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -39,6 +39,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = { {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"}, {CD_PROP_INT8, "INT8", 0, "8-Bit Integer", "Smaller integer with a range from -128 to 127"}, + {CD_PROP_INT32_2D, "INT32_2D", 0, "2D Integer Vector", "32-bit signed integer vector"}, {0, NULL, 0, NULL, NULL}, }; @@ -65,7 +66,8 @@ const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = { {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"}, - {CD_PROP_INT8, "INT8", 0, "8-Bit Integer", "Smaller integer with a range from -128 to 127"}, + {CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"}, + {CD_PROP_INT32_2D, "INT32_2D", 0, "2D Integer Vector", "32-bit signed integer vector"}, {0, NULL, 0, NULL, NULL}, }; @@ -162,6 +164,8 @@ static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type) return &RNA_Float2Attribute; case CD_PROP_INT8: return &RNA_ByteIntAttribute; + case CD_PROP_INT32_2D: + return &RNA_Int2Attribute; default: return NULL; } @@ -292,6 +296,9 @@ static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRN case CD_PROP_INT8: struct_size = sizeof(int8_t); break; + case CD_PROP_INT32_2D: + struct_size = sizeof(int[2]); + break; default: struct_size = 0; length = 0; @@ -1017,6 +1024,40 @@ static void rna_def_attribute_int8(BlenderRNA *brna) prop, "rna_ByteIntAttributeValue_get", "rna_ByteIntAttributeValue_set", NULL); } +static void rna_def_attribute_int2(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "Int2Attribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text( + srna, "2D Integer Vector Attribute", "Geometry attribute that stores 2D integer vectors"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "Int2AttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "Int2AttributeValue", NULL); + RNA_def_struct_sdna(srna, "vec2i"); + RNA_def_struct_ui_text( + srna, "2D Integer Vector Attribute Value", "2D value in geometry attribute"); + + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Vector", "2D vector"); + RNA_def_property_int_sdna(prop, NULL, "x"); + RNA_def_property_array(prop, 2); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + static void rna_def_attribute_float2(BlenderRNA *brna) { StructRNA *srna; @@ -1095,6 +1136,7 @@ static void rna_def_attribute(BlenderRNA *brna) rna_def_attribute_float_color(brna); rna_def_attribute_byte_color(brna); rna_def_attribute_int(brna); + rna_def_attribute_int2(brna); rna_def_attribute_string(brna); rna_def_attribute_bool(brna); rna_def_attribute_float2(brna); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b4c1058969c..a475ccf55ba 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -8004,6 +8004,11 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna) RNA_def_property_ui_text(prop, "8-Bit Integer Value", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + prop = RNA_def_property(srna, "value_int2", PROP_INT, PROP_NONE); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "2D Vector Value", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE); RNA_def_property_ui_text(prop, "Boolean Value", "");