This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/mask/mask_edit.c

556 lines
14 KiB
C
Raw Normal View History

/*
* ***** 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.
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation,
* Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/mask/mask_edit.c
* \ingroup edmask
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_mask.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */
#include "ED_image.h"
#include "ED_object.h" /* ED_keymap_proportional_maskmode only */
#include "ED_clip.h"
#include "ED_sequencer.h"
#include "ED_transform.h"
#include "UI_view2d.h"
#include "RNA_access.h"
#include "mask_intern.h" /* own include */
/********************** generic poll functions *********************/
2018-07-02 11:47:00 +02:00
bool ED_maskedit_poll(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_poll(C);
case SPACE_SEQ:
return ED_space_sequencer_maskedit_poll(C);
case SPACE_IMAGE:
return ED_space_image_maskedit_poll(C);
}
}
return false;
}
2018-07-02 11:47:00 +02:00
bool ED_maskedit_mask_poll(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_mask_poll(C);
case SPACE_SEQ:
return ED_space_sequencer_maskedit_mask_poll(C);
case SPACE_IMAGE:
return ED_space_image_maskedit_mask_poll(C);
}
}
return false;
}
/********************** registration *********************/
/* takes event->mval */
void ED_mask_mouse_pos(ScrArea *sa, ARegion *ar, const int mval[2], float co[2])
{
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
ED_clip_mouse_pos(sc, ar, mval, co);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
}
case SPACE_SEQ:
{
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &co[0], &co[1]);
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
ED_image_mouse_pos(sima, ar, mval, co);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
zero_v2(co);
break;
}
}
else {
BLI_assert(0);
zero_v2(co);
}
}
/* input: x/y - mval space
* output: xr/yr - mask point space */
void ED_mask_point_pos(ScrArea *sa, ARegion *ar, float x, float y, float *xr, float *yr)
{
float co[2];
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
ED_clip_point_stable_pos(sc, ar, x, y, &co[0], &co[1]);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
}
case SPACE_SEQ:
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
ED_image_point_pos(sima, ar, x, y, &co[0], &co[1]);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
zero_v2(co);
break;
}
}
else {
BLI_assert(0);
zero_v2(co);
}
*xr = co[0];
*yr = co[1];
}
void ED_mask_point_pos__reverse(ScrArea *sa, ARegion *ar, float x, float y, float *xr, float *yr)
{
float co[2];
if (sa) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, co, co);
ED_clip_point_stable_pos__reverse(sc, ar, co, co);
break;
}
case SPACE_SEQ:
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_image(sima->image, &sima->iuser, co, co);
ED_image_point_pos__reverse(sima, ar, co, co);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
zero_v2(co);
break;
}
}
else {
BLI_assert(0);
zero_v2(co);
}
*xr = co[0];
*yr = co[1];
}
void ED_mask_get_size(ScrArea *sa, int *width, int *height)
{
if (sa && sa->spacedata.first) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
ED_space_clip_get_size(sc, width, height);
break;
}
case SPACE_SEQ:
{
// Scene *scene = CTX_data_scene(C);
// *width = (scene->r.size * scene->r.xsch) / 100;
// *height = (scene->r.size * scene->r.ysch) / 100;
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
ED_space_image_get_size(sima, width, height);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
*width = 0;
*height = 0;
break;
}
}
else {
BLI_assert(0);
*width = 0;
*height = 0;
}
}
void ED_mask_zoom(ScrArea *sa, ARegion *ar, float *zoomx, float *zoomy)
{
if (sa && sa->spacedata.first) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
ED_space_clip_get_zoom(sc, ar, zoomx, zoomy);
break;
}
case SPACE_SEQ:
{
*zoomx = *zoomy = 1.0f;
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
*zoomx = *zoomy = 1.0f;
break;
}
}
else {
BLI_assert(0);
*zoomx = *zoomy = 1.0f;
}
}
void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(ar), float *aspx, float *aspy)
{
if (sa && sa->spacedata.first) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
ED_space_clip_get_aspect(sc, aspx, aspy);
break;
}
case SPACE_SEQ:
{
*aspx = *aspy = 1.0f; /* MASKTODO - render aspect? */
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
ED_space_image_get_aspect(sima, aspx, aspy);
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
*aspx = *aspy = 1.0f;
break;
}
}
else {
BLI_assert(0);
*aspx = *aspy = 1.0f;
}
}
void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *ar, float *scalex, float *scaley)
{
if (sa && sa->spacedata.first) {
switch (sa->spacetype) {
case SPACE_CLIP:
{
SpaceClip *sc = sa->spacedata.first;
float aspx, aspy;
2014-04-21 18:46:52 +10:00
UI_view2d_scale_get(&ar->v2d, scalex, scaley);
ED_space_clip_get_aspect(sc, &aspx, &aspy);
*scalex *= aspx;
*scaley *= aspy;
break;
}
case SPACE_SEQ:
{
*scalex = *scaley = 1.0f; /* MASKTODO? */
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
float aspx, aspy;
2014-04-21 18:46:52 +10:00
UI_view2d_scale_get(&ar->v2d, scalex, scaley);
ED_space_image_get_aspect(sima, &aspx, &aspy);
*scalex *= aspx;
*scaley *= aspy;
break;
}
default:
/* possible other spaces from which mask editing is available */
BLI_assert(0);
*scalex = *scaley = 1.0f;
break;
}
}
else {
BLI_assert(0);
*scalex = *scaley = 1.0f;
}
}
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);
}
}
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
{
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer;
bool ok = false;
if (mask == NULL)
return ok;
INIT_MINMAX2(min, max);
for (mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
MaskSpline *spline;
2015-06-16 10:18:45 +10:00
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
for (spline = mask_layer->splines.first;
spline != NULL;
spline = spline->next)
{
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskSplinePoint *deform_point = &points_array[i];
BezTriple *bezt = &point->bezt;
float handle[2];
if (!MASKPOINT_ISSEL_ANY(point)) {
continue;
}
if (bezt->f2 & SELECT) {
minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]);
}
if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle);
minmax_v2v2_v2(min, max, handle);
}
else {
if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle);
minmax_v2v2_v2(min, max, handle);
}
if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle);
minmax_v2v2_v2(min, max, handle);
}
}
ok = true;
}
}
}
return ok;
}
/********************** registration *********************/
void ED_operatortypes_mask(void)
{
WM_operatortype_append(MASK_OT_new);
/* mask layers */
WM_operatortype_append(MASK_OT_layer_new);
WM_operatortype_append(MASK_OT_layer_remove);
/* 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);
WM_operatortype_append(MASK_OT_normals_make_consistent);
WM_operatortype_append(MASK_OT_delete);
/* select */
WM_operatortype_append(MASK_OT_select);
WM_operatortype_append(MASK_OT_select_all);
WM_operatortype_append(MASK_OT_select_box);
WM_operatortype_append(MASK_OT_select_lasso);
WM_operatortype_append(MASK_OT_select_circle);
WM_operatortype_append(MASK_OT_select_linked_pick);
WM_operatortype_append(MASK_OT_select_linked);
2013-07-20 10:24:16 +00:00
WM_operatortype_append(MASK_OT_select_more);
WM_operatortype_append(MASK_OT_select_less);
/* hide/reveal */
WM_operatortype_append(MASK_OT_hide_view_clear);
WM_operatortype_append(MASK_OT_hide_view_set);
/* feather */
WM_operatortype_append(MASK_OT_feather_weight_clear);
/* shape */
WM_operatortype_append(MASK_OT_slide_point);
WM_operatortype_append(MASK_OT_slide_spline_curvature);
WM_operatortype_append(MASK_OT_cyclic_toggle);
WM_operatortype_append(MASK_OT_handle_type_set);
/* relationships */
WM_operatortype_append(MASK_OT_parent_set);
WM_operatortype_append(MASK_OT_parent_clear);
/* shapekeys */
WM_operatortype_append(MASK_OT_shape_key_insert);
WM_operatortype_append(MASK_OT_shape_key_clear);
WM_operatortype_append(MASK_OT_shape_key_feather_reset);
WM_operatortype_append(MASK_OT_shape_key_rekey);
/* layers */
WM_operatortype_append(MASK_OT_layer_move);
/* duplicate */
WM_operatortype_append(MASK_OT_duplicate);
/* clipboard */
WM_operatortype_append(MASK_OT_copy_splines);
WM_operatortype_append(MASK_OT_paste_splines);
}
void ED_keymap_mask(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mask Editing", 0, 0);
2012-06-04 17:30:54 +00:00
keymap->poll = ED_maskedit_poll;
}
void ED_operatormacros_mask(void)
{
wmOperatorType *ot;
wmOperatorTypeMacro *otmacro;
ot = WM_operatortype_append_macro("MASK_OT_add_vertex_slide", "Add Vertex and Slide",
"Add new vertex and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
ot->description = "Add new vertex and slide it";
WM_operatortype_macro_define(ot, "MASK_OT_add_vertex");
Implement asymmetric and free handles type for masks Summary: The title actually says it all, it's just possible to have independent free handles for mask splines. Also it's now possible to have aligned handles displayed as independent handles. Required changes in quite a few places, but they're rather straightforward. From user perspective there's one really visible change which is removed Handle Type menu from the panel. With asymmetric handles it's not clear which handle type to display there. So now the only way to change handle type is via V-key menu. Rewrote normal evaluation function to make it deal with new type of handles we support. Now it works in the following way: - Offset the original spline by maximal weight - Calculate vector between corresponding U positions on offset and original spline - Normalize this vector. Seems to be giving more adequate results and doesn't tend to self-intersect as much as old behavior used to, There're still some changes which needed to be done, but which are planned for further patch: - Support colors and handle size via themes. - Make handles color-coded, just the same as done for regular bezier splines in 3D viewport. Additional changes to make roto workflow even better: - Use circles to draw handles - Support AA for handles - Change click-create-drag to change curvature of the spline instead of adjusting point position. Reviewers: campbellbarton CC: sebastian_k, hype, cronk Differential Revision: http://developer.blender.org/D121
2013-10-30 10:38:45 +01:00
otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point");
RNA_boolean_set(otmacro->ptr, "is_new_point", true);
ot = WM_operatortype_append_macro("MASK_OT_add_feather_vertex_slide", "Add Feather Vertex and Slide",
"Add new vertex to feather and slide it", OPTYPE_UNDO | OPTYPE_REGISTER);
ot->description = "Add new feather vertex and slide it";
WM_operatortype_macro_define(ot, "MASK_OT_add_feather_vertex");
otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point");
RNA_boolean_set(otmacro->ptr, "slide_feather", true);
ot = WM_operatortype_append_macro("MASK_OT_duplicate_move", "Add Duplicate", "Duplicate mask and move",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MASK_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", false);
}