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
This commit is contained in:
Hans Goudey
2023-04-14 16:08:05 +02:00
committed by Hans Goudey
parent 80f3f59555
commit 988f23cec3
26 changed files with 347 additions and 17 deletions

View File

@@ -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<const int2 *>(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<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);

View File

@@ -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<const int2 *>(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;

View File

@@ -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<const int2 *>(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<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);

View File

@@ -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<int> {
* uses double instead of float so that it is accurate for all 32 bit integers. */
using type = SimpleMixerWithAccumulationType<int, double, double_to_int>;
};
template<> struct DefaultMixerStruct<int2> {
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<int2, double2, double_to_int>;
};
template<> struct DefaultMixerStruct<bool> {
static bool float_to_bool(const float &value)
{

View File

@@ -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. */

View File

@@ -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<float3>();
case CD_PROP_INT32:
return &CPPType::get<int>();
case CD_PROP_INT32_2D:
return &CPPType::get<int2>();
case CD_PROP_COLOR:
return &CPPType::get<ColorGeometry4f>();
case CD_PROP_BOOL:
@@ -5389,6 +5391,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<int>()) {
return CD_PROP_INT32;
}
if (type.is<int2>()) {
return CD_PROP_INT32_2D;
}
if (type.is<ColorGeometry4f>()) {
return CD_PROP_COLOR;
}

View File

@@ -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<const blender::int2 *>(l1->data);
const blender::int2 *l2_data = static_cast<const blender::int2 *>(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;

View File

@@ -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<int8_t>::min()), int(std::numeric_limits<int8_t>::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<float, float2, float_to_float2>(conversions);
add_implicit_conversion<float, float3, float_to_float3>(conversions);
add_implicit_conversion<float, int32_t, float_to_int>(conversions);
add_implicit_conversion<float, int2, float_to_int2>(conversions);
add_implicit_conversion<float, bool, float_to_bool>(conversions);
add_implicit_conversion<float, int8_t, float_to_int8>(conversions);
add_implicit_conversion<float, ColorGeometry4f, float_to_color>(conversions);
@@ -288,6 +354,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float2, float3, float2_to_float3>(conversions);
add_implicit_conversion<float2, float, float2_to_float>(conversions);
add_implicit_conversion<float2, int32_t, float2_to_int>(conversions);
add_implicit_conversion<float2, int2, float2_to_int2>(conversions);
add_implicit_conversion<float2, bool, float2_to_bool>(conversions);
add_implicit_conversion<float2, int8_t, float2_to_int8>(conversions);
add_implicit_conversion<float2, ColorGeometry4f, float2_to_color>(conversions);
@@ -297,20 +364,32 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<float3, int8_t, float3_to_int8>(conversions);
add_implicit_conversion<float3, float, float3_to_float>(conversions);
add_implicit_conversion<float3, int32_t, float3_to_int>(conversions);
add_implicit_conversion<float3, int2, float3_to_int2>(conversions);
add_implicit_conversion<float3, float2, float3_to_float2>(conversions);
add_implicit_conversion<float3, ColorGeometry4f, float3_to_color>(conversions);
add_implicit_conversion<float3, ColorGeometry4b, float3_to_byte_color>(conversions);
add_implicit_conversion<int32_t, bool, int_to_bool>(conversions);
add_implicit_conversion<int32_t, int8_t, int_to_int8>(conversions);
add_implicit_conversion<int32_t, int2, int_to_int2>(conversions);
add_implicit_conversion<int32_t, float, int_to_float>(conversions);
add_implicit_conversion<int32_t, float2, int_to_float2>(conversions);
add_implicit_conversion<int32_t, float3, int_to_float3>(conversions);
add_implicit_conversion<int32_t, ColorGeometry4f, int_to_color>(conversions);
add_implicit_conversion<int32_t, ColorGeometry4b, int_to_byte_color>(conversions);
add_implicit_conversion<int2, bool, int2_to_bool>(conversions);
add_implicit_conversion<int2, int8_t, int2_to_int8>(conversions);
add_implicit_conversion<int2, int, int2_to_int>(conversions);
add_implicit_conversion<int2, float, int2_to_float>(conversions);
add_implicit_conversion<int2, float2, int2_to_float2>(conversions);
add_implicit_conversion<int2, float3, int2_to_float3>(conversions);
add_implicit_conversion<int2, ColorGeometry4f, int2_to_color>(conversions);
add_implicit_conversion<int2, ColorGeometry4b, int2_to_byte_color>(conversions);
add_implicit_conversion<int8_t, bool, int8_to_bool>(conversions);
add_implicit_conversion<int8_t, int32_t, int8_to_int>(conversions);
add_implicit_conversion<int8_t, int2, int8_to_int2>(conversions);
add_implicit_conversion<int8_t, float, int8_to_float>(conversions);
add_implicit_conversion<int8_t, float2, int8_to_float2>(conversions);
add_implicit_conversion<int8_t, float3, int8_to_float3>(conversions);
@@ -320,6 +399,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<bool, float, bool_to_float>(conversions);
add_implicit_conversion<bool, int8_t, bool_to_int8>(conversions);
add_implicit_conversion<bool, int32_t, bool_to_int>(conversions);
add_implicit_conversion<bool, int2, bool_to_int2>(conversions);
add_implicit_conversion<bool, float2, bool_to_float2>(conversions);
add_implicit_conversion<bool, float3, bool_to_float3>(conversions);
add_implicit_conversion<bool, ColorGeometry4f, bool_to_color>(conversions);
@@ -329,6 +409,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<ColorGeometry4f, int8_t, color_to_int8>(conversions);
add_implicit_conversion<ColorGeometry4f, float, color_to_float>(conversions);
add_implicit_conversion<ColorGeometry4f, int32_t, color_to_int>(conversions);
add_implicit_conversion<ColorGeometry4f, int2, color_to_int2>(conversions);
add_implicit_conversion<ColorGeometry4f, float2, color_to_float2>(conversions);
add_implicit_conversion<ColorGeometry4f, float3, color_to_float3>(conversions);
add_implicit_conversion<ColorGeometry4f, ColorGeometry4b, color_to_byte_color>(conversions);
@@ -337,6 +418,7 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<ColorGeometry4b, int8_t, byte_color_to_int8>(conversions);
add_implicit_conversion<ColorGeometry4b, float, byte_color_to_float>(conversions);
add_implicit_conversion<ColorGeometry4b, int32_t, byte_color_to_int>(conversions);
add_implicit_conversion<ColorGeometry4b, int2, byte_color_to_int2>(conversions);
add_implicit_conversion<ColorGeometry4b, float2, byte_color_to_float2>(conversions);
add_implicit_conversion<ColorGeometry4b, float3, byte_color_to_float3>(conversions);
add_implicit_conversion<ColorGeometry4b, ColorGeometry4f, byte_color_to_color>(conversions);

View File

@@ -194,11 +194,22 @@ inline T interpolate(const T &a, const T &b, const FactorT &t)
template<typename T> inline T midpoint(const T &a, const T &b)
{
auto result = (a + b) * T(0.5);
if constexpr (std::is_integral_v<T>) {
result = std::round(result);
/** See std::midpoint from C++20. */
using Unsigned = std::make_unsigned_t<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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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()) {

View File

@@ -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<int32_t, int3>(mr, vbo, request);
break;
case CD_PROP_INT32_2D:
extract_attr_generic<int2>(mr, vbo, request);
break;
case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;

View File

@@ -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<int32_t *>(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<int *>(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<int32_t>());
break;
case CD_PROP_INT32_2D:
RNA_property_int_set_array(op->ptr, prop, *active_value.get<int2>());
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", "");

View File

@@ -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:

View File

@@ -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:

View File

@@ -30,6 +30,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<int>()) {
return SPREADSHEET_VALUE_TYPE_INT32;
}
if (type.is<int2>()) {
return SPREADSHEET_VALUE_TYPE_INT32_2D;
}
if (type.is<float>()) {
return SPREADSHEET_VALUE_TYPE_FLOAT;
}

View File

@@ -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<int2>()) {
const int2 value = data.get<int2>(real_index);
this->draw_int_vector(params, Span(&value.x, 2));
}
else if (data.type().is<float>()) {
const float value = data.get<float>(real_index);
std::stringstream ss;
@@ -311,6 +315,36 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
void draw_int_vector(const CellDrawParams &params, const Span<int> 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 &params, const ColorGeometry4b color) const
{
const ColorGeometry4f float_color = color.decode();

View File

@@ -140,6 +140,36 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
else if (column_data.type().is<int2>()) {
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<int2>(),
[&](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<int2>(),
[&](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<int2>(),
[&](const int2 cell) { return cell.x < value.x && cell.y < value.y; },
prev_mask,
new_indices);
break;
}
}
}
else if (column_data.type().is<float2>()) {
const float2 value = row_filter.value_float2;
switch (row_filter.operation) {

View File

@@ -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);

View File

@@ -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<std::string>);
@@ -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<std::string>);

View File

@@ -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)

View File

@@ -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;
/**

View File

@@ -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;

View File

@@ -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);

View File

@@ -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", "");