d9ca58fa88ccdae5bbc90946dc7ec82ce12c9053
[blender.git] / source / blender / editors / mask / mask_draw.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edmask
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_utildefines.h"
27 #include "BLI_math.h"
28 #include "BLI_rect.h"
29 #include "BLI_listbase.h"
30
31 #include "BKE_context.h"
32 #include "BKE_mask.h"
33
34 #include "DNA_mask_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_object_types.h" /* SELECT */
37 #include "DNA_space_types.h"
38
39 #include "ED_clip.h"
40 #include "ED_mask.h" /* own include */
41 #include "ED_space_api.h"
42
43 #include "BIF_glutil.h"
44
45 #include "GPU_immediate.h"
46 #include "GPU_draw.h"
47 #include "GPU_shader.h"
48 #include "GPU_matrix.h"
49 #include "GPU_state.h"
50
51 #include "UI_interface.h"
52 #include "UI_resources.h"
53 #include "UI_view2d.h"
54
55 #include "DEG_depsgraph_query.h"
56
57 #include "mask_intern.h" /* own include */
58
59 static void mask_spline_color_get(MaskLayer *masklay,
60                                   MaskSpline *spline,
61                                   const bool is_sel,
62                                   unsigned char r_rgb[4])
63 {
64   if (is_sel) {
65     if (masklay->act_spline == spline) {
66       r_rgb[0] = r_rgb[1] = r_rgb[2] = 255;
67     }
68     else {
69       r_rgb[0] = 255;
70       r_rgb[1] = r_rgb[2] = 0;
71     }
72   }
73   else {
74     r_rgb[0] = 128;
75     r_rgb[1] = r_rgb[2] = 0;
76   }
77
78   r_rgb[3] = 255;
79 }
80
81 static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay),
82                                           MaskSpline *UNUSED(spline),
83                                           const bool is_sel,
84                                           unsigned char r_rgb[4])
85 {
86   if (is_sel) {
87     r_rgb[1] = 255;
88     r_rgb[0] = r_rgb[2] = 0;
89   }
90   else {
91     r_rgb[1] = 128;
92     r_rgb[0] = r_rgb[2] = 0;
93   }
94
95   r_rgb[3] = 255;
96 }
97
98 static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
99 {
100   BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
101   ED_clip_point_undistorted_pos(sc, r_co, r_co);
102   BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
103 }
104
105 static void draw_single_handle(const MaskLayer *mask_layer,
106                                const MaskSplinePoint *point,
107                                const eMaskWhichHandle which_handle,
108                                const int draw_type,
109                                const float handle_size,
110                                const float point_pos[2],
111                                const float handle_pos[2])
112 {
113   const BezTriple *bezt = &point->bezt;
114   char handle_type;
115
116   if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) {
117     handle_type = bezt->h1;
118   }
119   else {
120     handle_type = bezt->h2;
121   }
122
123   if (handle_type == HD_VECT) {
124     return;
125   }
126
127   GPUVertFormat *format = immVertexFormat();
128   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
129   const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
130
131   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
132   immUniformColor3ubv(rgb_gray);
133
134   /* this could be split into its own loop */
135   if (draw_type == MASK_DT_OUTLINE) {
136     GPU_line_width(3.0f);
137     immBegin(GPU_PRIM_LINES, 2);
138     immVertex2fv(pos, point_pos);
139     immVertex2fv(pos, handle_pos);
140     immEnd();
141   }
142
143   switch (handle_type) {
144     case HD_FREE:
145       immUniformThemeColor(TH_HANDLE_FREE);
146       break;
147     case HD_AUTO:
148       immUniformThemeColor(TH_HANDLE_AUTO);
149       break;
150     case HD_ALIGN:
151     case HD_ALIGN_DOUBLESIDE:
152       immUniformThemeColor(TH_HANDLE_ALIGN);
153       break;
154   }
155
156   GPU_line_width(1.0f);
157   immBegin(GPU_PRIM_LINES, 2);
158   immVertex2fv(pos, point_pos);
159   immVertex2fv(pos, handle_pos);
160   immEnd();
161   immUnbindProgram();
162
163   /* draw handle points */
164   immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
165   immUniform1f("size", handle_size);
166   immUniform1f("outlineWidth", 1.5f);
167
168   float point_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; /* active color by default */
169   if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
170     if (point != mask_layer->act_point) {
171       UI_GetThemeColor3fv(TH_HANDLE_VERTEX_SELECT, point_color);
172     }
173   }
174   else {
175     UI_GetThemeColor3fv(TH_HANDLE_VERTEX, point_color);
176   }
177
178   immUniform4fv("outlineColor", point_color);
179   immUniformColor3fvAlpha(point_color, 0.25f);
180
181   immBegin(GPU_PRIM_POINTS, 1);
182   immVertex2fv(pos, handle_pos);
183   immEnd();
184
185   immUnbindProgram();
186 }
187
188 /* return non-zero if spline is selected */
189 static void draw_spline_points(const bContext *C,
190                                MaskLayer *masklay,
191                                MaskSpline *spline,
192                                const char draw_flag,
193                                const char draw_type)
194 {
195   const bool is_spline_sel = (spline->flag & SELECT) &&
196                              (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
197   const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
198
199   unsigned char rgb_spline[4];
200   MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
201   SpaceClip *sc = CTX_wm_space_clip(C);
202   bool undistort = false;
203
204   int tot_feather_point;
205   float(*feather_points)[2], (*fp)[2];
206   float min[2], max[2];
207
208   if (!spline->tot_point) {
209     return;
210   }
211
212   if (sc) {
213     undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
214   }
215
216   /* TODO, add this to sequence editor */
217   float handle_size = 2.0f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
218
219   mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
220
221   GPUVertFormat *format = immVertexFormat();
222   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
223
224   immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
225   immUniform1f("size", 0.7f * handle_size);
226
227   /* feather points */
228   feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
229   for (int i = 0; i < spline->tot_point; i++) {
230
231     /* watch it! this is intentionally not the deform array, only check for sel */
232     MaskSplinePoint *point = &spline->points[i];
233
234     for (int j = 0; j <= point->tot_uw; j++) {
235       float feather_point[2];
236       bool sel = false;
237
238       copy_v2_v2(feather_point, *fp);
239
240       if (undistort) {
241         mask_point_undistort_pos(sc, feather_point, feather_point);
242       }
243
244       if (j == 0) {
245         sel = MASKPOINT_ISSEL_ANY(point);
246       }
247       else {
248         sel = (point->uw[j - 1].flag & SELECT) != 0;
249       }
250
251       if (sel) {
252         if (point == masklay->act_point) {
253           immUniformColor3f(1.0f, 1.0f, 1.0f);
254         }
255         else {
256           immUniformThemeColorShadeAlpha(TH_HANDLE_VERTEX_SELECT, 0, 255);
257         }
258       }
259       else {
260         immUniformThemeColorShadeAlpha(TH_HANDLE_VERTEX, 0, 255);
261       }
262
263       immBegin(GPU_PRIM_POINTS, 1);
264       immVertex2fv(pos, feather_point);
265       immEnd();
266
267       fp++;
268     }
269   }
270   MEM_freeN(feather_points);
271
272   immUnbindProgram();
273
274   if (is_smooth) {
275     GPU_line_smooth(true);
276   }
277
278   /* control points */
279   INIT_MINMAX2(min, max);
280   for (int i = 0; i < spline->tot_point; i++) {
281
282     /* watch it! this is intentionally not the deform array, only check for sel */
283     MaskSplinePoint *point = &spline->points[i];
284     MaskSplinePoint *point_deform = &points_array[i];
285     BezTriple *bezt = &point_deform->bezt;
286
287     float vert[2];
288
289     copy_v2_v2(vert, bezt->vec[1]);
290
291     if (undistort) {
292       mask_point_undistort_pos(sc, vert, vert);
293     }
294
295     /* draw handle segment */
296     if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
297       float handle[2];
298       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle);
299       if (undistort) {
300         mask_point_undistort_pos(sc, handle, handle);
301       }
302       draw_single_handle(
303           masklay, point, MASK_WHICH_HANDLE_STICK, draw_type, handle_size, vert, handle);
304     }
305     else {
306       float handle_left[2], handle_right[2];
307       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left);
308       BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right);
309       if (undistort) {
310         mask_point_undistort_pos(sc, handle_left, handle_left);
311         mask_point_undistort_pos(sc, handle_left, handle_left);
312       }
313       draw_single_handle(
314           masklay, point, MASK_WHICH_HANDLE_LEFT, draw_type, handle_size, vert, handle_left);
315       draw_single_handle(
316           masklay, point, MASK_WHICH_HANDLE_RIGHT, draw_type, handle_size, vert, handle_right);
317     }
318
319     /* bind program in loop so it does not interfere with draw_single_handle */
320     immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
321
322     /* draw CV point */
323     if (MASKPOINT_ISSEL_KNOT(point)) {
324       if (point == masklay->act_point) {
325         immUniformColor3f(1.0f, 1.0f, 1.0f);
326       }
327       else {
328         immUniformThemeColorShadeAlpha(TH_HANDLE_VERTEX_SELECT, 0, 255);
329       }
330     }
331     else {
332       immUniformThemeColorShadeAlpha(TH_HANDLE_VERTEX, 0, 255);
333     }
334
335     immBegin(GPU_PRIM_POINTS, 1);
336     immVertex2fv(pos, vert);
337     immEnd();
338
339     immUnbindProgram();
340
341     minmax_v2v2_v2(min, max, vert);
342   }
343
344   if (is_smooth) {
345     GPU_line_smooth(false);
346   }
347
348   if (is_spline_sel) {
349     float x = (min[0] + max[0]) * 0.5f;
350     float y = (min[1] + max[1]) * 0.5f;
351
352     immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
353     immUniform1f("outlineWidth", 1.5f);
354
355     if (masklay->act_spline == spline) {
356       immUniformColor3f(1.0f, 1.0f, 1.0f);
357     }
358     else {
359       immUniformColor3f(1.0f, 1.0f, 0.0f);
360     }
361
362     immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f);
363     immUniform1f("size", 12.0f);
364
365     immBegin(GPU_PRIM_POINTS, 1);
366     immVertex2f(pos, x, y);
367     immEnd();
368
369     immUnbindProgram();
370   }
371 }
372
373 static void mask_color_active_tint(unsigned char r_rgb[4],
374                                    const unsigned char rgb[4],
375                                    const bool is_active)
376 {
377   if (!is_active) {
378     r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
379     r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
380     r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
381     r_rgb[3] = rgb[3];
382   }
383   else {
384     *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
385   }
386 }
387
388 static void mask_draw_array(unsigned int pos,
389                             GPUPrimType prim_type,
390                             const float (*points)[2],
391                             unsigned int vertex_len)
392 {
393   immBegin(prim_type, vertex_len);
394   for (unsigned int i = 0; i < vertex_len; ++i) {
395     immVertex2fv(pos, points[i]);
396   }
397   immEnd();
398 }
399
400 static void mask_draw_curve_type(const bContext *C,
401                                  MaskSpline *spline,
402                                  float (*orig_points)[2],
403                                  int tot_point,
404                                  const bool is_feather,
405                                  const bool is_active,
406                                  const unsigned char rgb_spline[4],
407                                  const char draw_type)
408 {
409   const GPUPrimType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GPU_PRIM_LINE_LOOP :
410                                                                         GPU_PRIM_LINE_STRIP;
411   const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
412   unsigned char rgb_tmp[4];
413   SpaceClip *sc = CTX_wm_space_clip(C);
414   float(*points)[2] = orig_points;
415
416   if (sc) {
417     const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
418
419     if (undistort) {
420       points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
421
422       for (int i = 0; i < tot_point; i++) {
423         mask_point_undistort_pos(sc, points[i], orig_points[i]);
424       }
425     }
426   }
427
428   GPUVertFormat *format = immVertexFormat();
429   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
430
431   switch (draw_type) {
432
433     case MASK_DT_OUTLINE:
434       /* TODO(merwin): use fancy line shader here
435        * probably better with geometry shader (after core profile switch)
436        */
437       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
438
439       GPU_line_width(3.0f);
440
441       mask_color_active_tint(rgb_tmp, rgb_black, is_active);
442       immUniformColor4ubv(rgb_tmp);
443       mask_draw_array(pos, draw_method, points, tot_point);
444
445       GPU_line_width(1.0f);
446
447       mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
448       immUniformColor4ubv(rgb_tmp);
449       mask_draw_array(pos, draw_method, points, tot_point);
450
451       immUnbindProgram();
452       break;
453
454     case MASK_DT_BLACK:
455     case MASK_DT_WHITE:
456       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
457       GPU_line_width(1.0f);
458
459       if (draw_type == MASK_DT_BLACK) {
460         rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0;
461       }
462       else {
463         rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255;
464       }
465       /* alpha values seem too low but gl draws many points that compensate for it */
466       if (is_feather) {
467         rgb_tmp[3] = 64;
468       }
469       else {
470         rgb_tmp[3] = 128;
471       }
472
473       if (is_feather) {
474         rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
475         rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
476         rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
477       }
478
479       mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
480       immUniformColor4ubv(rgb_tmp);
481       mask_draw_array(pos, draw_method, points, tot_point);
482
483       immUnbindProgram();
484       break;
485
486     case MASK_DT_DASH: {
487       float colors[8];
488
489       mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
490       rgba_uchar_to_float(colors, rgb_tmp);
491       mask_color_active_tint(rgb_tmp, rgb_black, is_active);
492       rgba_uchar_to_float(colors + 4, rgb_tmp);
493
494       immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
495
496       float viewport_size[4];
497       GPU_viewport_size_get_f(viewport_size);
498       immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
499
500       immUniform1i("colors_len", 2); /* "advanced" mode */
501       immUniformArray4fv("colors", colors, 2);
502       immUniform1f("dash_width", 4.0f);
503       GPU_line_width(1.0f);
504
505       mask_draw_array(pos, draw_method, points, tot_point);
506
507       immUnbindProgram();
508       break;
509     }
510
511     default:
512       BLI_assert(false);
513   }
514
515   if (points != orig_points) {
516     MEM_freeN(points);
517   }
518 }
519
520 static void draw_spline_curve(const bContext *C,
521                               MaskLayer *masklay,
522                               MaskSpline *spline,
523                               const char draw_flag,
524                               const char draw_type,
525                               const bool is_active,
526                               const int width,
527                               const int height)
528 {
529   const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
530                                     BKE_mask_spline_resolution(spline, width, height));
531
532   unsigned char rgb_tmp[4];
533
534   const bool is_spline_sel = (spline->flag & SELECT) &&
535                              (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
536   const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
537   const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
538
539   unsigned int tot_diff_point;
540   float(*diff_points)[2];
541
542   unsigned int tot_feather_point;
543   float(*feather_points)[2];
544
545   diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
546
547   if (!diff_points) {
548     return;
549   }
550
551   if (is_smooth) {
552     GPU_line_smooth(true);
553   }
554
555   feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
556       spline, &tot_feather_point, resol, (is_fill != false));
557
558   /* draw feather */
559   mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
560   mask_draw_curve_type(
561       C, spline, feather_points, tot_feather_point, true, is_active, rgb_tmp, draw_type);
562
563   if (!is_fill) {
564     const float *fp = &diff_points[0][0];
565     float *fp_feather = &feather_points[0][0];
566
567     BLI_assert(tot_diff_point == tot_feather_point);
568
569     for (int i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
570       float tvec[2];
571       sub_v2_v2v2(tvec, fp, fp_feather);
572       add_v2_v2v2(fp_feather, fp, tvec);
573     }
574
575     /* same as above */
576     mask_draw_curve_type(
577         C, spline, feather_points, tot_feather_point, true, is_active, rgb_tmp, draw_type);
578   }
579
580   MEM_freeN(feather_points);
581
582   /* draw main curve */
583   mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
584   mask_draw_curve_type(
585       C, spline, diff_points, tot_diff_point, false, is_active, rgb_tmp, draw_type);
586   MEM_freeN(diff_points);
587
588   if (is_smooth) {
589     GPU_line_smooth(false);
590   }
591 }
592
593 static void draw_masklays(const bContext *C,
594                           Mask *mask,
595                           const char draw_flag,
596                           const char draw_type,
597                           const int width,
598                           const int height)
599 {
600   GPU_blend(true);
601   GPU_blend_set_func_separate(
602       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
603   GPU_program_point_size(true);
604
605   MaskLayer *masklay;
606   int i;
607
608   for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
609     MaskSpline *spline;
610     const bool is_active = (i == mask->masklay_act);
611
612     if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
613       continue;
614     }
615
616     for (spline = masklay->splines.first; spline; spline = spline->next) {
617
618       /* draw curve itself first... */
619       draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
620
621       if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
622         /* ...and then handles over the curve so they're nicely visible */
623         draw_spline_points(C, masklay, spline, draw_flag, draw_type);
624       }
625
626       /* show undeform for testing */
627       if (0) {
628         void *back = spline->points_deform;
629
630         spline->points_deform = NULL;
631         draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
632         draw_spline_points(C, masklay, spline, draw_flag, draw_type);
633         spline->points_deform = back;
634       }
635     }
636   }
637
638   GPU_program_point_size(false);
639   GPU_blend(false);
640 }
641
642 void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
643 {
644   ScrArea *sa = CTX_wm_area(C);
645   Mask *mask = CTX_data_edit_mask(C);
646   int width, height;
647
648   if (!mask) {
649     return;
650   }
651
652   ED_mask_get_size(sa, &width, &height);
653
654   draw_masklays(C, mask, draw_flag, draw_type, width, height);
655 }
656
657 static float *mask_rasterize(Mask *mask, const int width, const int height)
658 {
659   MaskRasterHandle *handle;
660   float *buffer = MEM_mallocN(sizeof(float) * height * width, "rasterized mask buffer");
661
662   /* Initialize rasterization handle. */
663   handle = BKE_maskrasterize_handle_new();
664   BKE_maskrasterize_handle_init(handle, mask, width, height, true, true, true);
665
666   BKE_maskrasterize_buffer(handle, width, height, buffer);
667
668   /* Free memory. */
669   BKE_maskrasterize_handle_free(handle);
670
671   return buffer;
672 }
673
674 /* sets up the opengl context.
675  * width, height are to match the values from ED_mask_get_size() */
676 void ED_mask_draw_region(
677     Depsgraph *depsgraph,
678     Mask *mask_,
679     ARegion *ar,
680     const char draw_flag,
681     const char draw_type,
682     const char overlay_mode,
683     /* convert directly into aspect corrected vars */
684     const int width_i,
685     const int height_i,
686     const float aspx,
687     const float aspy,
688     const bool do_scale_applied,
689     const bool do_draw_cb,
690     /* optional - only used by clip */
691     float stabmat[4][4],
692     /* optional - only used when do_post_draw is set or called from clip editor */
693     const bContext *C)
694 {
695   struct View2D *v2d = &ar->v2d;
696   Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_->id);
697
698   /* aspect always scales vertically in movie and image spaces */
699   const float width = width_i, height = (float)height_i * (aspy / aspx);
700
701   int x, y;
702   /* int w, h; */
703   float zoomx, zoomy;
704
705   /* frame image */
706   float maxdim;
707   float xofs, yofs;
708
709   /* find window pixel coordinates of origin */
710   UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
711
712   /* w = BLI_rctf_size_x(&v2d->tot); */
713   /* h = BLI_rctf_size_y(&v2d->tot); */
714
715   zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
716   zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur);
717
718   if (do_scale_applied) {
719     zoomx /= width;
720     zoomy /= height;
721   }
722
723   x += v2d->tot.xmin * zoomx;
724   y += v2d->tot.ymin * zoomy;
725
726   /* frame the image */
727   maxdim = max_ff(width, height);
728   if (width == height) {
729     xofs = yofs = 0;
730   }
731   else if (width < height) {
732     xofs = ((height - width) / -2.0f) * zoomx;
733     yofs = 0.0f;
734   }
735   else { /* (width > height) */
736     xofs = 0.0f;
737     yofs = ((width - height) / -2.0f) * zoomy;
738   }
739
740   if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
741     float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
742     float *buffer = mask_rasterize(mask_eval, width, height);
743
744     if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
745       /* More blending types could be supported in the future. */
746       GPU_blend(true);
747       GPU_blend_set_func(GPU_DST_COLOR, GPU_ZERO);
748     }
749
750     GPU_matrix_push();
751     GPU_matrix_translate_2f(x, y);
752     GPU_matrix_scale_2f(zoomx, zoomy);
753     if (stabmat) {
754       GPU_matrix_mul(stabmat);
755     }
756     IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
757     GPU_shader_uniform_vector(
758         state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
759     immDrawPixelsTex(
760         &state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
761
762     GPU_matrix_pop();
763
764     if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
765       GPU_blend(false);
766     }
767
768     MEM_freeN(buffer);
769   }
770
771   /* apply transformation so mask editing tools will assume drawing from the
772    * origin in normalized space */
773   GPU_matrix_push();
774   GPU_matrix_translate_2f(x + xofs, y + yofs);
775   GPU_matrix_scale_2f(zoomx, zoomy);
776   if (stabmat) {
777     GPU_matrix_mul(stabmat);
778   }
779   GPU_matrix_scale_2f(maxdim, maxdim);
780
781   if (do_draw_cb) {
782     ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
783   }
784
785   /* draw! */
786   draw_masklays(C, mask_eval, draw_flag, draw_type, width, height);
787
788   if (do_draw_cb) {
789     ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
790   }
791
792   GPU_matrix_pop();
793 }
794
795 void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
796 {
797   const float framelen = ar->winx / (float)(efra - sfra + 1);
798
799   MaskLayer *masklay = BKE_mask_layer_active(mask);
800
801   if (masklay) {
802     unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes);
803
804     if (num_lines > 0) {
805       uint pos = GPU_vertformat_attr_add(
806           immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
807
808       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
809       immUniformColor4ub(255, 175, 0, 255);
810
811       immBegin(GPU_PRIM_LINES, 2 * num_lines);
812
813       for (MaskLayerShape *masklay_shape = masklay->splines_shapes.first; masklay_shape;
814            masklay_shape = masklay_shape->next) {
815         int frame = masklay_shape->frame;
816
817         /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
818         int height = (frame == cfra) ? 22 : 10;
819         int x = (frame - sfra) * framelen;
820         immVertex2i(pos, x, 0);
821         immVertex2i(pos, x, height);
822       }
823       immEnd();
824       immUnbindProgram();
825     }
826   }
827 }