Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2020-12-17 22:28:12 +01:00
commit c0cb475689
22 changed files with 1010 additions and 218 deletions

View File

@ -483,6 +483,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeColorRamp"),
@ -510,6 +511,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
NodeItem("GeometryNodePointInstance"),
NodeItem("GeometryNodePointSeparate"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),

View File

@ -1353,6 +1353,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ATTRIBUTE_FILL 1011
#define GEO_NODE_ATTRIBUTE_MIX 1012
#define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013
#define GEO_NODE_POINT_SEPARATE 1014
#define GEO_NODE_ATTRIBUTE_COMPARE 1015
/** \} */

View File

@ -4728,6 +4728,7 @@ static void registerGeometryNodes(void)
{
register_node_type_geo_group();
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_fill();
register_node_type_geo_triangulate();
register_node_type_geo_edge_split();
@ -4736,6 +4737,7 @@ static void registerGeometryNodes(void)
register_node_type_geo_boolean();
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
register_node_type_geo_point_separate();
register_node_type_geo_object_info();
register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_math();

View File

@ -1428,5 +1428,26 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == GEO_NODE_ATTRIBUTE_MATH && node->storage == NULL) {
const int old_use_attibute_a = (1 << 0);
const int old_use_attibute_b = (1 << 1);
NodeAttributeMath *data = MEM_callocN(sizeof(NodeAttributeMath), "NodeAttributeMath");
data->operation = NODE_MATH_ADD;
data->input_type_a = (node->custom2 & old_use_attibute_a) ?
GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE :
GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_b = (node->custom2 & old_use_attibute_b) ?
GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE :
GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
}
}
}
}
FOREACH_NODETREE_END;
}
}

View File

@ -5861,7 +5861,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
ColorPicker *cpicker = but->custom_data;
float hsv_static[3] = {0.0f};
float *hsv = cpicker ? cpicker->color_data : hsv_static;
float *hsv = cpicker ? cpicker->hsv_perceptual : hsv_static;
float col[3];
ui_but_v3_get(but, col);
@ -6089,7 +6089,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but,
{
const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
float rgb[3];
float x, y;
float mx_fl, my_fl;
@ -6107,7 +6107,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but,
#endif
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv);
@ -6120,7 +6120,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but,
/* calculate original hsv again */
copy_v3_v3(rgb, data->origvec);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
copy_v3_v3(hsvo, hsv);
@ -6183,7 +6183,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but,
}
ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
ui_perceptual_to_scene_linear_space(but, rgb);
/* clamp because with color conversion we can exceed range T34295. */
if (hsv_but->gradient_type == UI_GRAD_V_ALT) {
@ -6206,13 +6206,13 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but,
const bool shift)
{
ColorPicker *cpicker = hsv_but->but.custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
const float hsv_v_max = max_ff(hsv[2], hsv_but->but.softmax);
float rgb[3];
const float sensitivity = (shift ? 0.15f : 0.3f) * ndof->dt;
ui_but_v3_get(&hsv_but->but, rgb);
ui_scene_linear_to_color_picker_space(&hsv_but->but, rgb);
ui_scene_linear_to_perceptual_space(&hsv_but->but, rgb);
ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv);
switch (hsv_but->gradient_type) {
@ -6261,7 +6261,7 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but,
hsv_clamp_v(hsv, hsv_v_max);
ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb);
ui_color_picker_to_scene_linear_space(&hsv_but->but, rgb);
ui_perceptual_to_scene_linear_space(&hsv_but->but, rgb);
copy_v3_v3(data->vec, rgb);
ui_but_v3_set(&hsv_but->but, data->vec);
@ -6318,7 +6318,7 @@ static int ui_do_but_HSVCUBE(
float rgb[3], def_hsv[3];
float def[4];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
ui_rgb_to_color_picker_HSVCUBE_v(hsv_but, def, def_hsv);
@ -6374,7 +6374,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but,
{
const bool changed = true;
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
float mx_fl, my_fl;
ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
@ -6400,8 +6400,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but,
float rgb[3];
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
/* exception, when using color wheel in 'locked' value state:
* allow choosing a hue for black values, by giving a tiny increment */
@ -6428,8 +6428,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but,
/* calculate original hsv again */
copy_v3_v3(hsvo, hsv);
copy_v3_v3(rgbo, data->origvec);
ui_scene_linear_to_color_picker_space(but, rgbo);
ui_rgb_to_color_picker_compat_v(rgbo, hsvo);
ui_scene_linear_to_perceptual_space(but, rgbo);
ui_color_picker_rgb_to_hsv_compat(rgbo, hsvo);
/* and original position */
ui_hsvcircle_pos_from_vals(cpicker, &rect, hsvo, &xpos, &ypos);
@ -6448,7 +6448,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but,
ui_color_snap_hue(snap, &hsv[0]);
}
ui_color_picker_to_rgb_v(hsv, rgb);
ui_color_picker_hsv_to_rgb(hsv, rgb);
if ((cpicker->use_luminosity_lock)) {
if (!is_zero_v3(rgb)) {
@ -6456,7 +6456,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but,
}
}
ui_color_picker_to_scene_linear_space(but, rgb);
ui_perceptual_to_scene_linear_space(but, rgb);
ui_but_v3_set(but, rgb);
data->draglastx = mx;
@ -6473,14 +6473,14 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but,
const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
float rgb[3];
float phi, r /*, sqr */ /* UNUSED */, v[2];
const float sensitivity = (shift ? 0.06f : 0.3f) * ndof->dt;
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
/* Convert current color on hue/sat disc to circular coordinates phi, r */
phi = fmodf(hsv[0] + 0.25f, 1.0f) * -2.0f * (float)M_PI;
@ -6530,7 +6530,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but,
hsv_clamp_v(hsv, FLT_MAX);
ui_color_picker_to_rgb_v(hsv, data->vec);
ui_color_picker_hsv_to_rgb(hsv, data->vec);
if (cpicker->use_luminosity_lock) {
if (!is_zero_v3(data->vec)) {
@ -6538,7 +6538,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but,
}
}
ui_color_picker_to_scene_linear_space(but, data->vec);
ui_perceptual_to_scene_linear_space(but, data->vec);
ui_but_v3_set(but, data->vec);
}
#endif /* WITH_INPUT_NDOF */
@ -6547,7 +6547,7 @@ static int ui_do_but_HSVCIRCLE(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
int mx = event->x;
int my = event->y;
ui_window_to_block(data->region, block, &mx, &my);
@ -6594,10 +6594,10 @@ static int ui_do_but_HSVCIRCLE(
def = MEM_callocN(sizeof(float) * len, "reset_defaults - float");
RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
ui_color_picker_to_rgb_v(def, def_hsv);
ui_color_picker_hsv_to_rgb(def, def_hsv);
ui_but_v3_get(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
def_hsv[0] = hsv[0];
def_hsv[2] = hsv[2];

View File

@ -378,11 +378,20 @@ typedef struct uiButExtraOpIcon {
typedef struct ColorPicker {
struct ColorPicker *next, *prev;
/** Color data, may be HSV or HSL. */
float color_data[3];
/** Initial color data (detect changes). */
float color_data_init[3];
/** Color in HSV or HSL, in color picking color space. Used for HSV cube,
* circle and slider widgets. The color picking space is perceptually
* linear for intuitive editing. */
float hsv_perceptual[3];
/** Initial color data (to detect changes). */
float hsv_perceptual_init[3];
bool is_init;
/** HSV or HSL color in scene linear color space value used for number
* buttons. This is scene linear so that there is a clear correspondence
* to the scene linear RGB values. */
float hsv_scene_linear[3];
/** Cubic saturation for the color wheel. */
bool use_color_cubic;
bool use_color_lock;
@ -734,15 +743,14 @@ struct uiPopupBlockHandle {
/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]);
void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]);
void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]);
void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b);
void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]);
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]);
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]);
bool ui_but_is_color_gamma(uiBut *but);
void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]);
void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]);
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]);
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3]);
uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, void *arg_but);
ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);

View File

@ -77,8 +77,10 @@ static void ui_color_picker_rgb_round(float rgb[3])
}
}
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3])
void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3])
{
/* Convert RGB to HSV, remaining as compatible as possible with the existing
* r_hsv value (for example when value goes to zero, preserve the hue). */
switch (U.color_picker_type) {
case USER_CP_CIRCLE_HSL:
rgb_to_hsl_compat_v(rgb, r_cp);
@ -89,7 +91,7 @@ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3])
}
}
void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3])
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3])
{
switch (U.color_picker_type) {
case USER_CP_CIRCLE_HSL:
@ -101,7 +103,7 @@ void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3])
}
}
void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3])
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
{
switch (U.color_picker_type) {
case USER_CP_CIRCLE_HSL:
@ -113,18 +115,6 @@ void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3])
}
}
void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b)
{
switch (U.color_picker_type) {
case USER_CP_CIRCLE_HSL:
hsl_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
break;
default:
hsv_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
break;
}
}
/* Returns true if the button is for a color with gamma baked in,
* or if it's a color picker for such a button. */
bool ui_but_is_color_gamma(uiBut *but)
@ -138,7 +128,7 @@ bool ui_but_is_color_gamma(uiBut *but)
return but->block->is_color_gamma_picker;
}
void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3])
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
{
/* Map to color picking space for HSV values and HSV cube/circle,
* assuming it is more perceptually linear than the scene linear
@ -149,7 +139,7 @@ void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3])
}
}
void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3])
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3])
{
if (!ui_but_is_color_gamma(but)) {
IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
@ -163,16 +153,46 @@ void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3])
/** \name Color Picker
* \{ */
static void ui_color_picker_update_hsv(ColorPicker *cpicker,
uiBut *from_but,
const float rgb_scene_linear[3])
{
/* Convert from RGB to HSV in scene linear space color for number editing. */
if (cpicker->is_init == false) {
ui_color_picker_rgb_to_hsv(rgb_scene_linear, cpicker->hsv_scene_linear);
}
else {
ui_color_picker_rgb_to_hsv_compat(rgb_scene_linear, cpicker->hsv_scene_linear);
}
/* Convert from RGB to HSV in perceptually linear space for picker widgets. */
float rgb_perceptual[3];
copy_v3_v3(rgb_perceptual, rgb_scene_linear);
if (from_but) {
ui_scene_linear_to_perceptual_space(from_but, rgb_perceptual);
}
if (cpicker->is_init == false) {
ui_color_picker_rgb_to_hsv(rgb_perceptual, cpicker->hsv_perceptual);
copy_v3_v3(cpicker->hsv_perceptual_init, cpicker->hsv_perceptual);
}
else {
ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, cpicker->hsv_perceptual);
}
cpicker->is_init = true;
}
/* for picker, while editing hsv */
void ui_but_hsv_set(uiBut *but)
{
float col[3];
float rgb_perceptual[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv_perceptual = cpicker->hsv_perceptual;
ui_color_picker_to_rgb_v(hsv, col);
ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_perceptual);
ui_but_v3_set(but, col);
ui_but_v3_set(but, rgb_perceptual);
}
/* Updates all buttons who share the same color picker as the one passed
@ -180,17 +200,9 @@ void ui_but_hsv_set(uiBut *but)
static void ui_update_color_picker_buts_rgb(uiBut *from_but,
uiBlock *block,
ColorPicker *cpicker,
const float rgb[3])
const float rgb_scene_linear[3])
{
float *hsv = cpicker->color_data;
/* Convert from RGB to HSV in perceptually linear space. */
float tmp[3];
copy_v3_v3(tmp, rgb);
if (from_but) {
ui_scene_linear_to_color_picker_space(from_but, tmp);
}
ui_rgb_to_color_picker_compat_v(tmp, hsv);
ui_color_picker_update_hsv(cpicker, from_but, rgb_scene_linear);
/* this updates button strings,
* is hackish... but button pointers are on stack of caller function */
@ -200,7 +212,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
}
if (bt->rnaprop) {
ui_but_v3_set(bt, rgb);
ui_but_v3_set(bt, rgb_scene_linear);
/* original button that created the color picker already does undo
* push, so disable it on RNA buttons in the color picker block */
@ -213,7 +225,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
/* Hex code is assumed to be in sRGB space
* (coming from other applications, web, etc) */
copy_v3_v3(rgb_hex, rgb);
copy_v3_v3(rgb_hex, rgb_scene_linear);
if (from_but && !ui_but_is_color_gamma(from_but)) {
IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
ui_color_picker_rgb_round(rgb_hex);
@ -226,25 +238,25 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
}
else if (bt->str[1] == ' ') {
if (bt->str[0] == 'R') {
ui_but_value_set(bt, rgb[0]);
ui_but_value_set(bt, rgb_scene_linear[0]);
}
else if (bt->str[0] == 'G') {
ui_but_value_set(bt, rgb[1]);
ui_but_value_set(bt, rgb_scene_linear[1]);
}
else if (bt->str[0] == 'B') {
ui_but_value_set(bt, rgb[2]);
ui_but_value_set(bt, rgb_scene_linear[2]);
}
else if (bt->str[0] == 'H') {
ui_but_value_set(bt, hsv[0]);
ui_but_value_set(bt, cpicker->hsv_scene_linear[0]);
}
else if (bt->str[0] == 'S') {
ui_but_value_set(bt, hsv[1]);
ui_but_value_set(bt, cpicker->hsv_scene_linear[1]);
}
else if (bt->str[0] == 'V') {
ui_but_value_set(bt, hsv[2]);
ui_but_value_set(bt, cpicker->hsv_scene_linear[2]);
}
else if (bt->str[0] == 'L') {
ui_but_value_set(bt, hsv[2]);
ui_but_value_set(bt, cpicker->hsv_scene_linear[2]);
}
}
@ -252,17 +264,17 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
}
}
static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
static void ui_colorpicker_rgba_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
PropertyRNA *prop = but->rnaprop;
PointerRNA ptr = but->rnapoin;
float rgb[4];
float rgb_scene_linear[4];
if (prop) {
RNA_property_float_get_array(&ptr, prop, rgb);
ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb);
RNA_property_float_get_array(&ptr, prop, rgb_scene_linear);
ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb_scene_linear);
}
if (popup) {
@ -270,20 +282,15 @@ static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a
}
}
static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
static void ui_colorpicker_hsv_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
{
uiBut *but = (uiBut *)bt1;
uiPopupBlockHandle *popup = but->block->handle;
float rgb[3];
float rgb_scene_linear[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
ui_color_picker_to_rgb_v(hsv, rgb);
/* hsv is saved in perceptually linear space so convert back */
ui_color_picker_to_scene_linear_space(but, rgb);
ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
ui_color_picker_hsv_to_rgb(cpicker->hsv_scene_linear, rgb_scene_linear);
ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb_scene_linear);
if (popup) {
popup->menuretval = UI_RETURN_UPDATE;
@ -321,7 +328,7 @@ static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
if (popup) {
ColorPicker *cpicker = but->custom_data;
BLI_assert(cpicker->is_init);
popup->menuretval = (equals_v3v3(cpicker->color_data, cpicker->color_data_init) ?
popup->menuretval = (equals_v3v3(cpicker->hsv_perceptual, cpicker->hsv_perceptual_init) ?
UI_RETURN_CANCEL :
UI_RETURN_OK);
}
@ -331,12 +338,12 @@ static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormod
{
/* tag buttons */
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
if ((bt->func == ui_colorpicker_rgba_update_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
(bt->rnaindex != 3)) {
/* RGB sliders (color circle and alpha are always shown) */
SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_RGB), UI_HIDDEN);
}
else if (bt->func == ui_color_wheel_rna_cb) {
else if (bt->func == ui_colorpicker_hsv_update_cb) {
/* HSV sliders */
SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HSV), UI_HIDDEN);
}
@ -386,7 +393,7 @@ static void ui_colorpicker_circle(uiBlock *block,
0.0,
0,
TIP_("Color"));
UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL);
bt->custom_data = cpicker;
/* value */
@ -408,7 +415,7 @@ static void ui_colorpicker_circle(uiBlock *block,
0,
"Lightness");
hsv_but->gradient_type = UI_GRAD_L_ALT;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL);
}
else {
hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
@ -428,7 +435,7 @@ static void ui_colorpicker_circle(uiBlock *block,
0,
TIP_("Value"));
hsv_but->gradient_type = UI_GRAD_V_ALT;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL);
}
hsv_but->but.custom_data = cpicker;
}
@ -461,7 +468,7 @@ static void ui_colorpicker_square(uiBlock *block,
0,
TIP_("Color"));
hsv_but->gradient_type = type;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL);
hsv_but->but.custom_data = cpicker;
/* value */
@ -482,12 +489,15 @@ static void ui_colorpicker_square(uiBlock *block,
0,
TIP_("Value"));
hsv_but->gradient_type = type + 3;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL);
hsv_but->but.custom_data = cpicker;
}
/* a HS circle, V slider, rgb/hsv/hex sliders */
static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker)
static void ui_block_colorpicker(uiBlock *block,
uiBut *from_but,
float rgba_scene_linear[4],
bool show_picker)
{
/* ePickerType */
static char colormode = 1;
@ -497,7 +507,6 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
float softmin, softmax, hardmin, hardmax, step, precision;
int yco;
ColorPicker *cpicker = ui_block_colorpicker_create(block);
float *hsv = cpicker->color_data;
PointerRNA *ptr = &from_but->rnapoin;
PropertyRNA *prop = from_but->rnaprop;
@ -505,20 +514,13 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
butwidth = width - 1.5f * UI_UNIT_X;
/* sneaky way to check for alpha */
rgba[3] = FLT_MAX;
rgba_scene_linear[3] = FLT_MAX;
RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_get_array(ptr, prop, rgba);
RNA_property_float_get_array(ptr, prop, rgba_scene_linear);
float rgb_perceptual[3];
copy_v3_v3(rgb_perceptual, rgba);
ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual);
ui_rgb_to_color_picker_v(rgb_perceptual, hsv);
if (cpicker->is_init == false) {
copy_v3_v3(cpicker->color_data_init, cpicker->color_data);
cpicker->is_init = true;
}
ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear);
/* when the softmax isn't defined in the RNA,
* using very large numbers causes sRGB/linear round trip to fail. */
@ -639,7 +641,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
0,
3,
TIP_("Red"));
UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL);
bt->custom_data = cpicker;
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
@ -657,7 +659,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
0,
3,
TIP_("Green"));
UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL);
bt->custom_data = cpicker;
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
@ -675,7 +677,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
0,
3,
TIP_("Blue"));
UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL);
bt->custom_data = cpicker;
/* Could use:
@ -693,14 +695,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
yco,
butwidth,
UI_UNIT_Y,
hsv,
cpicker->hsv_scene_linear,
0.0,
1.0,
10,
3,
TIP_("Hue"));
UI_but_flag_disable(bt, UI_BUT_UNDO);
UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL);
bt->custom_data = cpicker;
bt = uiDefButF(block,
UI_BTYPE_NUM_SLIDER,
@ -710,14 +712,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
yco -= UI_UNIT_Y,
butwidth,
UI_UNIT_Y,
hsv + 1,
cpicker->hsv_scene_linear + 1,
0.0,
1.0,
10,
3,
TIP_("Saturation"));
UI_but_flag_disable(bt, UI_BUT_UNDO);
UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL);
bt->custom_data = cpicker;
if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
bt = uiDefButF(block,
@ -728,7 +730,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
yco -= UI_UNIT_Y,
butwidth,
UI_UNIT_Y,
hsv + 2,
cpicker->hsv_scene_linear + 2,
0.0,
1.0,
10,
@ -744,7 +746,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
yco -= UI_UNIT_Y,
butwidth,
UI_UNIT_Y,
hsv + 2,
cpicker->hsv_scene_linear + 2,
0.0,
softmax,
10,
@ -754,12 +756,12 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
UI_but_flag_disable(bt, UI_BUT_UNDO);
bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */
UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL);
bt->custom_data = cpicker;
UI_block_align_end(block);
if (rgba[3] != FLT_MAX) {
if (rgba_scene_linear[3] != FLT_MAX) {
bt = uiDefButR_prop(block,
UI_BTYPE_NUM_SLIDER,
0,
@ -776,18 +778,18 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4],
0,
3,
TIP_("Alpha"));
UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL);
bt->custom_data = cpicker;
}
else {
rgba[3] = 1.0f;
rgba_scene_linear[3] = 1.0f;
}
/* Hex color is in sRGB space. */
float rgb_hex[3];
uchar rgb_hex_uchar[3];
copy_v3_v3(rgb_hex, rgba);
copy_v3_v3(rgb_hex, rgba_scene_linear);
if (!ui_but_is_color_gamma(from_but)) {
IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
@ -850,21 +852,22 @@ static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C),
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) {
uiPopupBlockHandle *popup = block->handle;
float rgb[3];
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv_perceptual = cpicker->hsv_perceptual;
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
float rgb_perceptual[3];
ui_but_v3_get(but, rgb_perceptual);
ui_scene_linear_to_perceptual_space(but, rgb_perceptual);
ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, hsv_perceptual);
hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f);
hsv_perceptual[2] = clamp_f(hsv_perceptual[2] + add, 0.0f, 1.0f);
ui_color_picker_to_rgb_v(hsv, rgb);
ui_color_picker_to_scene_linear_space(but, rgb);
ui_but_v3_set(but, rgb);
float rgb_scene_linear[3];
ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_scene_linear);
ui_perceptual_to_scene_linear_space(but, rgb_scene_linear);
ui_but_v3_set(but, rgb_scene_linear);
ui_update_color_picker_buts_rgb(but, block, cpicker, rgb);
ui_update_color_picker_buts_rgb(but, block, cpicker, rgb_scene_linear);
if (popup) {
popup->menuretval = UI_RETURN_UPDATE;
}

View File

@ -2906,12 +2906,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
const bool is_color_gamma = ui_but_is_color_gamma(but);
/* Initialize for compatibility. */
copy_v3_v3(hsv, cpicker->color_data);
copy_v3_v3(hsv, cpicker->hsv_perceptual);
/* Compute current hue. */
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
@ -2928,8 +2928,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
}
const float hsv_center[3] = {0.0f, 0.0f, hsv[2]};
ui_color_picker_to_rgb_v(hsv_center, rgb_center);
ui_color_picker_to_scene_linear_space(but, rgb_center);
ui_color_picker_hsv_to_rgb(hsv_center, rgb_center);
ui_perceptual_to_scene_linear_space(but, rgb_center);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_center);
@ -2956,8 +2956,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1);
hsv_ang[2] = hsv[2];
ui_color_picker_to_rgb_v(hsv_ang, rgb_ang);
ui_color_picker_to_scene_linear_space(but, rgb_ang);
ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang);
ui_perceptual_to_scene_linear_space(but, rgb_ang);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_ang);
@ -2987,10 +2987,10 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
GPU_line_smooth(false);
/* cursor */
copy_v3_v3(hsv, cpicker->color_data);
copy_v3_v3(hsv, cpicker->hsv_perceptual);
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_rgb_to_color_picker_compat_v(rgb, hsv);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
float xpos, ypos;
ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
@ -3212,14 +3212,14 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
float rgb[3];
float x = 0.0f, y = 0.0f;
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
float *hsv = cpicker->hsv_perceptual;
float hsv_n[3];
/* Initialize for compatibility. */
copy_v3_v3(hsv_n, hsv);
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
rgb_to_hsv_compat_v(rgb, hsv_n);
ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f);
@ -3251,7 +3251,7 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
float rgb[3], hsv[3], v;
ui_but_v3_get(but, rgb);
ui_scene_linear_to_color_picker_space(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
if (hsv_but->gradient_type == UI_GRAD_L_ALT) {
rgb_to_hsl_v(rgb, hsv);

View File

@ -3149,6 +3149,15 @@ static void node_geometry_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_geometry_buts_attribute_compare(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE);
uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
}
static void node_geometry_buts_subdivision_surface(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *UNUSED(ptr))
@ -3240,6 +3249,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_ATTRIBUTE_MATH:
ntype->draw_buttons = node_geometry_buts_attribute_math;
break;
case GEO_NODE_ATTRIBUTE_COMPARE:
ntype->draw_buttons = node_geometry_buts_attribute_compare;
break;
case GEO_NODE_POINT_INSTANCE:
ntype->draw_buttons = node_geometry_buts_point_instance;
break;

View File

@ -220,7 +220,7 @@ typedef enum CustomDataType {
/* All generic attributes. */
#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_MLOOPCOL)
CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL)
typedef struct CustomData_MeshMasks {
uint64_t vmask;

View File

@ -1074,6 +1074,28 @@ typedef struct NodeDenoise {
char _pad[7];
} NodeDenoise;
typedef struct NodeAttributeCompare {
/* FloatCompareOperation. */
uint8_t operation;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_a;
uint8_t input_type_b;
char _pad[5];
} NodeAttributeCompare;
typedef struct NodeAttributeMath {
/* e.g. NODE_MATH_ADD. */
uint8_t operation;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_a;
uint8_t input_type_b;
char _pad[5];
} NodeAttributeMath;
typedef struct NodeAttributeMix {
/* e.g. MA_RAMP_BLEND. */
uint8_t blend_type;
@ -1365,14 +1387,14 @@ enum {
};
/* Float compare node operations. */
enum {
typedef enum FloatCompareOperation {
NODE_FLOAT_COMPARE_LESS_THAN = 0,
NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
NODE_FLOAT_COMPARE_GREATER_THAN = 2,
NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
NODE_FLOAT_COMPARE_EQUAL = 4,
NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
};
} FloatCompareOperation;
/* Clamp node types. */
enum {
@ -1488,11 +1510,6 @@ typedef enum GeometryNodeTriangulateQuads {
GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE = 3,
} GeometryNodeTriangulateQuads;
typedef enum GeometryNodeUseAttributeFlag {
GEO_NODE_USE_ATTRIBUTE_A = (1 << 0),
GEO_NODE_USE_ATTRIBUTE_B = (1 << 1),
} GeometryNodeUseAttributeFlag;
typedef enum GeometryNodePointInstanceType {
GEO_NODE_POINT_INSTANCE_TYPE_OBJECT = 0,
GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1,
@ -1503,6 +1520,7 @@ typedef enum GeometryNodeAttributeInputMode {
GEO_NODE_ATTRIBUTE_INPUT_FLOAT = 1,
GEO_NODE_ATTRIBUTE_INPUT_VECTOR = 2,
GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3,
GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN = 4,
} GeometryNodeAttributeInputMode;
typedef enum GeometryNodePointDistributeMethod {

View File

@ -426,31 +426,53 @@ static const EnumPropertyItem rna_node_geometry_triangulate_ngon_method_items[]
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_a_items[] = {
{0, "FLOAT", 0, "Float", ""},
{GEO_NODE_USE_ATTRIBUTE_A, "ATTRIBUTE", 0, "Attribute", ""},
# define ITEM_ATTRIBUTE \
{ \
GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE, "ATTRIBUTE", 0, "Attribute", "" \
}
# define ITEM_FLOAT \
{ \
GEO_NODE_ATTRIBUTE_INPUT_FLOAT, "FLOAT", 0, "Float", "" \
}
# define ITEM_VECTOR \
{ \
GEO_NODE_ATTRIBUTE_INPUT_VECTOR, "VECTOR", 0, "Vector", "" \
}
# define ITEM_COLOR \
{ \
GEO_NODE_ATTRIBUTE_INPUT_COLOR, "COLOR", 0, "Color", "" \
}
# define ITEM_BOOLEAN \
{ \
GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN, "BOOLEAN", 0, "Boolean", "" \
}
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float[] = {
ITEM_ATTRIBUTE,
ITEM_FLOAT,
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = {
ITEM_ATTRIBUTE,
ITEM_FLOAT,
ITEM_VECTOR,
ITEM_COLOR,
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_any[] = {
ITEM_ATTRIBUTE,
ITEM_FLOAT,
ITEM_VECTOR,
ITEM_COLOR,
ITEM_BOOLEAN,
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_b_items[] = {
{0, "FLOAT", 0, "Float", ""},
{GEO_NODE_USE_ATTRIBUTE_B, "ATTRIBUTE", 0, "Attribute", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_factor_input_type_items[] = {
{GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE, "ATTRIBUTE", 0, "Attribute", ""},
{GEO_NODE_ATTRIBUTE_INPUT_FLOAT, "FLOAT", 0, "Float", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_geometry_attribute_input_type_items[] = {
{GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE, "ATTRIBUTE", 0, "Attribute", ""},
{GEO_NODE_ATTRIBUTE_INPUT_FLOAT, "FLOAT", 0, "Float", ""},
{GEO_NODE_ATTRIBUTE_INPUT_VECTOR, "VECTOR", 0, "Vector", ""},
{GEO_NODE_ATTRIBUTE_INPUT_COLOR, "COLOR", 0, "Color", ""},
{0, NULL, 0, NULL, NULL},
};
# undef ITEM_ATTRIBUTE
# undef ITEM_FLOAT
# undef ITEM_VECTOR
# undef ITEM_COLOR
# undef ITEM_BOOLEAN
static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] = {
{GEO_NODE_POINT_DISTRIBUTE_RANDOM,
@ -8420,8 +8442,10 @@ static void def_geo_attribute_math(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeAttributeMath", "storage");
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_sdna(prop, NULL, "operation");
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf");
RNA_def_property_enum_default(prop, NODE_MATH_ADD);
@ -8429,14 +8453,14 @@ static void def_geo_attribute_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_a_items);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type A", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_b_items);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_b");
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
@ -8480,17 +8504,40 @@ static void def_geo_attribute_mix(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "input_type_factor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_factor_input_type_items);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type Factor", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
RNA_def_property_ui_text(prop, "Input Type A", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_attribute_attribute_compare(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeAttributeCompare", "storage");
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
RNA_def_property_enum_default(prop, NODE_MATH_ADD);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
RNA_def_property_ui_text(prop, "Input Type A", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}

View File

@ -139,6 +139,7 @@ set(SRC
function/node_function_util.cc
geometry/nodes/node_geo_attribute_color_ramp.cc
geometry/nodes/node_geo_attribute_compare.cc
geometry/nodes/node_geo_attribute_fill.cc
geometry/nodes/node_geo_attribute_math.cc
geometry/nodes/node_geo_attribute_randomize.cc
@ -151,6 +152,7 @@ set(SRC
geometry/nodes/node_geo_point_distribute.cc
geometry/nodes/node_geo_point_distribute_poisson_disk.cc
geometry/nodes/node_geo_point_instance.cc
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc

View File

@ -38,6 +38,8 @@ void register_node_type_geo_object_info(void);
void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_math(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_point_separate(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_color_ramp(void);

View File

@ -36,6 +36,7 @@ struct FloatMathOperationInfo {
};
const FloatMathOperationInfo *get_float_math_operation_info(const int operation);
const FloatMathOperationInfo *get_float_compare_operation_info(const int operation);
/**
* This calls the `callback` with two arguments:
@ -197,4 +198,37 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
return false;
}
/**
* This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature.
*/
template<typename Callback>
inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation,
Callback &&callback)
{
const FloatMathOperationInfo *info = get_float_compare_operation_info(operation);
if (info == nullptr) {
return false;
}
/* This is just an utility function to keep the individual cases smaller. */
auto dispatch = [&](auto math_function) -> bool {
callback(math_function, *info);
return true;
};
switch (operation) {
case NODE_FLOAT_COMPARE_LESS_THAN:
return dispatch([](float a, float b) { return a < b; });
case NODE_FLOAT_COMPARE_LESS_EQUAL:
return dispatch([](float a, float b) { return a <= b; });
case NODE_FLOAT_COMPARE_GREATER_THAN:
return dispatch([](float a, float b) { return a > b; });
case NODE_FLOAT_COMPARE_GREATER_EQUAL:
return dispatch([](float a, float b) { return a >= b; });
default:
return false;
}
return false;
}
} // namespace blender::nodes

View File

@ -280,6 +280,8 @@ DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry,
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "")
DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "")
/* undefine macros */
#undef DefNode

View File

@ -36,6 +36,48 @@ void update_attribute_input_socket_availabilities(bNode &node,
}
}
static int attribute_data_type_complexity(const CustomDataType data_type)
{
switch (data_type) {
case CD_PROP_BOOL:
return 0;
case CD_PROP_INT32:
return 1;
case CD_PROP_FLOAT:
return 2;
case CD_PROP_FLOAT3:
return 4;
case CD_PROP_COLOR:
return 5;
#if 0 /* Attribute types are not supported yet. */
case CD_MLOOPCOL:
return 3;
case CD_PROP_STRING:
return 6;
#endif
default:
/* Only accept "generic" custom data types used by the attribute system. */
BLI_assert(false);
return 0;
}
}
CustomDataType attribute_domain_highest_complexity(Span<CustomDataType> data_types)
{
int highest_complexity = INT_MIN;
CustomDataType most_complex_type = CD_PROP_COLOR;
for (const CustomDataType data_type : data_types) {
const int complexity = attribute_data_type_complexity(data_type);
if (complexity > highest_complexity) {
highest_complexity = complexity;
most_complex_type = data_type;
}
}
return most_complex_type;
}
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)

View File

@ -43,6 +43,8 @@ void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode);
CustomDataType attribute_domain_highest_complexity(Span<CustomDataType>);
void poisson_disk_point_elimination(Vector<float3> const *input_points,
Vector<float3> *output_points,
float maximum_distance,

View File

@ -0,0 +1,362 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "node_geometry_util.hh"
#include "BKE_attribute.h"
#include "BKE_attribute_access.hh"
#include "BLI_array.hh"
#include "BLI_math_base_safe.h"
#include "BLI_rand.hh"
#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
#include "NOD_math_functions.hh"
static bNodeSocketTemplate geo_node_attribute_compare_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("A")},
{SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
{SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
{SOCK_RGBA, N_("A"), 0.5, 0.5, 0.5, 1.0},
{SOCK_STRING, N_("B")},
{SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
{SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
{SOCK_RGBA, N_("B"), 0.5, 0.5, 0.5, 1.0},
{SOCK_FLOAT, N_("Threshold"), 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
{SOCK_STRING, N_("Result")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_attribute_compare_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
"attribute mix node");
data->operation = NODE_FLOAT_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
static bool operation_tests_equality(const NodeAttributeCompare &node_storage)
{
return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL);
}
namespace blender::nodes {
static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage;
update_attribute_input_socket_availabilities(
*node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
update_attribute_input_socket_availabilities(
*node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9);
nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage));
}
static void do_math_operation(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
const FloatCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
Span<float> span_a = input_a.get_span();
Span<float> span_b = input_b.get_span();
if (try_dispatch_float_math_fl_fl_to_bool(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
for (const int i : IndexRange(size)) {
const float a = span_a[i];
const float b = span_b[i];
const bool out = math_function(a, b);
span_result[i] = out;
}
})) {
return;
}
/* The operation is not supported by this node currently. */
BLI_assert(false);
}
static void do_equal_operation(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const float a = input_a[i];
const float b = input_b[i];
span_result[i] = compare_ff(a, b, threshold);
}
}
static void do_equal_operation(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const float3 a = input_a[i];
const float3 b = input_b[i];
span_result[i] = len_squared_v3v3(a, b) < threshold_squared;
}
}
static void do_equal_operation(const Color4fReadAttribute &input_a,
const Color4fReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const Color4f a = input_a[i];
const Color4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) < threshold_squared;
}
}
static void do_equal_operation(const BooleanReadAttribute &input_a,
const BooleanReadAttribute &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const bool a = input_a[i];
const bool b = input_b[i];
span_result[i] = a == b;
}
}
static void do_not_equal_operation(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const float a = input_a[i];
const float b = input_b[i];
span_result[i] = !compare_ff(a, b, threshold);
}
}
static void do_not_equal_operation(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const float3 a = input_a[i];
const float3 b = input_b[i];
span_result[i] = len_squared_v3v3(a, b) >= threshold_squared;
}
}
static void do_not_equal_operation(const Color4fReadAttribute &input_a,
const Color4fReadAttribute &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const Color4f a = input_a[i];
const Color4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) >= threshold_squared;
}
}
static void do_not_equal_operation(const BooleanReadAttribute &input_a,
const BooleanReadAttribute &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
const int size = input_a.size();
for (const int i : IndexRange(size)) {
const bool a = input_a[i];
const bool b = input_b[i];
span_result[i] = a != b;
}
}
static CustomDataType get_data_type(GeometryComponent &component,
const GeoNodeExecParams &params,
const NodeAttributeCompare &node_storage)
{
if (operation_tests_equality(node_storage)) {
CustomDataType data_type_a = params.get_input_attribute_data_type(
"A", component, CD_PROP_FLOAT);
CustomDataType data_type_b = params.get_input_attribute_data_type(
"B", component, CD_PROP_FLOAT);
/* Convert the input attributes to the same data type for the equality tests. Use the higher
* complexity attribute type, otherwise information necessary to the comparison may be lost. */
return attribute_domain_highest_complexity({data_type_a, data_type_b});
}
/* Use float compare for every operation besides equality. */
return CD_PROP_FLOAT;
}
static void attribute_compare_calc(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
const FloatCompareOperation operation = static_cast<FloatCompareOperation>(
node_storage->operation);
/* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_BOOL;
/* The result domain is always point for now. */
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
const std::string result_name = params.get_input<std::string>("Result");
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
}
const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, input_data_type, nullptr);
ReadAttributePtr attribute_b = params.get_input_attribute(
"B", component, result_domain, input_data_type, nullptr);
if (!attribute_a || !attribute_b) {
/* Attribute wasn't found. */
return;
}
BooleanWriteAttribute attribute_result_bool = std::move(attribute_result);
MutableSpan<bool> result_span = attribute_result_bool.get_span();
/* Use specific types for correct equality operations, but for other operations we use implicit
* conversions and float comparison. In other words, the comparison is not element-wise. */
if (operation_tests_equality(*node_storage)) {
const float threshold = params.get_input<float>("Threshold");
if (operation == NODE_FLOAT_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
FloatReadAttribute attribute_a_float = std::move(attribute_a);
FloatReadAttribute attribute_b_float = std::move(attribute_b);
do_equal_operation(
std::move(attribute_a_float), std::move(attribute_b_float), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
Float3ReadAttribute attribute_a_float3 = std::move(attribute_a);
Float3ReadAttribute attribute_b_float3 = std::move(attribute_b);
do_equal_operation(
std::move(attribute_a_float3), std::move(attribute_b_float3), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
Color4fReadAttribute attribute_a_color = std::move(attribute_a);
Color4fReadAttribute attribute_b_color = std::move(attribute_b);
do_equal_operation(
std::move(attribute_a_color), std::move(attribute_b_color), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
BooleanReadAttribute attribute_a_bool = std::move(attribute_a);
BooleanReadAttribute attribute_b_bool = std::move(attribute_b);
do_equal_operation(
std::move(attribute_a_bool), std::move(attribute_b_bool), threshold, result_span);
}
}
else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
FloatReadAttribute attribute_a_float = std::move(attribute_a);
FloatReadAttribute attribute_b_float = std::move(attribute_b);
do_not_equal_operation(
std::move(attribute_a_float), std::move(attribute_b_float), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
Float3ReadAttribute attribute_a_float3 = std::move(attribute_a);
Float3ReadAttribute attribute_b_float3 = std::move(attribute_b);
do_not_equal_operation(
std::move(attribute_a_float3), std::move(attribute_b_float3), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
Color4fReadAttribute attribute_a_color = std::move(attribute_a);
Color4fReadAttribute attribute_b_color = std::move(attribute_b);
do_not_equal_operation(
std::move(attribute_a_color), std::move(attribute_b_color), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
BooleanReadAttribute attribute_a_bool = std::move(attribute_a);
BooleanReadAttribute attribute_b_bool = std::move(attribute_b);
do_not_equal_operation(
std::move(attribute_a_bool), std::move(attribute_b_bool), threshold, result_span);
}
}
}
else {
do_math_operation(std::move(attribute_a), std::move(attribute_b), operation, result_span);
}
attribute_result_bool.apply_span();
}
static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
if (geometry_set.has<MeshComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
}
if (geometry_set.has<PointCloudComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params);
}
params.set_output("Geometry", geometry_set);
}
} // namespace blender::nodes
void register_node_type_geo_attribute_compare()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
node_type_socket_templates(
&ntype, geo_node_attribute_compare_in, geo_node_attribute_compare_out);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec;
node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update);
node_type_storage(
&ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage);
node_type_init(&ntype, geo_node_attribute_compare_init);
nodeRegisterType(&ntype);
}

View File

@ -30,9 +30,9 @@
static bNodeSocketTemplate geo_node_attribute_math_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Attribute A")},
{SOCK_STRING, N_("A")},
{SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("Attribute B")},
{SOCK_STRING, N_("B")},
{SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("Result")},
{-1, ""},
@ -45,27 +45,27 @@ static bNodeSocketTemplate geo_node_attribute_math_out[] = {
static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = NODE_MATH_ADD;
node->custom2 = GEO_NODE_USE_ATTRIBUTE_A | GEO_NODE_USE_ATTRIBUTE_B;
}
NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath),
"NodeAttributeMath");
static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock_attribute_a = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *sock_float_a = sock_attribute_a->next;
bNodeSocket *sock_attribute_b = sock_float_a->next;
bNodeSocket *sock_float_b = sock_attribute_b->next;
GeometryNodeUseAttributeFlag flag = static_cast<GeometryNodeUseAttributeFlag>(node->custom2);
nodeSetSocketAvailability(sock_attribute_a, flag & GEO_NODE_USE_ATTRIBUTE_A);
nodeSetSocketAvailability(sock_attribute_b, flag & GEO_NODE_USE_ATTRIBUTE_B);
nodeSetSocketAvailability(sock_float_a, !(flag & GEO_NODE_USE_ATTRIBUTE_A));
nodeSetSocketAvailability(sock_float_b, !(flag & GEO_NODE_USE_ATTRIBUTE_B));
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
namespace blender::nodes {
static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
update_attribute_input_socket_availabilities(
*node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
update_attribute_input_socket_availabilities(
*node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
}
static void do_math_operation(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
FloatWriteAttribute result,
@ -112,23 +112,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
return;
}
GeometryNodeUseAttributeFlag flag = static_cast<GeometryNodeUseAttributeFlag>(node.custom2);
auto get_input_attribute = [&](GeometryNodeUseAttributeFlag use_flag,
StringRef attribute_socket_identifier,
StringRef value_socket_identifier) {
if (flag & use_flag) {
const std::string attribute_name = params.get_input<std::string>(
attribute_socket_identifier);
return component.attribute_try_get_for_read(attribute_name, result_domain, result_type);
}
const float value = params.get_input<float>(value_socket_identifier);
return component.attribute_get_constant_for_read(result_domain, result_type, &value);
};
ReadAttributePtr attribute_a = get_input_attribute(GEO_NODE_USE_ATTRIBUTE_A, "Attribute A", "A");
ReadAttributePtr attribute_b = get_input_attribute(GEO_NODE_USE_ATTRIBUTE_B, "Attribute B", "B");
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
ReadAttributePtr attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
if (!attribute_a || !attribute_b) {
/* Attribute wasn't found. */
return;
@ -161,7 +148,9 @@ void register_node_type_geo_attribute_math()
geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
node_type_socket_templates(&ntype, geo_node_attribute_math_in, geo_node_attribute_math_out);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec;
node_type_update(&ntype, geo_node_attribute_math_update);
node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update);
node_type_init(&ntype, geo_node_attribute_math_init);
node_type_storage(
&ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,212 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_mesh.h"
#include "BKE_persistent_data_handle.hh"
#include "BKE_pointcloud.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_point_instance_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Mask")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_point_instance_out[] = {
{SOCK_GEOMETRY, N_("Geometry 1")},
{SOCK_GEOMETRY, N_("Geometry 2")},
{-1, ""},
};
namespace blender::nodes {
static void fill_new_attribute_from_input(ReadAttributePtr input_attribute,
WriteAttributePtr out_attribute_a,
WriteAttributePtr out_attribute_b,
Span<bool> a_or_b)
{
fn::GSpan in_span = input_attribute->get_span();
int i_a = 0;
int i_b = 0;
for (int i_in = 0; i_in < in_span.size(); i_in++) {
const bool move_to_b = a_or_b[i_in];
if (move_to_b) {
out_attribute_b->set(i_b, in_span[i_in]);
i_b++;
}
else {
out_attribute_a->set(i_a, in_span[i_in]);
i_a++;
}
}
}
/**
* Move the original attribute values to the two output components.
*
* \note This assumes a consistent ordering of indices before and after the split,
* which is true for points and a simple vertex array.
*/
static void move_split_attributes(const GeometryComponent &in_component,
GeometryComponent &out_component_a,
GeometryComponent &out_component_b,
Span<bool> a_or_b)
{
Set<std::string> attribute_names = in_component.attribute_names();
for (const std::string &name : attribute_names) {
ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name);
BLI_assert(attribute);
/* Since this node only creates points and vertices, don't copy other attributes. */
if (attribute->domain() != ATTR_DOMAIN_POINT) {
continue;
}
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type());
const AttributeDomain domain = attribute->domain();
/* Don't try to create the attribute on the new component if it already exists. Built-in
* attributes will already exist on new components by definition. It should always be possible
* to recreate the attribute on the same component type. Also, if one of the new components
* has the attribute the other one should have it too, but check independently to be safe. */
if (!out_component_a.attribute_exists(name)) {
if (!out_component_a.attribute_try_create(name, domain, data_type)) {
BLI_assert(false);
continue;
}
}
if (!out_component_b.attribute_exists(name)) {
if (!out_component_b.attribute_try_create(name, domain, data_type)) {
BLI_assert(false);
continue;
}
}
WriteAttributePtr out_attribute_a = out_component_a.attribute_try_get_for_write(name);
WriteAttributePtr out_attribute_b = out_component_b.attribute_try_get_for_write(name);
if (!out_attribute_a || !out_attribute_b) {
BLI_assert(false);
continue;
}
fill_new_attribute_from_input(
std::move(attribute), std::move(out_attribute_a), std::move(out_attribute_b), a_or_b);
}
}
/**
* Find total in each new set and find which of the output sets each point will belong to.
*/
static Array<bool> count_point_splits(const GeometryComponent &component,
const GeoNodeExecParams &params,
int *r_a_total,
int *r_b_total)
{
const BooleanReadAttribute mask_attribute = params.get_input_attribute<bool>(
"Mask", component, ATTR_DOMAIN_POINT, false);
Array<bool> masks = mask_attribute.get_span();
const int in_total = masks.size();
*r_b_total = 0;
for (const bool mask : masks) {
if (mask) {
*r_b_total += 1;
}
}
*r_a_total = in_total - *r_b_total;
return masks;
}
static void separate_mesh(const MeshComponent &in_component,
const GeoNodeExecParams &params,
MeshComponent &out_component_a,
MeshComponent &out_component_b)
{
const int size = in_component.attribute_domain_size(ATTR_DOMAIN_POINT);
if (size == 0) {
return;
}
int a_total;
int b_total;
Array<bool> a_or_b = count_point_splits(in_component, params, &a_total, &b_total);
out_component_a.replace(BKE_mesh_new_nomain(a_total, 0, 0, 0, 0));
out_component_b.replace(BKE_mesh_new_nomain(b_total, 0, 0, 0, 0));
move_split_attributes(in_component, out_component_a, out_component_b, a_or_b);
}
static void separate_point_cloud(const PointCloudComponent &in_component,
const GeoNodeExecParams &params,
PointCloudComponent &out_component_a,
PointCloudComponent &out_component_b)
{
const int size = in_component.attribute_domain_size(ATTR_DOMAIN_POINT);
if (size == 0) {
return;
}
int a_total;
int b_total;
Array<bool> a_or_b = count_point_splits(in_component, params, &a_total, &b_total);
out_component_a.replace(BKE_pointcloud_new_nomain(a_total));
out_component_b.replace(BKE_pointcloud_new_nomain(b_total));
move_split_attributes(in_component, out_component_a, out_component_b, a_or_b);
}
static void geo_node_point_separate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet out_set_a(geometry_set);
GeometrySet out_set_b;
if (geometry_set.has<PointCloudComponent>()) {
separate_point_cloud(*geometry_set.get_component_for_read<PointCloudComponent>(),
params,
out_set_a.get_component_for_write<PointCloudComponent>(),
out_set_b.get_component_for_write<PointCloudComponent>());
}
if (geometry_set.has<MeshComponent>()) {
separate_mesh(*geometry_set.get_component_for_read<MeshComponent>(),
params,
out_set_a.get_component_for_write<MeshComponent>(),
out_set_b.get_component_for_write<MeshComponent>());
}
params.set_output("Geometry 1", std::move(out_set_a));
params.set_output("Geometry 2", std::move(out_set_b));
}
} // namespace blender::nodes
void register_node_type_geo_point_separate()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_instance_in, geo_node_point_instance_out);
ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec;
nodeRegisterType(&ntype);
}

View File

@ -116,4 +116,34 @@ const FloatMathOperationInfo *get_float_math_operation_info(const int operation)
return nullptr;
}
const FloatMathOperationInfo *get_float_compare_operation_info(const int operation)
{
#define RETURN_OPERATION_INFO(title_case_name, shader_name) \
{ \
static const FloatMathOperationInfo info{title_case_name, shader_name}; \
return &info; \
} \
((void)0)
switch (operation) {
case NODE_FLOAT_COMPARE_LESS_THAN:
RETURN_OPERATION_INFO("Less Than", "math_less_than");
case NODE_FLOAT_COMPARE_LESS_EQUAL:
RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal");
case NODE_FLOAT_COMPARE_GREATER_THAN:
RETURN_OPERATION_INFO("Greater Than", "math_greater_than");
case NODE_FLOAT_COMPARE_GREATER_EQUAL:
RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal");
case NODE_FLOAT_COMPARE_EQUAL:
RETURN_OPERATION_INFO("Equal", "math_equal");
case NODE_FLOAT_COMPARE_NOT_EQUAL:
RETURN_OPERATION_INFO("Not Equal", "math_not_equal");
}
#undef RETURN_OPERATION_INFO
return nullptr;
}
} // namespace blender::nodes