Mask primitives

Currently only circle and square, might be easily
extended in the future.

New primitives are creating at cursor location.
This also implied adding 2d cursor to space clip.

Also fix set 2D cursor location which didn't work
in image editor's mask mode since 2.67.

TODO: draw_image_cursor better be moved to some
      more generic file, but it's not so much
      important for now and might be solved later.

Thanks Campbell for the review!
This commit is contained in:
2013-08-26 20:23:26 +00:00
parent 11aa7a76fa
commit 03dbae07d3
18 changed files with 350 additions and 24 deletions

View File

@@ -28,6 +28,7 @@ _modules = [
"clip",
"console",
"image",
"mask",
"mesh",
"node",
"object_align",

View File

@@ -0,0 +1,34 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8-80 compliant>
import bpy
from bpy.types import Menu
class MASK_MT_add(Menu):
bl_idname = "MASK_MT_add"
bl_label = "Add"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mask.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
layout.operator("mask.primitive_square_add", text="Square", icon='MESH_PLANE')

View File

@@ -48,6 +48,8 @@ void ED_mask_point_pos(struct ScrArea *sa, struct ARegion *ar, float x, float y,
void ED_mask_point_pos__reverse(struct ScrArea *sa, struct ARegion *ar,
float x, float y, float *xr, float *yr);
void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]);
void ED_operatortypes_mask(void);
void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);

View File

@@ -102,7 +102,7 @@ void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
/* uvedit_draw.c */
void draw_image_cursor(struct SpaceImage *sima, struct ARegion *ar);
void draw_image_cursor(struct ARegion *ar, const float cursor[2]);
void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
/* uvedit_buttons.c */

View File

@@ -192,6 +192,7 @@ void UI_view2d_listview_visible_cells(struct View2D *v2d, float columnwidth, flo
void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *viewx, float *viewy);
void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *regionx, int *regiony);
void UI_view2d_to_region_no_clip(struct View2D *v2d, float x, float y, int *regionx, int *region_y);
void UI_view2d_to_region_float(struct View2D *v2d, float x, float y, float *regionx, float *regiony);
/* utilities */
struct View2D *UI_view2d_fromcontext(const struct bContext *C);

View File

@@ -2029,6 +2029,17 @@ void UI_view2d_to_region_no_clip(View2D *v2d, float x, float y, int *regionx, in
}
}
void UI_view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony)
{
/* express given coordinates as proportional values */
x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur);
y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur);
/* convert proportional distances to screen coordinates */
*regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask);
*regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask);
}
/* *********************************************************************** */
/* Utilities */

View File

@@ -737,3 +737,159 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Location of vertex in normalized space", -1.0f, 1.0f);
}
/******************** common primitive functions *********************/
static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2],
int num_points, char handle_type)
{
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Mask *mask;
MaskLayer *mask_layer;
MaskSpline *new_spline;
float scale, location[2], frame_size[2];
int i, width, height;
int size = RNA_float_get(op->ptr, "size");
ED_mask_get_size(sa, &width, &height);
scale = (float)size / max_ii(width, height);
/* Get location in mask space. */
frame_size[0] = width;
frame_size[1] = height;
RNA_float_get_array(op->ptr, "location", location);
location[0] /= width;
location[1] /= height;
BKE_mask_coord_from_frame(location, location, frame_size);
/* Make it so new primitive is centered to mouse location. */
location[0] -= 0.5f * scale;
location[1] -= 0.5f * scale;
mask_layer = ED_mask_layer_ensure(C);
mask = CTX_data_edit_mask(C);
ED_mask_select_toggle_all(mask, SEL_DESELECT);
new_spline = BKE_mask_spline_add(mask_layer);
new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
new_spline->tot_point = num_points;
new_spline->points = MEM_recallocN(new_spline->points,
sizeof(MaskSplinePoint) * new_spline->tot_point);
mask_layer->act_spline = new_spline;
mask_layer->act_point = NULL;
for (i = 0; i < num_points; i++) {
MaskSplinePoint *new_point = &new_spline->points[i];
copy_v2_v2(new_point->bezt.vec[1], points[i]);
mul_v2_fl(new_point->bezt.vec[1], scale);
add_v2_v2(new_point->bezt.vec[1], location);
new_point->bezt.h1 = handle_type;
new_point->bezt.h2 = handle_type;
BKE_mask_point_select_set(new_point, true);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
/* TODO: only update this spline */
BKE_mask_update_display(mask, CFRA);
return OPERATOR_FINISHED;
}
static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
ScrArea *sa = CTX_wm_area(C);
float cursor[2];
int width, height;
ED_mask_get_size(sa, &width, &height);
ED_mask_cursor_location_get(sa, cursor);
cursor[0] *= width;
cursor[1] *= height;
RNA_float_set_array(op->ptr, "location", cursor);
return op->type->exec(C, op);
}
static void define_prinitive_add_properties(wmOperatorType *ot)
{
RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX,
"Size", "Size of new circle", -FLT_MAX, FLT_MAX);
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Location of new circle", -FLT_MAX, FLT_MAX);
}
/******************** primitive add circle *********************/
static int primitive_circle_add_exec(bContext *C, wmOperator *op)
{
const float points[4][2] = {{0.0f, 0.5f},
{0.5f, 1.0f},
{1.0f, 0.5f},
{0.5f, 0.0f}};
int num_points = sizeof(points) / (2 * sizeof(float));
create_primitive_from_points(C, op, points, num_points, HD_AUTO);
return OPERATOR_FINISHED;
}
void MASK_OT_primitive_circle_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Circle";
ot->description = "Add new circle-shaped spline";
ot->idname = "MASK_OT_primitive_circle_add";
/* api callbacks */
ot->exec = primitive_circle_add_exec;
ot->invoke = primitive_add_invoke;
ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
define_prinitive_add_properties(ot);
}
/******************** primitive add suqare *********************/
static int primitive_square_add_exec(bContext *C, wmOperator *op)
{
const float points[4][2] = {{0.0f, 0.0f},
{0.0f, 1.0f},
{1.0f, 1.0f},
{1.0f, 0.0f}};
int num_points = sizeof(points) / (2 * sizeof(float));
create_primitive_from_points(C, op, points, num_points, HD_VECT);
return OPERATOR_FINISHED;
}
void MASK_OT_primitive_square_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Square";
ot->description = "Add new square-shaped spline";
ot->idname = "MASK_OT_primitive_square_add";
/* api callbacks */
ot->exec = primitive_square_add_exec;
ot->invoke = primitive_add_invoke;
ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
define_prinitive_add_properties(ot);
}

View File

@@ -363,6 +363,40 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *ar, float *scalex, float *s
}
}
void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
{
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *space_clip = sa->spacedata.first;
copy_v2_v2(cursor, space_clip->cursor);
break;
}
case SPACE_SEQ:
{
zero_v2(cursor);
break;
}
case SPACE_IMAGE:
{
SpaceImage *space_image = sa->spacedata.first;
copy_v2_v2(cursor, space_image->cursor);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
zero_v2(cursor);
break;
}
}
else {
BLI_assert(0);
zero_v2(cursor);
}
}
/********************** registration *********************/
void ED_operatortypes_mask(void)
@@ -376,6 +410,8 @@ void ED_operatortypes_mask(void)
/* add */
WM_operatortype_append(MASK_OT_add_vertex);
WM_operatortype_append(MASK_OT_add_feather_vertex);
WM_operatortype_append(MASK_OT_primitive_circle_add);
WM_operatortype_append(MASK_OT_primitive_square_add);
/* geometry */
WM_operatortype_append(MASK_OT_switch_direction);
@@ -432,6 +468,9 @@ void ED_keymap_mask(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MASK_OT_new", NKEY, KM_PRESS, KM_ALT, 0);
/* add menu */
WM_keymap_add_menu(keymap, "MASK_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
/* mask mode supports PET now */
ED_keymap_proportional_cycle(keyconf, keymap);
ED_keymap_proportional_maskmode(keyconf, keymap);

View File

@@ -42,9 +42,12 @@ struct wmOperatorType;
/* mask_add.c */
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
void MASK_OT_primitive_circle_add(struct wmOperatorType *ot);
void MASK_OT_primitive_square_add(struct wmOperatorType *ot);
/* mask_ops.c */
struct Mask *ED_mask_new(struct bContext *C, const char *name);
struct MaskLayer *ED_mask_layer_ensure(struct bContext *C);
void MASK_OT_new(struct wmOperatorType *ot);
void MASK_OT_layer_new(struct wmOperatorType *ot);

View File

@@ -292,6 +292,26 @@ Mask *ED_mask_new(bContext *C, const char *name)
return mask;
}
/* Get ative layer. Will create mask/layer to be sure there's an active layer. */
MaskLayer *ED_mask_layer_ensure(bContext *C)
{
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer;
if (mask == NULL) {
/* If there's no active mask, create one. */
mask = ED_mask_new(C, NULL);
}
mask_layer = BKE_mask_layer_active(mask);
if (mask_layer == NULL) {
/* If there's no active mask layer, create one. */
mask_layer = BKE_mask_layer_new(mask, "");
}
return mask_layer;
}
static int mask_new_exec(bContext *C, wmOperator *op)
{
char name[MAX_ID_NAME - 2];

View File

@@ -1004,17 +1004,6 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
}
}
static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony)
{
/* express given coordinates as proportional values */
x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur);
y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur);
/* convert proportional distances to screen coordinates */
*regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask);
*regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask);
}
static void plane_track_colors(bool is_active, float color[3], float selected_color[3])
{
UI_GetThemeColor3fv(TH_MARKER, color);
@@ -1175,7 +1164,7 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip,
* to avoid this flickering, calculate base point in the same way as it happens
* in UI_view2d_to_region_no_clip, but do it in floats here */
view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y);
UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y);
glPushMatrix();
glTranslatef(x, y, 0);
@@ -1418,7 +1407,7 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
if ((sc->flag & SC_SHOW_GRID) == 0 && (sc->flag & SC_MANUAL_CALIBRATION) == 0)
return;
view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y);
UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y);
glPushMatrix();
glTranslatef(x, y, 0);

View File

@@ -112,6 +112,8 @@ void CLIP_OT_prefetch(struct wmOperatorType *ot);
void CLIP_OT_set_scene_frames(wmOperatorType *ot);
void CLIP_OT_cursor_set(struct wmOperatorType *ot);
/* clip_toolbar.c */
struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa);
void CLIP_OT_tools(struct wmOperatorType *ot);

View File

@@ -1458,6 +1458,51 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->exec = clip_set_scene_frames_exec;
}
/******************** set 3d cursor operator ********************/
static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceClip *sclip = CTX_wm_space_clip(C);
RNA_float_get_array(op->ptr, "location", sclip->cursor);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
return OPERATOR_FINISHED;
}
static int clip_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceClip *sclip = CTX_wm_space_clip(C);
float location[2];
ED_clip_mouse_pos(sclip, ar, event->mval, location);
RNA_float_set_array(op->ptr, "location", location);
return clip_set_2d_cursor_exec(C, op);
}
void CLIP_OT_cursor_set(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Set 2D Cursor";
ot->description = "Set 2D cursor location";
ot->idname = "CLIP_OT_cursor_set";
/* api callbacks */
ot->exec = clip_set_2d_cursor_exec;
ot->invoke = clip_set_2d_cursor_invoke;
ot->poll = ED_space_clip_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
"Cursor location in normalized clip coordinates", -10.0f, 10.0f);
}
/********************** macroses *********************/
void ED_operatormacros_clip(void)

View File

@@ -56,6 +56,7 @@
#include "ED_screen.h"
#include "ED_clip.h"
#include "ED_transform.h"
#include "ED_uvedit.h" /* just for draw_image_cursor */
#include "IMB_imbuf.h"
@@ -442,6 +443,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_view_ndof);
WM_operatortype_append(CLIP_OT_prefetch);
WM_operatortype_append(CLIP_OT_set_scene_frames);
WM_operatortype_append(CLIP_OT_cursor_set);
/* ** clip_toolbar.c ** */
WM_operatortype_append(CLIP_OT_tools);
@@ -724,6 +726,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_ALL);
RNA_boolean_set(kmi->ptr, "clear_active", FALSE);
/* Cursor */
WM_keymap_add_item(keymap, "CLIP_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
/* ******** Hotkeys avalaible for preview region only ******** */
keymap = WM_keymap_find(keyconf, "Clip Graph Editor", SPACE_CLIP, 0);
@@ -1153,8 +1158,9 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
if (mask) {
ScrArea *sa = CTX_wm_area(C);
int width, height;
float aspx, aspy;
float aspx, aspy, zoomx, zoomy, x, y;
ED_mask_get_size(sa, &width, &height);
ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
ED_space_clip_get_aspect(sc, &aspx, &aspy);
ED_mask_draw_region(mask, ar,
sc->mask_info.draw_flag, sc->mask_info.draw_type,
@@ -1162,9 +1168,18 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
aspx, aspy,
TRUE, TRUE,
sc->stabmat, C);
/* TODO(sergey): would be nice to find a way to de-duplicate all this space conversions */
UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y);
glPushMatrix();
glTranslatef(x, y, 0);
glScalef(zoomx, zoomy, 0);
glMultMatrixf(sc->stabmat);
glScalef(width, height, 0);
draw_image_cursor(ar, sc->cursor);
glPopMatrix();
}
}
if (sc->flag & SC_SHOW_GPENCIL) {

View File

@@ -674,7 +674,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
}
else if (sima->mode == SI_MODE_MASK) {
mask = ED_space_image_get_mask(sima);
draw_image_cursor(sima, ar);
draw_image_cursor(ar, sima->cursor);
}
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
@@ -723,7 +723,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
ED_mask_draw_frames(mask, ar, CFRA, mask->sfra, mask->efra);
draw_image_cursor(sima, ar);
draw_image_cursor(ar, sima->cursor);
}
/* scrollers? */

View File

@@ -69,7 +69,7 @@
#define USE_EDBM_LOOPTRIS
void draw_image_cursor(SpaceImage *sima, ARegion *ar)
void draw_image_cursor(ARegion *ar, const float cursor[2])
{
float zoom[2], x_fac, y_fac;
@@ -80,7 +80,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar)
y_fac = zoom[1];
cpack(0xFFFFFF);
glTranslatef(sima->cursor[0], sima->cursor[1], 0.0);
glTranslatef(cursor[0], cursor[1], 0.0);
fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac);
fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f);
fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac);
@@ -108,7 +108,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar)
fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac);
fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac);
glTranslatef(-sima->cursor[0], -sima->cursor[1], 0.0);
glTranslatef(-cursor[0], -cursor[1], 0.0);
setlinestyle(0);
}
@@ -884,7 +884,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi
draw_uvs_texpaint(sima, scene, obact);
if (show_uvedit && !(toolsettings->use_uv_sculpt))
draw_image_cursor(sima, ar);
draw_image_cursor(ar, sima->cursor);
}
}

View File

@@ -3823,6 +3823,12 @@ static void UV_OT_reveal(wmOperatorType *ot)
/******************** set 3d cursor operator ********************/
static int uv_set_2d_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) ||
ED_space_image_maskedit_poll(C);
}
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -3858,7 +3864,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_set_2d_cursor_exec;
ot->invoke = uv_set_2d_cursor_invoke;
ot->poll = ED_operator_uvedit_space_image;
ot->poll = uv_set_2d_cursor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;

View File

@@ -1093,6 +1093,8 @@ typedef struct SpaceClip {
int around, pad4; /* pivot point for transforms */
float cursor[2]; /* Mask editor 2d cursor */
MaskSpaceInfo mask_info;
} SpaceClip;