Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
c0cb475689
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ¶ms,
|
||||
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 ¶ms)
|
||||
{
|
||||
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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ¶ms,
|
||||
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 ¶ms,
|
||||
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 ¶ms,
|
||||
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);
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue