Implement asymmetric and free handles type for masks
[blender-staging.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
40 #include "BKE_context.h"
41 #include "BKE_mask.h"
42
43 #include "DNA_mask_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_object_types.h"   /* SELECT */
46 #include "DNA_space_types.h"
47
48 #include "ED_clip.h"
49 #include "ED_mask.h"  /* own include */
50 #include "ED_space_api.h"
51 #include "BIF_gl.h"
52 #include "BIF_glutil.h"
53
54 #include "UI_resources.h"
55 #include "UI_view2d.h"
56
57 #include "mask_intern.h"  /* own include */
58
59 static void mask_spline_color_get(MaskLayer *masklay, MaskSpline *spline, 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), MaskSpline *UNUSED(spline), const bool is_sel,
80                                           unsigned char r_rgb[4])
81 {
82         if (is_sel) {
83                 r_rgb[1] = 255;
84                 r_rgb[0] = r_rgb[2] = 0;
85         }
86         else {
87                 r_rgb[1] = 128;
88                 r_rgb[0] = r_rgb[2] = 0;
89         }
90
91         r_rgb[3] = 255;
92 }
93
94 #if 0
95 static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
96 {
97         int i;
98         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
99
100         if (!spline->tot_point)
101                 return;
102
103         glColor3ub(0, 0, 0);
104         glEnable(GL_LINE_STIPPLE);
105         glLineStipple(1, 0xAAAA);
106
107         glBegin(GL_LINES);
108
109         for (i = 0; i < spline->tot_point; i++) {
110                 MaskSplinePoint *point = &points_array[i];
111                 BezTriple *bezt = &point->bezt;
112
113                 if (point->parent.id) {
114                         glVertex2f(bezt->vec[1][0],
115                                    bezt->vec[1][1]);
116
117                         glVertex2f(bezt->vec[1][0] - point->parent.offset[0],
118                                    bezt->vec[1][1] - point->parent.offset[1]);
119                 }
120         }
121
122         glEnd();
123
124         glDisable(GL_LINE_STIPPLE);
125 }
126 #endif
127
128 static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
129 {
130         BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
131         ED_clip_point_undistorted_pos(sc, r_co, r_co);
132         BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
133 }
134
135 static void draw_circle(const float x, const float y,
136                         const float size, const float xscale, const float yscale)
137 {
138         static GLuint displist = 0;
139
140         /* Initialize round circle shape. */
141         if (displist == 0) {
142                 GLUquadricObj *qobj;
143
144                 displist = glGenLists(1);
145                 glNewList(displist, GL_COMPILE);
146
147                 qobj = gluNewQuadric();
148                 gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
149                 gluDisk(qobj, 0,  0.7, 8, 1);
150                 gluDeleteQuadric(qobj);
151
152                 glEndList();
153         }
154
155         glPushMatrix();
156         glTranslatef(x, y, 0.0f);
157         glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f);
158         glCallList(displist);
159         glPopMatrix();
160 }
161
162 static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point,
163                                const eMaskWhichHandle which_handle, const int draw_type,
164                                const float handle_size, const float xscale, const float yscale,
165                                const float point_pos[2], const float handle_pos[2])
166 {
167         const BezTriple *bezt = &point->bezt;
168         char handle_type;
169
170         if (which_handle == MASK_WHICH_HANDLE_STICK || which_handle == MASK_WHICH_HANDLE_LEFT) {
171                 handle_type = bezt->h1;
172         }
173         else {
174                 handle_type = bezt->h2;
175         }
176
177         if (handle_type == HD_VECT) {
178                 return;
179         }
180
181         /* this could be split into its own loop */
182         if (draw_type == MASK_DT_OUTLINE) {
183                 const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
184                 glLineWidth(3);
185                 glColor4ubv(rgb_gray);
186                 glBegin(GL_LINES);
187                 glVertex2fv(point_pos);
188                 glVertex2fv(handle_pos);
189                 glEnd();
190                 glLineWidth(1);
191         }
192
193         switch (handle_type) {
194                 case HD_FREE:
195                         UI_ThemeColor(TH_HANDLE_FREE);
196                         break;
197                 case HD_AUTO:
198                         UI_ThemeColor(TH_HANDLE_AUTO);
199                         break;
200                 case HD_ALIGN:
201                 case HD_ALIGN_DOUBLESIDE:
202                         UI_ThemeColor(TH_HANDLE_ALIGN);
203                         break;
204         }
205
206         glBegin(GL_LINES);
207         glVertex2fv(point_pos);
208         glVertex2fv(handle_pos);
209         glEnd();
210
211         /* draw handle points */
212         if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
213                 if (point == mask_layer->act_point)
214                         glColor3f(1.0f, 1.0f, 1.0f);
215                 else
216                         glColor3f(1.0f, 1.0f, 0.0f);
217         }
218         else {
219                 glColor3f(0.5f, 0.5f, 0.0f);
220         }
221
222         draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale);
223 }
224
225 /* return non-zero if spline is selected */
226 static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
227                                const char draw_flag, const char draw_type,
228                                const float xscale, const float yscale)
229 {
230         const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
231         const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
232
233         unsigned char rgb_spline[4];
234         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
235         SpaceClip *sc = CTX_wm_space_clip(C);
236         bool undistort = false;
237
238         int i, handle_size, tot_feather_point;
239         float (*feather_points)[2], (*fp)[2];
240
241         if (!spline->tot_point)
242                 return;
243
244         if (sc)
245                 undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
246
247         /* TODO, add this to sequence editor */
248         handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
249
250         glPointSize(handle_size);
251
252         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
253
254         /* feather points */
255         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
256         for (i = 0; i < spline->tot_point; i++) {
257
258                 /* watch it! this is intentionally not the deform array, only check for sel */
259                 MaskSplinePoint *point = &spline->points[i];
260
261                 int j;
262
263                 for (j = 0; j <= point->tot_uw; j++) {
264                         float feather_point[2];
265                         int sel = FALSE;
266
267                         copy_v2_v2(feather_point, *fp);
268
269                         if (undistort)
270                                 mask_point_undistort_pos(sc, feather_point, feather_point);
271
272                         if (j == 0) {
273                                 sel = MASKPOINT_ISSEL_ANY(point);
274                         }
275                         else {
276                                 sel = point->uw[j - 1].flag & SELECT;
277                         }
278
279                         if (sel) {
280                                 if (point == masklay->act_point)
281                                         glColor3f(1.0f, 1.0f, 1.0f);
282                                 else
283                                         glColor3f(1.0f, 1.0f, 0.0f);
284                         }
285                         else {
286                                 glColor3f(0.5f, 0.5f, 0.0f);
287                         }
288
289                         glBegin(GL_POINTS);
290                         glVertex2fv(feather_point);
291                         glEnd();
292
293                         fp++;
294                 }
295         }
296         MEM_freeN(feather_points);
297
298         if (is_smooth) {
299                 glEnable(GL_LINE_SMOOTH);
300                 glEnable(GL_BLEND);
301                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302         }
303
304         /* control points */
305         for (i = 0; i < spline->tot_point; i++) {
306
307                 /* watch it! this is intentionally not the deform array, only check for sel */
308                 MaskSplinePoint *point = &spline->points[i];
309                 MaskSplinePoint *point_deform = &points_array[i];
310                 BezTriple *bezt = &point_deform->bezt;
311
312                 float vert[2];
313
314                 copy_v2_v2(vert, bezt->vec[1]);
315
316                 if (undistort) {
317                         mask_point_undistort_pos(sc, vert, vert);
318                 }
319
320                 /* draw handle segment */
321                 if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
322                         float handle[2];
323                         BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_STICK, handle);
324                         if (undistort) {
325                                 mask_point_undistort_pos(sc, handle, handle);
326                         }
327                         draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK,
328                                            draw_type, handle_size, xscale, yscale, vert, handle);
329                 }
330                 else {
331                         float handle_left[2], handle_right[2];
332                         BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_LEFT, handle_left);
333                         BKE_mask_point_handle(point_deform, MASK_WHICH_HANDLE_RIGHT, handle_right);
334                         if (undistort) {
335                                 mask_point_undistort_pos(sc, handle_left, handle_left);
336                                 mask_point_undistort_pos(sc, handle_left, handle_left);
337                         }
338                         draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT,
339                                            draw_type, handle_size, xscale, yscale, vert, handle_left);
340                         draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT,
341                                            draw_type, handle_size, xscale, yscale, vert, handle_right);
342                 }
343
344                 /* draw CV point */
345                 if (MASKPOINT_ISSEL_KNOT(point)) {
346                         if (point == masklay->act_point)
347                                 glColor3f(1.0f, 1.0f, 1.0f);
348                         else
349                                 glColor3f(1.0f, 1.0f, 0.0f);
350                 }
351                 else
352                         glColor3f(0.5f, 0.5f, 0.0f);
353
354                 glBegin(GL_POINTS);
355                 glVertex2fv(vert);
356                 glEnd();
357         }
358
359         glPointSize(1.0f);
360
361         if (is_smooth) {
362                 glDisable(GL_LINE_SMOOTH);
363                 glDisable(GL_BLEND);
364         }
365 }
366
367 /* #define USE_XOR */
368
369 static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const short is_active)
370 {
371         if (!is_active) {
372                 r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
373                 r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
374                 r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
375                 r_rgb[3] = rgb[3];
376         }
377         else {
378                 *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
379         }
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_smooth, const bool is_active,
384                                  const unsigned char rgb_spline[4], const char draw_type)
385 {
386         const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP;
387         const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
388 //      const unsigned char rgb_white[4] = {0xff, 0xff, 0xff, 0xff};
389         unsigned char rgb_tmp[4];
390         SpaceClip *sc = CTX_wm_space_clip(C);
391         float (*points)[2] = orig_points;
392
393         if (sc) {
394                 int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
395
396                 if (undistort) {
397                         int i;
398
399                         points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
400
401                         for (i = 0; i < tot_point; i++) {
402                                 mask_point_undistort_pos(sc, points[i], orig_points[i]);
403                         }
404                 }
405         }
406
407         glEnableClientState(GL_VERTEX_ARRAY);
408         glVertexPointer(2, GL_FLOAT, 0, points);
409
410         switch (draw_type) {
411
412                 case MASK_DT_OUTLINE:
413                         glLineWidth(3);
414
415                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
416                         glColor4ubv(rgb_tmp);
417
418                         glDrawArrays(draw_method, 0, tot_point);
419
420                         glLineWidth(1);
421                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
422                         glColor4ubv(rgb_tmp);
423                         glDrawArrays(draw_method, 0, tot_point);
424
425                         break;
426
427                 case MASK_DT_DASH:
428                 default:
429                         glEnable(GL_LINE_STIPPLE);
430
431 #ifdef USE_XOR
432                         glEnable(GL_COLOR_LOGIC_OP);
433                         glLogicOp(GL_OR);
434 #endif
435                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
436                         glColor4ubv(rgb_tmp);
437                         glLineStipple(3, 0xaaaa);
438                         glEnableClientState(GL_VERTEX_ARRAY);
439                         glVertexPointer(2, GL_FLOAT, 0, points);
440                         glDrawArrays(draw_method, 0, tot_point);
441
442 #ifdef USE_XOR
443                         glDisable(GL_COLOR_LOGIC_OP);
444 #endif
445                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
446                         glColor4ubv(rgb_tmp);
447                         glLineStipple(3, 0x5555);
448                         glDrawArrays(draw_method, 0, tot_point);
449
450                         glDisable(GL_LINE_STIPPLE);
451                         break;
452
453
454                 case MASK_DT_BLACK:
455                 case MASK_DT_WHITE:
456                         if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0;   }
457                         else                            { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
458                         /* alpha values seem too low but gl draws many points that compensate for it */
459                         if (is_feather) { rgb_tmp[3] = 64; }
460                         else            { rgb_tmp[3] = 128; }
461
462                         if (is_feather) {
463                                 rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
464                                 rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
465                                 rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
466                         }
467
468                         if (is_smooth == FALSE && is_feather) {
469                                 glEnable(GL_BLEND);
470                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
471                         }
472
473                         mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
474                         glColor4ubv(rgb_tmp);
475
476                         glEnableClientState(GL_VERTEX_ARRAY);
477                         glVertexPointer(2, GL_FLOAT, 0, points);
478                         glDrawArrays(draw_method, 0, tot_point);
479
480                         if (is_smooth == FALSE && is_feather) {
481                                 glDisable(GL_BLEND);
482                         }
483
484                         break;
485         }
486
487         glDisableClientState(GL_VERTEX_ARRAY);
488
489         if (points != orig_points)
490                 MEM_freeN(points);
491 }
492
493 static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
494                               const char draw_flag, const char draw_type,
495                               const bool is_active,
496                               const int width, const int height)
497 {
498         const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
499                                           BKE_mask_spline_resolution(spline, width, height));
500
501         unsigned char rgb_tmp[4];
502
503         const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
504         const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
505         const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
506
507         unsigned int tot_diff_point;
508         float (*diff_points)[2];
509
510         unsigned int tot_feather_point;
511         float (*feather_points)[2];
512
513         diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
514
515         if (!diff_points)
516                 return;
517
518         if (is_smooth) {
519                 glEnable(GL_LINE_SMOOTH);
520                 glEnable(GL_BLEND);
521                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
522         }
523
524         feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != FALSE));
525
526         /* draw feather */
527         mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
528         mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
529                              TRUE, is_smooth, is_active,
530                              rgb_tmp, draw_type);
531
532         if (!is_fill) {
533
534                 float *fp         = &diff_points[0][0];
535                 float *fp_feather = &feather_points[0][0];
536                 float tvec[2];
537                 int i;
538
539                 BLI_assert(tot_diff_point == tot_feather_point);
540
541                 for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
542                         sub_v2_v2v2(tvec, fp, fp_feather);
543                         add_v2_v2v2(fp_feather, fp, tvec);
544                 }
545
546                 /* same as above */
547                 mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
548                                      TRUE, is_smooth, is_active,
549                                      rgb_tmp, draw_type);
550         }
551
552         MEM_freeN(feather_points);
553
554         /* draw main curve */
555         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
556         mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
557                              FALSE, is_smooth, is_active,
558                              rgb_tmp, draw_type);
559         MEM_freeN(diff_points);
560
561         if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
562                 glDisable(GL_LINE_SMOOTH);
563                 glDisable(GL_BLEND);
564         }
565
566         (void)draw_type;
567 }
568
569 static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
570                           const int width, const int height, const float xscale, const float yscale)
571 {
572         MaskLayer *masklay;
573         int i;
574
575         for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
576                 MaskSpline *spline;
577                 const bool is_active = (i == mask->masklay_act);
578
579                 if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
580                         continue;
581                 }
582
583                 for (spline = masklay->splines.first; spline; spline = spline->next) {
584
585                         /* draw curve itself first... */
586                         draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
587
588 //                      draw_spline_parents(masklay, spline);
589
590                         if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
591                                 /* ...and then handles over the curve so they're nicely visible */
592                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
593                         }
594
595                         /* show undeform for testing */
596                         if (0) {
597                                 void *back = spline->points_deform;
598
599                                 spline->points_deform = NULL;
600                                 draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
601 //                              draw_spline_parents(masklay, spline);
602                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
603                                 spline->points_deform = back;
604                         }
605                 }
606         }
607 }
608
609 void ED_mask_draw(const bContext *C,
610                   const char draw_flag, const char draw_type)
611 {
612         ScrArea *sa = CTX_wm_area(C);
613         ARegion *ar = CTX_wm_region(C);
614
615         Mask *mask = CTX_data_edit_mask(C);
616         int width, height;
617         float aspx, aspy;
618         float xscale, yscale;
619
620         if (!mask)
621                 return;
622
623         ED_mask_get_size(sa, &width, &height);
624         ED_mask_get_aspect(sa, ar, &aspx, &aspy);
625         UI_view2d_getscale(&ar->v2d, &xscale, &yscale);
626
627         draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy);
628 }
629
630 typedef struct ThreadedMaskRasterizeState {
631         MaskRasterHandle *handle;
632         float *buffer;
633         int width, height;
634 } ThreadedMaskRasterizeState;
635
636 typedef struct ThreadedMaskRasterizeData {
637         int start_scanline;
638         int num_scanlines;
639 } ThreadedMaskRasterizeData;
640
641 static void mask_rasterize_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
642 {
643         ThreadedMaskRasterizeState *state = (ThreadedMaskRasterizeState *) BLI_task_pool_userdata(pool);
644         ThreadedMaskRasterizeData *data = (ThreadedMaskRasterizeData *) taskdata;
645         int scanline;
646
647         for (scanline = 0; scanline < data->num_scanlines; scanline++) {
648                 int x, y = data->start_scanline + scanline;
649                 for (x = 0; x < state->width; x++) {
650                         int index = y * state->width + x;
651                         float xy[2];
652
653                         xy[0] = (float) x / state->width;
654                         xy[1] = (float) y / state->height;
655
656                         state->buffer[index] = BKE_maskrasterize_handle_sample(state->handle, xy);
657                 }
658         }
659 }
660
661 static float *threaded_mask_rasterize(Mask *mask, const int width, const int height)
662 {
663         TaskScheduler *task_scheduler = BLI_task_scheduler_get();
664         TaskPool *task_pool;
665         MaskRasterHandle *handle;
666         ThreadedMaskRasterizeState state;
667         float *buffer;
668         int i, num_threads = BLI_task_scheduler_num_threads(task_scheduler), scanlines_per_thread;
669
670         buffer = MEM_mallocN(sizeof(float) * height * width, "rasterized mask buffer");
671
672         /* Initialize rasterization handle. */
673         handle = BKE_maskrasterize_handle_new();
674         BKE_maskrasterize_handle_init(handle, mask, width, height, TRUE, TRUE, TRUE);
675
676         state.handle = handle;
677         state.buffer = buffer;
678         state.width = width;
679         state.height = height;
680
681         task_pool = BLI_task_pool_create(task_scheduler, &state);
682
683         scanlines_per_thread = height / num_threads;
684         for (i = 0; i < num_threads; i++) {
685                 ThreadedMaskRasterizeData *data = MEM_mallocN(sizeof(ThreadedMaskRasterizeData),
686                                                                 "threaded mask rasterize data");
687
688                 data->start_scanline = i * scanlines_per_thread;
689
690                 if (i < num_threads - 1) {
691                         data->num_scanlines = scanlines_per_thread;
692                 }
693                 else {
694                         data->num_scanlines = height - data->start_scanline;
695                 }
696
697                 BLI_task_pool_push(task_pool, mask_rasterize_func, data, true, TASK_PRIORITY_LOW);
698         }
699
700         /* work and wait until tasks are done */
701         BLI_task_pool_work_and_wait(task_pool);
702
703         /* Free memory. */
704         BLI_task_pool_free(task_pool);
705         BKE_maskrasterize_handle_free(handle);
706
707         return buffer;
708 }
709
710 /* sets up the opengl context.
711  * width, height are to match the values from ED_mask_get_size() */
712 void ED_mask_draw_region(Mask *mask, ARegion *ar,
713                          const char draw_flag, const char draw_type, const char overlay_mode,
714                          const int width_i, const int height_i,  /* convert directly into aspect corrected vars */
715                          const float aspx, const float aspy,
716                          const bool do_scale_applied, const bool do_draw_cb,
717                          float stabmat[4][4], /* optional - only used by clip */
718                          const bContext *C    /* optional - only used when do_post_draw is set or called from clip editor */
719                          )
720 {
721         struct View2D *v2d = &ar->v2d;
722
723         /* aspect always scales vertically in movie and image spaces */
724         const float width = width_i, height = (float)height_i * (aspy / aspx);
725
726         int x, y;
727         /* int w, h; */
728         float zoomx, zoomy;
729
730         /* frame image */
731         float maxdim;
732         float xofs, yofs;
733
734         /* find window pixel coordinates of origin */
735         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
736
737
738         /* w = BLI_rctf_size_x(&v2d->tot); */
739         /* h = BLI_rctf_size_y(&v2d->tot);/*/
740
741
742         zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
743         zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur);
744
745         if (do_scale_applied) {
746                 zoomx /= width;
747                 zoomy /= height;
748         }
749
750         x += v2d->tot.xmin * zoomx;
751         y += v2d->tot.ymin * zoomy;
752
753         /* frame the image */
754         maxdim = max_ff(width, height);
755         if (width == height) {
756                 xofs = yofs = 0;
757         }
758         else if (width < height) {
759                 xofs = ((height - width) / -2.0f) * zoomx;
760                 yofs = 0.0f;
761         }
762         else { /* (width > height) */
763                 xofs = 0.0f;
764                 yofs = ((width - height) / -2.0f) * zoomy;
765         }
766
767         if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
768                 float *buffer = threaded_mask_rasterize(mask, width, height);
769                 int format;
770
771                 if (overlay_mode == MASK_OVERLAY_ALPHACHANNEL) {
772                         glColor3f(1.0f, 1.0f, 1.0f);
773                         format = GL_LUMINANCE;
774                 }
775                 else {
776                         /* More blending types could be supported in the future. */
777                         glEnable(GL_BLEND);
778                         glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
779                         format = GL_ALPHA;
780                 }
781
782                 glPushMatrix();
783                 glTranslatef(x, y, 0);
784                 glScalef(zoomx, zoomy, 0);
785                 if (stabmat) {
786                         glMultMatrixf(stabmat);
787                 }
788                 glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer);
789                 glPopMatrix();
790
791                 if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
792                         glDisable(GL_BLEND);
793                 }
794
795                 MEM_freeN(buffer);
796         }
797
798         /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
799         glPushMatrix();
800         glTranslatef(x + xofs, y + yofs, 0);
801         glScalef(maxdim * zoomx, maxdim * zoomy, 0);
802
803         if (stabmat) {
804                 glMultMatrixf(stabmat);
805         }
806
807         if (do_draw_cb) {
808                 ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
809         }
810
811         /* draw! */
812         draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy);
813
814         if (do_draw_cb) {
815                 ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
816         }
817
818         glPopMatrix();
819 }
820
821 void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
822 {
823         const float framelen = ar->winx / (float)(efra - sfra + 1);
824
825         MaskLayer *masklay = BKE_mask_layer_active(mask);
826
827         glBegin(GL_LINES);
828         glColor4ub(255, 175, 0, 255);
829
830         if (masklay) {
831                 MaskLayerShape *masklay_shape;
832
833                 for (masklay_shape = masklay->splines_shapes.first;
834                      masklay_shape;
835                      masklay_shape = masklay_shape->next)
836                 {
837                         int frame = masklay_shape->frame;
838
839                         /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
840                         int height = (frame == cfra) ? 22 : 10;
841                         int x = (frame - sfra) * framelen;
842                         glVertex2i(x, 0);
843                         glVertex2i(x, height);
844                 }
845         }
846
847         glEnd();
848 }