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