24fcbd19fc1f6c51cd70abe23b8ab287b0b83f3b
[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
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 /* return non-zero if spline is selected */
136 static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
137                                const char UNUSED(draw_flag), const char draw_type)
138 {
139         const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
140         unsigned char rgb_spline[4];
141         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
142         SpaceClip *sc = CTX_wm_space_clip(C);
143         int undistort = FALSE;
144
145         int i, hsize, tot_feather_point;
146         float (*feather_points)[2], (*fp)[2];
147
148         if (!spline->tot_point)
149                 return;
150
151         if (sc)
152                 undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
153
154         /* TODO, add this to sequence editor */
155         hsize = 4; /* UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); */
156
157         glPointSize(hsize);
158
159         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
160
161         /* feather points */
162         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
163         for (i = 0; i < spline->tot_point; i++) {
164
165                 /* watch it! this is intentionally not the deform array, only check for sel */
166                 MaskSplinePoint *point = &spline->points[i];
167
168                 int j;
169
170                 for (j = 0; j <= point->tot_uw; j++) {
171                         float feather_point[2];
172                         int sel = FALSE;
173
174                         copy_v2_v2(feather_point, *fp);
175
176                         if (undistort)
177                                 mask_point_undistort_pos(sc, feather_point, feather_point);
178
179                         if (j == 0) {
180                                 sel = MASKPOINT_ISSEL_ANY(point);
181                         }
182                         else {
183                                 sel = point->uw[j - 1].flag & SELECT;
184                         }
185
186                         if (sel) {
187                                 if (point == masklay->act_point)
188                                         glColor3f(1.0f, 1.0f, 1.0f);
189                                 else
190                                         glColor3f(1.0f, 1.0f, 0.0f);
191                         }
192                         else {
193                                 glColor3f(0.5f, 0.5f, 0.0f);
194                         }
195
196                         glBegin(GL_POINTS);
197                         glVertex2fv(feather_point);
198                         glEnd();
199
200                         fp++;
201                 }
202         }
203         MEM_freeN(feather_points);
204
205         /* control points */
206         for (i = 0; i < spline->tot_point; i++) {
207
208                 /* watch it! this is intentionally not the deform array, only check for sel */
209                 MaskSplinePoint *point = &spline->points[i];
210                 MaskSplinePoint *point_deform = &points_array[i];
211                 BezTriple *bezt = &point_deform->bezt;
212
213                 float handle[2];
214                 float vert[2];
215                 const bool has_handle = BKE_mask_point_has_handle(point);
216
217                 copy_v2_v2(vert, bezt->vec[1]);
218                 BKE_mask_point_handle(point_deform, handle);
219
220                 if (undistort) {
221                         mask_point_undistort_pos(sc, vert, vert);
222                         mask_point_undistort_pos(sc, handle, handle);
223                 }
224
225                 /* draw handle segment */
226                 if (has_handle) {
227
228                         /* this could be split into its own loop */
229                         if (draw_type == MASK_DT_OUTLINE) {
230                                 const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
231                                 glLineWidth(3);
232                                 glColor4ubv(rgb_gray);
233                                 glBegin(GL_LINES);
234                                 glVertex2fv(vert);
235                                 glVertex2fv(handle);
236                                 glEnd();
237                                 glLineWidth(1);
238                         }
239
240                         glColor3ubv(rgb_spline);
241                         glBegin(GL_LINES);
242                         glVertex2fv(vert);
243                         glVertex2fv(handle);
244                         glEnd();
245                 }
246
247                 /* draw CV point */
248                 if (MASKPOINT_ISSEL_KNOT(point)) {
249                         if (point == masklay->act_point)
250                                 glColor3f(1.0f, 1.0f, 1.0f);
251                         else
252                                 glColor3f(1.0f, 1.0f, 0.0f);
253                 }
254                 else
255                         glColor3f(0.5f, 0.5f, 0.0f);
256
257                 glBegin(GL_POINTS);
258                 glVertex2fv(vert);
259                 glEnd();
260
261                 /* draw handle points */
262                 if (has_handle) {
263                         if (MASKPOINT_ISSEL_HANDLE(point)) {
264                                 if (point == masklay->act_point)
265                                         glColor3f(1.0f, 1.0f, 1.0f);
266                                 else
267                                         glColor3f(1.0f, 1.0f, 0.0f);
268                         }
269                         else {
270                                 glColor3f(0.5f, 0.5f, 0.0f);
271                         }
272
273                         glBegin(GL_POINTS);
274                         glVertex2fv(handle);
275                         glEnd();
276                 }
277         }
278
279         glPointSize(1.0f);
280 }
281
282 /* #define USE_XOR */
283
284 static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const short is_active)
285 {
286         if (!is_active) {
287                 r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
288                 r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
289                 r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
290                 r_rgb[3] = rgb[3];
291         }
292         else {
293                 *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
294         }
295 }
296
297 static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*orig_points)[2], int tot_point,
298                                  const bool is_feather, const bool is_smooth, const bool is_active,
299                                  const unsigned char rgb_spline[4], const char draw_type)
300 {
301         const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP;
302         const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
303 //      const unsigned char rgb_white[4] = {0xff, 0xff, 0xff, 0xff};
304         unsigned char rgb_tmp[4];
305         SpaceClip *sc = CTX_wm_space_clip(C);
306         float (*points)[2] = orig_points;
307
308         if (sc) {
309                 int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
310
311                 if (undistort) {
312                         int i;
313
314                         points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
315
316                         for (i = 0; i < tot_point; i++) {
317                                 mask_point_undistort_pos(sc, points[i], orig_points[i]);
318                         }
319                 }
320         }
321
322         glEnableClientState(GL_VERTEX_ARRAY);
323         glVertexPointer(2, GL_FLOAT, 0, points);
324
325         switch (draw_type) {
326
327                 case MASK_DT_OUTLINE:
328                         glLineWidth(3);
329
330                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
331                         glColor4ubv(rgb_tmp);
332
333                         glDrawArrays(draw_method, 0, tot_point);
334
335                         glLineWidth(1);
336                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
337                         glColor4ubv(rgb_tmp);
338                         glDrawArrays(draw_method, 0, tot_point);
339
340                         break;
341
342                 case MASK_DT_DASH:
343                 default:
344                         glEnable(GL_LINE_STIPPLE);
345
346 #ifdef USE_XOR
347                         glEnable(GL_COLOR_LOGIC_OP);
348                         glLogicOp(GL_OR);
349 #endif
350                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
351                         glColor4ubv(rgb_tmp);
352                         glLineStipple(3, 0xaaaa);
353                         glEnableClientState(GL_VERTEX_ARRAY);
354                         glVertexPointer(2, GL_FLOAT, 0, points);
355                         glDrawArrays(draw_method, 0, tot_point);
356
357 #ifdef USE_XOR
358                         glDisable(GL_COLOR_LOGIC_OP);
359 #endif
360                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
361                         glColor4ubv(rgb_tmp);
362                         glLineStipple(3, 0x5555);
363                         glDrawArrays(draw_method, 0, tot_point);
364
365                         glDisable(GL_LINE_STIPPLE);
366                         break;
367
368
369                 case MASK_DT_BLACK:
370                 case MASK_DT_WHITE:
371                         if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0;   }
372                         else                            { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
373                         /* alpha values seem too low but gl draws many points that compensate for it */
374                         if (is_feather) { rgb_tmp[3] = 64; }
375                         else            { rgb_tmp[3] = 128; }
376
377                         if (is_feather) {
378                                 rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
379                                 rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
380                                 rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
381                         }
382
383                         if (is_smooth == FALSE && is_feather) {
384                                 glEnable(GL_BLEND);
385                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
386                         }
387
388                         mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
389                         glColor4ubv(rgb_tmp);
390
391                         glEnableClientState(GL_VERTEX_ARRAY);
392                         glVertexPointer(2, GL_FLOAT, 0, points);
393                         glDrawArrays(draw_method, 0, tot_point);
394
395                         if (is_smooth == FALSE && is_feather) {
396                                 glDisable(GL_BLEND);
397                         }
398
399                         break;
400         }
401
402         glDisableClientState(GL_VERTEX_ARRAY);
403
404         if (points != orig_points)
405                 MEM_freeN(points);
406 }
407
408 static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
409                               const char draw_flag, const char draw_type,
410                               const bool is_active,
411                               int width, int height)
412 {
413         const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
414                                           BKE_mask_spline_resolution(spline, width, height));
415
416         unsigned char rgb_tmp[4];
417
418         const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
419         const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
420         const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
421
422         unsigned int tot_diff_point;
423         float (*diff_points)[2];
424
425         unsigned int tot_feather_point;
426         float (*feather_points)[2];
427
428         diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
429
430         if (!diff_points)
431                 return;
432
433         if (is_smooth) {
434                 glEnable(GL_LINE_SMOOTH);
435                 glEnable(GL_BLEND);
436                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
437         }
438
439         feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != FALSE));
440
441         /* draw feather */
442         mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
443         mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
444                              TRUE, is_smooth, is_active,
445                              rgb_tmp, draw_type);
446
447         if (!is_fill) {
448
449                 float *fp         = &diff_points[0][0];
450                 float *fp_feather = &feather_points[0][0];
451                 float tvec[2];
452                 int i;
453
454                 BLI_assert(tot_diff_point == tot_feather_point);
455
456                 for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
457                         sub_v2_v2v2(tvec, fp, fp_feather);
458                         add_v2_v2v2(fp_feather, fp, tvec);
459                 }
460
461                 /* same as above */
462                 mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
463                                      TRUE, is_smooth, is_active,
464                                      rgb_tmp, draw_type);
465         }
466
467         MEM_freeN(feather_points);
468
469         /* draw main curve */
470         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
471         mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
472                              FALSE, is_smooth, is_active,
473                              rgb_tmp, draw_type);
474         MEM_freeN(diff_points);
475
476         if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
477                 glDisable(GL_LINE_SMOOTH);
478                 glDisable(GL_BLEND);
479         }
480
481         (void)draw_type;
482 }
483
484 static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
485                           int width, int height)
486 {
487         MaskLayer *masklay;
488         int i;
489
490         for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
491                 MaskSpline *spline;
492                 const bool is_active = (i == mask->masklay_act);
493
494                 if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
495                         continue;
496                 }
497
498                 for (spline = masklay->splines.first; spline; spline = spline->next) {
499
500                         /* draw curve itself first... */
501                         draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
502
503 //                      draw_spline_parents(masklay, spline);
504
505                         if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
506                                 /* ...and then handles over the curve so they're nicely visible */
507                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type);
508                         }
509
510                         /* show undeform for testing */
511                         if (0) {
512                                 void *back = spline->points_deform;
513
514                                 spline->points_deform = NULL;
515                                 draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
516 //                              draw_spline_parents(masklay, spline);
517                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type);
518                                 spline->points_deform = back;
519                         }
520                 }
521         }
522 }
523
524 void ED_mask_draw(const bContext *C,
525                   const char draw_flag, const char draw_type)
526 {
527         ScrArea *sa = CTX_wm_area(C);
528
529         Mask *mask = CTX_data_edit_mask(C);
530         int width, height;
531
532         if (!mask)
533                 return;
534
535         ED_mask_get_size(sa, &width, &height);
536
537         draw_masklays(C, mask, draw_flag, draw_type, width, height);
538 }
539
540 typedef struct ThreadedMaskRasterizeState {
541         MaskRasterHandle *handle;
542         float *buffer;
543         int width, height;
544 } ThreadedMaskRasterizeState;
545
546 typedef struct ThreadedMaskRasterizeData {
547         int start_scanline;
548         int num_scanlines;
549 } ThreadedMaskRasterizeData;
550
551 static void mask_rasterize_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
552 {
553         ThreadedMaskRasterizeState *state = (ThreadedMaskRasterizeState *) BLI_task_pool_userdata(pool);
554         ThreadedMaskRasterizeData *data = (ThreadedMaskRasterizeData *) taskdata;
555         int scanline;
556
557         for (scanline = 0; scanline < data->num_scanlines; scanline++) {
558                 int x, y = data->start_scanline + scanline;
559                 for (x = 0; x < state->width; x++) {
560                         int index = y * state->width + x;
561                         float xy[2];
562
563                         xy[0] = (float) x / state->width;
564                         xy[1] = (float) y / state->height;
565
566                         state->buffer[index] = BKE_maskrasterize_handle_sample(state->handle, xy);
567                 }
568         }
569 }
570
571 static float *threaded_mask_rasterize(Mask *mask, const int width, const int height)
572 {
573         TaskScheduler *task_scheduler = BLI_task_scheduler_get();
574         TaskPool *task_pool;
575         MaskRasterHandle *handle;
576         ThreadedMaskRasterizeState state;
577         float *buffer;
578         int i, num_threads = BLI_task_scheduler_num_threads(task_scheduler), scanlines_per_thread;
579
580         buffer = MEM_mallocN(sizeof(float) * height * width, "rasterized mask buffer");
581
582         /* Initialize rasterization handle. */
583         handle = BKE_maskrasterize_handle_new();
584         BKE_maskrasterize_handle_init(handle, mask, width, height, TRUE, TRUE, TRUE);
585
586         state.handle = handle;
587         state.buffer = buffer;
588         state.width = width;
589         state.height = height;
590
591         task_pool = BLI_task_pool_create(task_scheduler, &state);
592
593         scanlines_per_thread = height / num_threads;
594         for (i = 0; i < num_threads; i++) {
595                 ThreadedMaskRasterizeData *data = MEM_mallocN(sizeof(ThreadedMaskRasterizeData),
596                                                                 "threaded mask rasterize data");
597
598                 data->start_scanline = i * scanlines_per_thread;
599
600                 if (i < num_threads - 1) {
601                         data->num_scanlines = scanlines_per_thread;
602                 }
603                 else {
604                         data->num_scanlines = height - data->start_scanline;
605                 }
606
607                 BLI_task_pool_push(task_pool, mask_rasterize_func, data, true, TASK_PRIORITY_LOW);
608         }
609
610         /* work and wait until tasks are done */
611         BLI_task_pool_work_and_wait(task_pool);
612
613         /* Free memory. */
614         BLI_task_pool_free(task_pool);
615         BKE_maskrasterize_handle_free(handle);
616
617         return buffer;
618 }
619
620 /* sets up the opengl context.
621  * width, height are to match the values from ED_mask_get_size() */
622 void ED_mask_draw_region(Mask *mask, ARegion *ar,
623                          const char draw_flag, const char draw_type, const char overlay_mode,
624                          const int width_i, const int height_i,  /* convert directly into aspect corrected vars */
625                          const float aspx, const float aspy,
626                          const bool do_scale_applied, const bool do_draw_cb,
627                          float stabmat[4][4], /* optional - only used by clip */
628                          const bContext *C    /* optional - only used when do_post_draw is set or called from clip editor */
629                          )
630 {
631         struct View2D *v2d = &ar->v2d;
632
633         /* aspect always scales vertically in movie and image spaces */
634         const float width = width_i, height = (float)height_i * (aspy / aspx);
635
636         int x, y;
637         /* int w, h; */
638         float zoomx, zoomy;
639
640         /* frame image */
641         float maxdim;
642         float xofs, yofs;
643
644         /* find window pixel coordinates of origin */
645         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
646
647
648         /* w = BLI_rctf_size_x(&v2d->tot); */
649         /* h = BLI_rctf_size_y(&v2d->tot);/*/
650
651
652         zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
653         zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur);
654
655         if (do_scale_applied) {
656                 zoomx /= width;
657                 zoomy /= height;
658         }
659
660         x += v2d->tot.xmin * zoomx;
661         y += v2d->tot.ymin * zoomy;
662
663         /* frame the image */
664         maxdim = max_ff(width, height);
665         if (width == height) {
666                 xofs = yofs = 0;
667         }
668         else if (width < height) {
669                 xofs = ((height - width) / -2.0f) * zoomx;
670                 yofs = 0.0f;
671         }
672         else { /* (width > height) */
673                 xofs = 0.0f;
674                 yofs = ((width - height) / -2.0f) * zoomy;
675         }
676
677         if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
678                 float *buffer = threaded_mask_rasterize(mask, width, height);
679                 int format;
680
681                 if (overlay_mode == MASK_OVERLAY_ALPHACHANNEL) {
682                         glColor3f(1.0f, 1.0f, 1.0f);
683                         format = GL_LUMINANCE;
684                 }
685                 else {
686                         /* More blending types could be supported in the future. */
687                         glEnable(GL_BLEND);
688                         glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
689                         format = GL_ALPHA;
690                 }
691
692                 glPushMatrix();
693                 glTranslatef(x, y, 0);
694                 glScalef(zoomx, zoomy, 0);
695                 if (stabmat) {
696                         glMultMatrixf(stabmat);
697                 }
698                 glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer);
699                 glPopMatrix();
700
701                 if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
702                         glDisable(GL_BLEND);
703                 }
704
705                 MEM_freeN(buffer);
706         }
707
708         /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
709         glPushMatrix();
710         glTranslatef(x + xofs, y + yofs, 0);
711         glScalef(maxdim * zoomx, maxdim * zoomy, 0);
712
713         if (stabmat) {
714                 glMultMatrixf(stabmat);
715         }
716
717         if (do_draw_cb) {
718                 ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
719         }
720
721         /* draw! */
722         draw_masklays(C, mask, draw_flag, draw_type, width, height);
723
724         if (do_draw_cb) {
725                 ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
726         }
727
728         glPopMatrix();
729 }
730
731 void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
732 {
733         const float framelen = ar->winx / (float)(efra - sfra + 1);
734
735         MaskLayer *masklay = BKE_mask_layer_active(mask);
736
737         glBegin(GL_LINES);
738         glColor4ub(255, 175, 0, 255);
739
740         if (masklay) {
741                 MaskLayerShape *masklay_shape;
742
743                 for (masklay_shape = masklay->splines_shapes.first;
744                      masklay_shape;
745                      masklay_shape = masklay_shape->next)
746                 {
747                         int frame = masklay_shape->frame;
748
749                         /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
750                         int height = (frame == cfra) ? 22 : 10;
751                         int x = (frame - sfra) * framelen;
752                         glVertex2i(x, 0);
753                         glVertex2i(x, height);
754                 }
755         }
756
757         glEnd();
758 }