The issue was caused here by usage of deprecated GL_CURRENT_PROGRAM which was returning rubbish value. Now we use imm API and create vertex format prior to immBindProgram. This made us required to have some sort of state passed from setup function to actual drawing.
843 lines
24 KiB
C
843 lines
24 KiB
C
/*
|
|
* ***** 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,
|
|
* Campbell Barton,
|
|
* Sergey Sharybin
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/editors/mask/mask_draw.c
|
|
* \ingroup edmask
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_rect.h"
|
|
#include "BLI_task.h"
|
|
#include "BLI_listbase.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_mask.h"
|
|
|
|
#include "DNA_mask_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_object_types.h" /* SELECT */
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "ED_clip.h"
|
|
#include "ED_mask.h" /* own include */
|
|
#include "ED_space_api.h"
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
#include "GPU_immediate.h"
|
|
#include "GPU_draw.h"
|
|
#include "GPU_shader.h"
|
|
#include "GPU_matrix.h"
|
|
|
|
#include "UI_resources.h"
|
|
#include "UI_view2d.h"
|
|
|
|
#include "mask_intern.h" /* own include */
|
|
|
|
static void mask_spline_color_get(MaskLayer *masklay, MaskSpline *spline, const bool is_sel,
|
|
unsigned char r_rgb[4])
|
|
{
|
|
if (is_sel) {
|
|
if (masklay->act_spline == spline) {
|
|
r_rgb[0] = r_rgb[1] = r_rgb[2] = 255;
|
|
}
|
|
else {
|
|
r_rgb[0] = 255;
|
|
r_rgb[1] = r_rgb[2] = 0;
|
|
}
|
|
}
|
|
else {
|
|
r_rgb[0] = 128;
|
|
r_rgb[1] = r_rgb[2] = 0;
|
|
}
|
|
|
|
r_rgb[3] = 255;
|
|
}
|
|
|
|
static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay), MaskSpline *UNUSED(spline), const bool is_sel,
|
|
unsigned char r_rgb[4])
|
|
{
|
|
if (is_sel) {
|
|
r_rgb[1] = 255;
|
|
r_rgb[0] = r_rgb[2] = 0;
|
|
}
|
|
else {
|
|
r_rgb[1] = 128;
|
|
r_rgb[0] = r_rgb[2] = 0;
|
|
}
|
|
|
|
r_rgb[3] = 255;
|
|
}
|
|
|
|
static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
|
|
{
|
|
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
|
|
ED_clip_point_undistorted_pos(sc, r_co, r_co);
|
|
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
|
|
}
|
|
|
|
static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point,
|
|
const eMaskWhichHandle which_handle, const int draw_type,
|
|
const float handle_size,
|
|
const float point_pos[2], const float handle_pos[2])
|
|
{
|
|
const BezTriple *bezt = &point->bezt;
|
|
char handle_type;
|
|
|
|
if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) {
|
|
handle_type = bezt->h1;
|
|
}
|
|
else {
|
|
handle_type = bezt->h2;
|
|
}
|
|
|
|
if (handle_type == HD_VECT) {
|
|
return;
|
|
}
|
|
|
|
VertexFormat *format = immVertexFormat();
|
|
unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT);
|
|
const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
immUniformColor3ubv(rgb_gray);
|
|
|
|
/* this could be split into its own loop */
|
|
if (draw_type == MASK_DT_OUTLINE) {
|
|
glLineWidth(3.0f);
|
|
immBegin(PRIM_LINES, 2);
|
|
immVertex2fv(pos, point_pos);
|
|
immVertex2fv(pos, handle_pos);
|
|
immEnd();
|
|
}
|
|
|
|
switch (handle_type) {
|
|
case HD_FREE:
|
|
immUniformThemeColor(TH_HANDLE_FREE);
|
|
break;
|
|
case HD_AUTO:
|
|
immUniformThemeColor(TH_HANDLE_AUTO);
|
|
break;
|
|
case HD_ALIGN:
|
|
case HD_ALIGN_DOUBLESIDE:
|
|
immUniformThemeColor(TH_HANDLE_ALIGN);
|
|
break;
|
|
}
|
|
|
|
glLineWidth(1.0f);
|
|
immBegin(PRIM_LINES, 2);
|
|
immVertex2fv(pos, point_pos);
|
|
immVertex2fv(pos, handle_pos);
|
|
immEnd();
|
|
immUnbindProgram();
|
|
|
|
/* draw handle points */
|
|
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
|
|
immUniform1f("size", handle_size);
|
|
immUniform1f("outlineWidth", 1.5f);
|
|
|
|
float point_color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; /* active color by default */
|
|
if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
|
|
if (point != mask_layer->act_point) {
|
|
UI_GetThemeColor3fv(TH_HANDLE_VERTEX_SELECT, point_color);
|
|
}
|
|
}
|
|
else {
|
|
UI_GetThemeColor3fv(TH_HANDLE_VERTEX, point_color);
|
|
}
|
|
|
|
immUniform4fv("outlineColor", point_color);
|
|
immUniformColor3fvAlpha(point_color, 0.25f);
|
|
|
|
immBegin(PRIM_POINTS, 1);
|
|
immVertex2fv(pos, handle_pos);
|
|
immEnd();
|
|
|
|
immUnbindProgram();
|
|
}
|
|
|
|
/* return non-zero if spline is selected */
|
|
static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
|
|
const char draw_flag, const char draw_type)
|
|
{
|
|
const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
|
|
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
|
|
|
|
unsigned char rgb_spline[4];
|
|
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
bool undistort = false;
|
|
|
|
int tot_feather_point;
|
|
float (*feather_points)[2], (*fp)[2];
|
|
float min[2], max[2];
|
|
|
|
if (!spline->tot_point)
|
|
return;
|
|
|
|
if (sc)
|
|
undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
|
|
|
|
/* TODO, add this to sequence editor */
|
|
float handle_size = 2.0f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
|
|
|
|
mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
|
|
|
|
VertexFormat *format = immVertexFormat();
|
|
unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT);
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
|
|
immUniform1f("size", 0.7f * handle_size);
|
|
|
|
/* feather points */
|
|
feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
|
|
for (int i = 0; i < spline->tot_point; i++) {
|
|
|
|
/* watch it! this is intentionally not the deform array, only check for sel */
|
|
MaskSplinePoint *point = &spline->points[i];
|
|
|
|
for (int j = 0; j <= point->tot_uw; j++) {
|
|
float feather_point[2];
|
|
bool sel = false;
|
|
|
|
copy_v2_v2(feather_point, *fp);
|
|
|
|
if (undistort)
|
|
mask_point_undistort_pos(sc, feather_point, feather_point);
|
|
|
|
if (j == 0) {
|
|
sel = MASKPOINT_ISSEL_ANY(point);
|
|
}
|
|
else {
|
|
sel = (point->uw[j - 1].flag & SELECT) != 0;
|
|
}
|
|
|
|
if (sel) {
|
|
if (point == masklay->act_point)
|
|
immUniformColor3f(1.0f, 1.0f, 1.0f);
|
|
else
|
|
immUniformThemeColor(TH_HANDLE_VERTEX_SELECT);
|
|
}
|
|
else {
|
|
immUniformThemeColor(TH_HANDLE_VERTEX);
|
|
}
|
|
|
|
immBegin(PRIM_POINTS, 1);
|
|
immVertex2fv(pos, feather_point);
|
|
immEnd();
|
|
|
|
fp++;
|
|
}
|
|
}
|
|
MEM_freeN(feather_points);
|
|
|
|
immUnbindProgram();
|
|
|
|
if (is_smooth) {
|
|
glEnable(GL_LINE_SMOOTH);
|
|
}
|
|
|
|
/* control points */
|
|
INIT_MINMAX2(min, max);
|
|
for (int i = 0; i < spline->tot_point; i++) {
|
|
|
|
/* watch it! this is intentionally not the deform array, only check for sel */
|
|
MaskSplinePoint *point = &spline->points[i];
|
|
MaskSplinePoint *point_deform = &points_array[i];
|
|
BezTriple *bezt = &point_deform->bezt;
|
|
|
|
float vert[2];
|
|
|
|
copy_v2_v2(vert, bezt->vec[1]);
|
|
|
|
if (undistort) {
|
|
mask_point_undistort_pos(sc, vert, vert);
|
|
}
|
|
|
|
/* draw handle segment */
|
|
if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
|
|
float handle[2];
|
|
BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle);
|
|
if (undistort) {
|
|
mask_point_undistort_pos(sc, handle, handle);
|
|
}
|
|
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK,
|
|
draw_type, handle_size, vert, handle);
|
|
}
|
|
else {
|
|
float handle_left[2], handle_right[2];
|
|
BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left);
|
|
BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right);
|
|
if (undistort) {
|
|
mask_point_undistort_pos(sc, handle_left, handle_left);
|
|
mask_point_undistort_pos(sc, handle_left, handle_left);
|
|
}
|
|
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT,
|
|
draw_type, handle_size, vert, handle_left);
|
|
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT,
|
|
draw_type, handle_size, vert, handle_right);
|
|
}
|
|
|
|
/* bind program in loop so it does not interfere with draw_single_handle */
|
|
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
|
|
|
|
/* draw CV point */
|
|
if (MASKPOINT_ISSEL_KNOT(point)) {
|
|
if (point == masklay->act_point)
|
|
immUniformColor3f(1.0f, 1.0f, 1.0f);
|
|
else
|
|
immUniformThemeColor(TH_HANDLE_VERTEX_SELECT);
|
|
}
|
|
else
|
|
immUniformThemeColor(TH_HANDLE_VERTEX);
|
|
|
|
immBegin(PRIM_POINTS, 1);
|
|
immVertex2fv(pos, vert);
|
|
immEnd();
|
|
|
|
immUnbindProgram();
|
|
|
|
minmax_v2v2_v2(min, max, vert);
|
|
}
|
|
|
|
if (is_smooth) {
|
|
glDisable(GL_LINE_SMOOTH);
|
|
}
|
|
|
|
if (is_spline_sel) {
|
|
float x = (min[0] + max[0]) * 0.5f;
|
|
float y = (min[1] + max[1]) * 0.5f;
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
|
|
immUniform1f("outlineWidth", 1.5f);
|
|
|
|
if (masklay->act_spline == spline) {
|
|
immUniformColor3f(1.0f, 1.0f, 1.0f);
|
|
}
|
|
else {
|
|
immUniformColor3f(1.0f, 1.0f, 0.0f);
|
|
}
|
|
|
|
immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f);
|
|
immUniform1f("size", 12.0f);
|
|
|
|
immBegin(PRIM_POINTS, 1);
|
|
immVertex2f(pos, x, y);
|
|
immEnd();
|
|
|
|
immUnbindProgram();
|
|
}
|
|
}
|
|
|
|
static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const bool is_active)
|
|
{
|
|
if (!is_active) {
|
|
r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
|
|
r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
|
|
r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
|
|
r_rgb[3] = rgb[3];
|
|
}
|
|
else {
|
|
*(unsigned int *)r_rgb = *(const unsigned int *)rgb;
|
|
}
|
|
}
|
|
|
|
static void mask_draw_array(unsigned int pos, PrimitiveType prim_type, const float (*points)[2], unsigned int vertex_ct)
|
|
{
|
|
immBegin(prim_type, vertex_ct);
|
|
for (unsigned int i = 0; i < vertex_ct; ++i) {
|
|
immVertex2fv(pos, points[i]);
|
|
}
|
|
immEnd();
|
|
}
|
|
|
|
static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*orig_points)[2], int tot_point,
|
|
const bool is_feather, const bool is_active,
|
|
const unsigned char rgb_spline[4], const char draw_type)
|
|
{
|
|
const PrimitiveType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? PRIM_LINE_LOOP : PRIM_LINE_STRIP;
|
|
const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
|
|
unsigned char rgb_tmp[4];
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
float (*points)[2] = orig_points;
|
|
|
|
if (sc) {
|
|
const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
|
|
|
|
if (undistort) {
|
|
points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
|
|
|
|
for (int i = 0; i < tot_point; i++) {
|
|
mask_point_undistort_pos(sc, points[i], orig_points[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
VertexFormat *format = immVertexFormat();
|
|
unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT);
|
|
|
|
switch (draw_type) {
|
|
|
|
case MASK_DT_OUTLINE:
|
|
/* TODO(merwin): use fancy line shader here
|
|
* probably better with geometry shader (after core profile switch)
|
|
*/
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
|
|
glLineWidth(3.0f);
|
|
|
|
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
|
|
immUniformColor4ubv(rgb_tmp);
|
|
mask_draw_array(pos, draw_method, points, tot_point);
|
|
|
|
glLineWidth(1.0f);
|
|
|
|
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
|
|
immUniformColor4ubv(rgb_tmp);
|
|
mask_draw_array(pos, draw_method, points, tot_point);
|
|
|
|
immUnbindProgram();
|
|
break;
|
|
|
|
case MASK_DT_BLACK:
|
|
case MASK_DT_WHITE:
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
glLineWidth(1.0f);
|
|
|
|
if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0; }
|
|
else { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
|
|
/* alpha values seem too low but gl draws many points that compensate for it */
|
|
if (is_feather) { rgb_tmp[3] = 64; }
|
|
else { rgb_tmp[3] = 128; }
|
|
|
|
if (is_feather) {
|
|
rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
|
|
rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
|
|
rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
|
|
}
|
|
|
|
mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
|
|
immUniformColor4ubv(rgb_tmp);
|
|
mask_draw_array(pos, draw_method, points, tot_point);
|
|
|
|
immUnbindProgram();
|
|
break;
|
|
|
|
case MASK_DT_DASH:
|
|
/* TODO(merwin): use dashed line shader here
|
|
* probably better with geometry shader (after core profile switch)
|
|
*/
|
|
#if 0
|
|
glLineWidth(1.0f);
|
|
|
|
GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
|
|
GPU_basic_shader_line_stipple(3, 0xAAAA);
|
|
|
|
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
|
|
immUniformColor4ubv(rgb_tmp);
|
|
mask_draw_array(pos, draw_method, points, tot_point);
|
|
|
|
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
|
|
immUniformColor4ubv(rgb_tmp);
|
|
GPU_basic_shader_line_stipple(3, 0x5555);
|
|
mask_draw_array(pos, draw_method, points, tot_point);
|
|
|
|
GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
BLI_assert(false);
|
|
}
|
|
|
|
if (points != orig_points)
|
|
MEM_freeN(points);
|
|
}
|
|
|
|
static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
|
|
const char draw_flag, const char draw_type,
|
|
const bool is_active,
|
|
const int width, const int height)
|
|
{
|
|
const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
|
|
BKE_mask_spline_resolution(spline, width, height));
|
|
|
|
unsigned char rgb_tmp[4];
|
|
|
|
const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
|
|
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
|
|
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
|
|
|
|
unsigned int tot_diff_point;
|
|
float (*diff_points)[2];
|
|
|
|
unsigned int tot_feather_point;
|
|
float (*feather_points)[2];
|
|
|
|
diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
|
|
|
|
if (!diff_points)
|
|
return;
|
|
|
|
if (is_smooth) {
|
|
glEnable(GL_LINE_SMOOTH);
|
|
}
|
|
|
|
feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != false));
|
|
|
|
/* draw feather */
|
|
mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
|
|
mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
|
|
true, is_active,
|
|
rgb_tmp, draw_type);
|
|
|
|
if (!is_fill) {
|
|
const float *fp = &diff_points[0][0];
|
|
float *fp_feather = &feather_points[0][0];
|
|
|
|
BLI_assert(tot_diff_point == tot_feather_point);
|
|
|
|
for (int i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
|
|
float tvec[2];
|
|
sub_v2_v2v2(tvec, fp, fp_feather);
|
|
add_v2_v2v2(fp_feather, fp, tvec);
|
|
}
|
|
|
|
/* same as above */
|
|
mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
|
|
true, is_active,
|
|
rgb_tmp, draw_type);
|
|
}
|
|
|
|
MEM_freeN(feather_points);
|
|
|
|
/* draw main curve */
|
|
mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
|
|
mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
|
|
false, is_active,
|
|
rgb_tmp, draw_type);
|
|
MEM_freeN(diff_points);
|
|
|
|
if (is_smooth) {
|
|
glDisable(GL_LINE_SMOOTH);
|
|
}
|
|
}
|
|
|
|
static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
|
|
const int width, const int height)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
GPU_enable_program_point_size();
|
|
|
|
MaskLayer *masklay;
|
|
int i;
|
|
|
|
for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
|
|
MaskSpline *spline;
|
|
const bool is_active = (i == mask->masklay_act);
|
|
|
|
if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
|
|
continue;
|
|
}
|
|
|
|
for (spline = masklay->splines.first; spline; spline = spline->next) {
|
|
|
|
/* draw curve itself first... */
|
|
draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
|
|
|
|
if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
|
|
/* ...and then handles over the curve so they're nicely visible */
|
|
draw_spline_points(C, masklay, spline, draw_flag, draw_type);
|
|
}
|
|
|
|
/* show undeform for testing */
|
|
if (0) {
|
|
void *back = spline->points_deform;
|
|
|
|
spline->points_deform = NULL;
|
|
draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
|
|
draw_spline_points(C, masklay, spline, draw_flag, draw_type);
|
|
spline->points_deform = back;
|
|
}
|
|
}
|
|
}
|
|
|
|
GPU_disable_program_point_size();
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
void ED_mask_draw(const bContext *C,
|
|
const char draw_flag, const char draw_type)
|
|
{
|
|
ScrArea *sa = CTX_wm_area(C);
|
|
Mask *mask = CTX_data_edit_mask(C);
|
|
int width, height;
|
|
|
|
if (!mask)
|
|
return;
|
|
|
|
ED_mask_get_size(sa, &width, &height);
|
|
|
|
draw_masklays(C, mask, draw_flag, draw_type, width, height);
|
|
}
|
|
|
|
typedef struct ThreadedMaskRasterizeState {
|
|
MaskRasterHandle *handle;
|
|
float *buffer;
|
|
int width, height;
|
|
} ThreadedMaskRasterizeState;
|
|
|
|
typedef struct ThreadedMaskRasterizeData {
|
|
int start_scanline;
|
|
int num_scanlines;
|
|
} ThreadedMaskRasterizeData;
|
|
|
|
static void mask_rasterize_func(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
|
|
{
|
|
ThreadedMaskRasterizeState *state = (ThreadedMaskRasterizeState *) BLI_task_pool_userdata(pool);
|
|
ThreadedMaskRasterizeData *data = (ThreadedMaskRasterizeData *) taskdata;
|
|
int scanline;
|
|
const float x_inv = 1.0f / (float)state->width;
|
|
const float y_inv = 1.0f / (float)state->height;
|
|
const float x_px_ofs = x_inv * 0.5f;
|
|
const float y_px_ofs = y_inv * 0.5f;
|
|
|
|
for (scanline = 0; scanline < data->num_scanlines; scanline++) {
|
|
float xy[2];
|
|
int x, y = data->start_scanline + scanline;
|
|
|
|
xy[1] = ((float)y * y_inv) + y_px_ofs;
|
|
|
|
for (x = 0; x < state->width; x++) {
|
|
int index = y * state->width + x;
|
|
|
|
xy[0] = ((float)x * x_inv) + x_px_ofs;
|
|
|
|
state->buffer[index] = BKE_maskrasterize_handle_sample(state->handle, xy);
|
|
}
|
|
}
|
|
}
|
|
|
|
static float *threaded_mask_rasterize(Mask *mask, const int width, const int height)
|
|
{
|
|
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
|
|
TaskPool *task_pool;
|
|
MaskRasterHandle *handle;
|
|
ThreadedMaskRasterizeState state;
|
|
float *buffer;
|
|
int i, num_threads = BLI_task_scheduler_num_threads(task_scheduler), scanlines_per_thread;
|
|
|
|
buffer = MEM_mallocN(sizeof(float) * height * width, "rasterized mask buffer");
|
|
|
|
/* Initialize rasterization handle. */
|
|
handle = BKE_maskrasterize_handle_new();
|
|
BKE_maskrasterize_handle_init(handle, mask, width, height, true, true, true);
|
|
|
|
state.handle = handle;
|
|
state.buffer = buffer;
|
|
state.width = width;
|
|
state.height = height;
|
|
|
|
task_pool = BLI_task_pool_create(task_scheduler, &state);
|
|
|
|
scanlines_per_thread = height / num_threads;
|
|
for (i = 0; i < num_threads; i++) {
|
|
ThreadedMaskRasterizeData *data = MEM_mallocN(sizeof(ThreadedMaskRasterizeData),
|
|
"threaded mask rasterize data");
|
|
|
|
data->start_scanline = i * scanlines_per_thread;
|
|
|
|
if (i < num_threads - 1) {
|
|
data->num_scanlines = scanlines_per_thread;
|
|
}
|
|
else {
|
|
data->num_scanlines = height - data->start_scanline;
|
|
}
|
|
|
|
BLI_task_pool_push(task_pool, mask_rasterize_func, data, true, TASK_PRIORITY_LOW);
|
|
}
|
|
|
|
/* work and wait until tasks are done */
|
|
BLI_task_pool_work_and_wait(task_pool);
|
|
|
|
/* Free memory. */
|
|
BLI_task_pool_free(task_pool);
|
|
BKE_maskrasterize_handle_free(handle);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
/* sets up the opengl context.
|
|
* width, height are to match the values from ED_mask_get_size() */
|
|
void ED_mask_draw_region(Mask *mask, ARegion *ar,
|
|
const char draw_flag, const char draw_type, const char overlay_mode,
|
|
const int width_i, const int height_i, /* convert directly into aspect corrected vars */
|
|
const float aspx, const float aspy,
|
|
const bool do_scale_applied, const bool do_draw_cb,
|
|
float stabmat[4][4], /* optional - only used by clip */
|
|
const bContext *C /* optional - only used when do_post_draw is set or called from clip editor */
|
|
)
|
|
{
|
|
struct View2D *v2d = &ar->v2d;
|
|
|
|
/* aspect always scales vertically in movie and image spaces */
|
|
const float width = width_i, height = (float)height_i * (aspy / aspx);
|
|
|
|
int x, y;
|
|
/* int w, h; */
|
|
float zoomx, zoomy;
|
|
|
|
/* frame image */
|
|
float maxdim;
|
|
float xofs, yofs;
|
|
|
|
/* find window pixel coordinates of origin */
|
|
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
|
|
|
|
|
|
/* w = BLI_rctf_size_x(&v2d->tot); */
|
|
/* h = BLI_rctf_size_y(&v2d->tot); */
|
|
|
|
|
|
zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
|
|
zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur);
|
|
|
|
if (do_scale_applied) {
|
|
zoomx /= width;
|
|
zoomy /= height;
|
|
}
|
|
|
|
x += v2d->tot.xmin * zoomx;
|
|
y += v2d->tot.ymin * zoomy;
|
|
|
|
/* frame the image */
|
|
maxdim = max_ff(width, height);
|
|
if (width == height) {
|
|
xofs = yofs = 0;
|
|
}
|
|
else if (width < height) {
|
|
xofs = ((height - width) / -2.0f) * zoomx;
|
|
yofs = 0.0f;
|
|
}
|
|
else { /* (width > height) */
|
|
xofs = 0.0f;
|
|
yofs = ((width - height) / -2.0f) * zoomy;
|
|
}
|
|
|
|
if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
|
|
float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
|
|
float *buffer = threaded_mask_rasterize(mask, width, height);
|
|
|
|
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
|
|
/* More blending types could be supported in the future. */
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
|
}
|
|
|
|
gpuPushMatrix();
|
|
gpuTranslate2f(x, y);
|
|
gpuScale2f(zoomx, zoomy);
|
|
if (stabmat) {
|
|
gpuMultMatrix3D(stabmat); /* XXX make this a 2D matrix */
|
|
}
|
|
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
|
|
GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
|
|
immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
|
|
|
|
gpuPopMatrix();
|
|
|
|
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
MEM_freeN(buffer);
|
|
}
|
|
|
|
/* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
|
|
gpuPushMatrix();
|
|
|
|
if (stabmat) {
|
|
gpuMultMatrix3D(stabmat); /* XXX make this a 2D matrix */
|
|
}
|
|
|
|
gpuTranslate2f(x + xofs, y + yofs);
|
|
gpuScale2f(maxdim * zoomx, maxdim * zoomy);
|
|
|
|
if (do_draw_cb) {
|
|
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
|
|
}
|
|
|
|
/* draw! */
|
|
draw_masklays(C, mask, draw_flag, draw_type, width, height);
|
|
|
|
if (do_draw_cb) {
|
|
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
|
|
}
|
|
|
|
gpuPopMatrix();
|
|
}
|
|
|
|
void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
|
|
{
|
|
const float framelen = ar->winx / (float)(efra - sfra + 1);
|
|
|
|
MaskLayer *masklay = BKE_mask_layer_active(mask);
|
|
|
|
if (masklay) {
|
|
unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes);
|
|
|
|
if (num_lines > 0) {
|
|
unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_I32, 2, CONVERT_INT_TO_FLOAT);
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
immUniformColor4ub(255, 175, 0, 255);
|
|
|
|
immBegin(PRIM_LINES, 2 * num_lines);
|
|
|
|
for (MaskLayerShape *masklay_shape = masklay->splines_shapes.first;
|
|
masklay_shape;
|
|
masklay_shape = masklay_shape->next)
|
|
{
|
|
int frame = masklay_shape->frame;
|
|
|
|
/* draw_keyframe(i, CFRA, sfra, framelen, 1); */
|
|
int height = (frame == cfra) ? 22 : 10;
|
|
int x = (frame - sfra) * framelen;
|
|
immVertex2i(pos, x, 0);
|
|
immVertex2i(pos, x, height);
|
|
}
|
|
immEnd();
|
|
immUnbindProgram();
|
|
}
|
|
}
|
|
}
|