Compositor: implement gizmo for ellipse mask node

Implement ellipse gizmo for the ellipse mask node. Behavior and implementation are similar to the box node with the exception that corners are always visible.

Pull Request: https://projects.blender.org/blender/blender/pulls/137115
This commit is contained in:
Habib Gahbiche
2025-04-11 10:32:43 +02:00
parent 51c2cf2b9d
commit b148593c5d
5 changed files with 146 additions and 88 deletions

View File

@@ -545,6 +545,8 @@ static void cage2d_draw_rect_wire(const rctf *r,
static void cage2d_draw_circle_wire(const float color[3],
const float size[2],
const float margin[2],
const int transform_flag,
const int draw_options,
const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -569,6 +571,30 @@ static void cage2d_draw_circle_wire(const float color[3],
imm_draw_circle_wire_aspect_3d(pos, 0.0f, 0.0f, size[0], size[1], CIRCLE_RESOL);
}
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
immBegin(GPU_PRIM_LINES, 4);
immVertex3f(pos, 0.0f, size[1], 0.0f);
immVertex3f(pos, 0.0f, size[1] + margin[1], 0.0f);
immVertex3f(pos, 0.0f, size[1] + margin[1], 0.0f);
immVertex3f(pos, 0.0f, size[1], 0.0f);
immEnd();
}
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
if (draw_options & ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE) {
const float rad[2] = {margin[0] / 2, margin[1] / 2};
const float center[2] = {0.0f, 0.0f};
immBegin(GPU_PRIM_LINES, 4);
immVertex3f(pos, center[0] - rad[0], center[1] - rad[1], 0.0f);
immVertex3f(pos, center[0] + rad[0], center[1] + rad[1], 0.0f);
immVertex3f(pos, center[0] + rad[0], center[1] - rad[1], 0.0f);
immVertex3f(pos, center[0] - rad[0], center[1] + rad[1], 0.0f);
immEnd();
}
}
immUnbindProgram();
}
@@ -581,21 +607,11 @@ static bool is_corner_highlighted(const int highlighted)
ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
}
static void cage2d_draw_rect_corner_handles(const rctf *r,
const int highlighted,
const float margin[2],
const float color[3],
const int transform_flag,
bool solid)
static void cage2d_draw_rect_rotate_handle(const rctf *r,
const float margin[2],
const float color[3],
bool solid)
{
/* Only draw corner handles when hovering over the corners. */
const bool draw_corners = is_corner_highlighted(highlighted);
const bool draw_rotate_handle = transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE;
if (!(draw_corners || draw_rotate_handle)) {
return;
}
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
void (*circle_fn)(uint, float, float, float, float, int) = (solid) ?
imm_draw_circle_fill_aspect_2d :
@@ -606,22 +622,32 @@ static void cage2d_draw_rect_corner_handles(const rctf *r,
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
const float handle[2] = {
BLI_rctf_cent_x(r),
r->ymax + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE),
};
circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu);
immUnbindProgram();
}
static void cage2d_draw_rect_corner_handles(const rctf *r,
const float margin[2],
const float color[3],
bool solid)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const float rad[2] = {margin[0] / 3, margin[1] / 3};
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3fv(color);
/* should really divide by two, but looks too bulky. */
{
if (draw_corners) {
imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid);
}
}
if (draw_rotate_handle) {
const float handle[2] = {
BLI_rctf_cent_x(r),
r->ymax + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE),
};
circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu);
imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid);
imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid);
}
immUnbindProgram();
@@ -704,7 +730,7 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
/* Only scaling is needed for now. */
GPU_select_load_id(select_id | ED_GIZMO_CAGE2D_PART_SCALE);
cage2d_draw_circle_wire(gz->color, size_real, margin, gz->line_width);
cage2d_draw_circle_wire(gz->color, size_real, margin, 0, draw_options, gz->line_width);
}
else {
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE) {
@@ -802,15 +828,35 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, color, true);
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, black, false);
/* Corner handles. */
cage2d_draw_rect_corner_handles(
&r, gz->highlight_part, margin, color, transform_flag, true);
cage2d_draw_rect_corner_handles(
&r, gz->highlight_part, margin, black, transform_flag, false);
/* Only draw corner handles when hovering over the corners. */
if (is_corner_highlighted(gz->highlight_part)) {
cage2d_draw_rect_corner_handles(&r, margin, color, true);
cage2d_draw_rect_corner_handles(&r, margin, black, false);
}
/* Rotate handles. */
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
cage2d_draw_rect_rotate_handle(&r, margin, color, true);
cage2d_draw_rect_rotate_handle(&r, margin, black, false);
}
}
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
cage2d_draw_circle_wire(black, size_real, margin, outline_line_width);
cage2d_draw_circle_wire(color, size_real, margin, gz->line_width);
cage2d_draw_circle_wire(
black, size_real, margin, transform_flag, draw_options, outline_line_width);
cage2d_draw_circle_wire(
color, size_real, margin, transform_flag, draw_options, gz->line_width);
/* Edge handles. */
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, color, true);
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, black, false);
/* Always draw corner handles. */
cage2d_draw_rect_corner_handles(&r, margin, color, true);
cage2d_draw_rect_corner_handles(&r, margin, black, false);
/* Rotation handles. */
cage2d_draw_rect_rotate_handle(&r, margin, color, true);
cage2d_draw_rect_rotate_handle(&r, margin, black, false);
}
else {
BLI_assert(0);

View File

@@ -595,51 +595,6 @@ static void node_composit_buts_combsep_color(uiLayout *layout, bContext * /*C*/,
}
}
static void node_composit_backdrop_ellipsemask(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
NodeEllipseMask *ellipsemask = (NodeEllipseMask *)node->storage;
const float backdropWidth = backdrop->x;
const float backdropHeight = backdrop->y;
const float aspect = backdropWidth / backdropHeight;
const float rad = -ellipsemask->rotation;
const float cosine = cosf(rad);
const float sine = sinf(rad);
const float halveBoxWidth = backdropWidth * (ellipsemask->width / 2.0f);
const float halveBoxHeight = backdropHeight * (ellipsemask->height / 2.0f) * aspect;
float cx, cy, x1, x2, x3, x4;
float y1, y2, y3, y4;
cx = x + snode->zoom * backdropWidth * ellipsemask->x;
cy = y + snode->zoom * backdropHeight * ellipsemask->y;
x1 = cx - (cosine * halveBoxWidth + sine * halveBoxHeight) * snode->zoom;
x2 = cx - (cosine * -halveBoxWidth + sine * halveBoxHeight) * snode->zoom;
x3 = cx - (cosine * -halveBoxWidth + sine * -halveBoxHeight) * snode->zoom;
x4 = cx - (cosine * halveBoxWidth + sine * -halveBoxHeight) * snode->zoom;
y1 = cy - (-sine * halveBoxWidth + cosine * halveBoxHeight) * snode->zoom;
y2 = cy - (-sine * -halveBoxWidth + cosine * halveBoxHeight) * snode->zoom;
y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
immBegin(GPU_PRIM_LINE_LOOP, 4);
immVertex2f(pos, x1, y1);
immVertex2f(pos, x2, y2);
immVertex2f(pos, x3, y3);
immVertex2f(pos, x4, y4);
immEnd();
immUnbindProgram();
}
static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
bContext * /*C*/,
PointerRNA *ptr)
@@ -743,9 +698,6 @@ static void node_composit_set_butfunc(blender::bke::bNodeType *ntype)
case CMP_NODE_SEPYCCA_LEGACY:
ntype->draw_buttons = node_composit_buts_ycc;
break;
case CMP_NODE_MASK_ELLIPSE:
ntype->draw_backdrop = node_composit_backdrop_ellipsemask;
break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;

View File

@@ -509,7 +509,7 @@ static void WIDGETGROUP_node_box_mask_setup(const bContext * /*C*/, wmGizmoGroup
};
}
static void WIDGETGROUP_node_box_mask_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_node_mask_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
@@ -519,7 +519,7 @@ static void WIDGETGROUP_node_box_mask_draw_prepare(const bContext *C, wmGizmoGro
node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
}
static void WIDGETGROUP_node_box_mask_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_node_mask_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Main *bmain = CTX_data_main(C);
NodeBBoxWidgetGroup *mask_group = (NodeBBoxWidgetGroup *)gzgroup->customdata;
@@ -569,8 +569,66 @@ void NODE_GGT_backdrop_box_mask(wmGizmoGroupType *gzgt)
gzgt->poll = WIDGETGROUP_node_box_mask_poll;
gzgt->setup = WIDGETGROUP_node_box_mask_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->draw_prepare = WIDGETGROUP_node_box_mask_draw_prepare;
gzgt->refresh = WIDGETGROUP_node_box_mask_refresh;
gzgt->draw_prepare = WIDGETGROUP_node_mask_draw_prepare;
gzgt->refresh = WIDGETGROUP_node_mask_refresh;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Ellipse Mask
* \{ */
static bool WIDGETGROUP_node_ellipse_mask_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/)
{
SpaceNode *snode = CTX_wm_space_node(C);
if (snode && (snode->flag & SNODE_BACKDRAW) == 0) {
return false;
}
if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
bNode *node = bke::node_get_active(*snode->edittree);
if (node && node->is_type("CompositorNodeEllipseMask")) {
return true;
}
}
return false;
}
static void WIDGETGROUP_node_ellipse_mask_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
NodeBBoxWidgetGroup *mask_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
mask_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
RNA_enum_set(mask_group->border->ptr,
"transform",
ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE_XFORM_FLAG_ROTATE |
ED_GIZMO_CAGE_XFORM_FLAG_SCALE);
RNA_enum_set(mask_group->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_CIRCLE);
RNA_enum_set(
mask_group->border->ptr, "draw_options", ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE);
gzgroup->customdata = mask_group;
gzgroup->customdata_free = [](void *customdata) {
MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
};
}
void NODE_GGT_backdrop_ellipse_mask(wmGizmoGroupType *gzgt)
{
gzgt->name = "Backdrop Ellipse Mask Widget";
gzgt->idname = "NODE_GGT_backdrop_ellipse_mask";
gzgt->flag |= WM_GIZMOGROUPTYPE_PERSISTENT;
gzgt->poll = WIDGETGROUP_node_ellipse_mask_poll;
gzgt->setup = WIDGETGROUP_node_ellipse_mask_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->draw_prepare = WIDGETGROUP_node_mask_draw_prepare;
gzgt->refresh = WIDGETGROUP_node_mask_refresh;
}
/** \} */

View File

@@ -398,6 +398,7 @@ void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_box_mask(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_ellipse_mask(wmGizmoGroupType *gzgt);
/* `node_geometry_attribute_search.cc` */

View File

@@ -1138,6 +1138,7 @@ static void node_widgets()
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_box_mask);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_ellipse_mask);
}
static void node_id_remap(ID *old_id, ID *new_id, SpaceNode *snode)