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