rename api functions...
[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
39 #include "BKE_context.h"
40 #include "BKE_mask.h"
41
42 #include "DNA_mask_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_object_types.h"   /* SELECT */
45 #include "DNA_space_types.h"
46
47 #include "ED_clip.h"
48 #include "ED_mask.h"  /* own include */
49 #include "ED_space_api.h"
50 #include "BIF_gl.h"
51
52 #include "UI_resources.h"
53 #include "UI_view2d.h"
54
55 #include "mask_intern.h"  /* own include */
56
57 static void mask_spline_color_get(MaskLayer *masklay, MaskSpline *spline, const int is_sel,
58                                   unsigned char r_rgb[4])
59 {
60         if (is_sel) {
61                 if (masklay->act_spline == spline) {
62                         r_rgb[0] = r_rgb[1] = r_rgb[2] = 255;
63                 }
64                 else {
65                         r_rgb[0] = 255;
66                         r_rgb[1] = r_rgb[2] = 0;
67                 }
68         }
69         else {
70                 r_rgb[0] = 128;
71                 r_rgb[1] = r_rgb[2] = 0;
72         }
73
74         r_rgb[3] = 255;
75 }
76
77 static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay), MaskSpline *UNUSED(spline), const int is_sel,
78                                           unsigned char r_rgb[4])
79 {
80         if (is_sel) {
81                 r_rgb[1] = 255;
82                 r_rgb[0] = r_rgb[2] = 0;
83         }
84         else {
85                 r_rgb[1] = 128;
86                 r_rgb[0] = r_rgb[2] = 0;
87         }
88
89         r_rgb[3] = 255;
90 }
91
92 #if 0
93 static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
94 {
95         int i;
96         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
97
98         if (!spline->tot_point)
99                 return;
100
101         glColor3ub(0, 0, 0);
102         glEnable(GL_LINE_STIPPLE);
103         glLineStipple(1, 0xAAAA);
104
105         glBegin(GL_LINES);
106
107         for (i = 0; i < spline->tot_point; i++) {
108                 MaskSplinePoint *point = &points_array[i];
109                 BezTriple *bezt = &point->bezt;
110
111                 if (point->parent.id) {
112                         glVertex2f(bezt->vec[1][0],
113                                    bezt->vec[1][1]);
114
115                         glVertex2f(bezt->vec[1][0] - point->parent.offset[0],
116                                    bezt->vec[1][1] - point->parent.offset[1]);
117                 }
118         }
119
120         glEnd();
121
122         glDisable(GL_LINE_STIPPLE);
123 }
124 #endif
125
126 static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], float co[2])
127 {
128         BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
129         ED_clip_point_undistorted_pos(sc, r_co, r_co);
130         BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
131 }
132
133 /* return non-zero if spline is selected */
134 static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
135                                const char UNUSED(draw_flag), const char draw_type)
136 {
137         const int is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
138         unsigned char rgb_spline[4];
139         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
140         SpaceClip *sc = CTX_wm_space_clip(C);
141         int undistort = FALSE;
142
143         int i, hsize, tot_feather_point;
144         float (*feather_points)[2], (*fp)[2];
145
146         if (!spline->tot_point)
147                 return;
148
149         if (sc)
150                 undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
151
152         /* TODO, add this to sequence editor */
153         hsize = 4; /* UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); */
154
155         glPointSize(hsize);
156
157         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
158
159         /* feather points */
160         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
161         for (i = 0; i < spline->tot_point; i++) {
162
163                 /* watch it! this is intentionally not the deform array, only check for sel */
164                 MaskSplinePoint *point = &spline->points[i];
165
166                 int j;
167
168                 for (j = 0; j < point->tot_uw + 1; j++) {
169                         float feather_point[2];
170                         int sel = FALSE;
171
172                         copy_v2_v2(feather_point, *fp);
173
174                         if (undistort)
175                                 mask_point_undistort_pos(sc, feather_point, feather_point);
176
177                         if (j == 0) {
178                                 sel = MASKPOINT_ISSEL_ANY(point);
179                         }
180                         else {
181                                 sel = point->uw[j - 1].flag & SELECT;
182                         }
183
184                         if (sel) {
185                                 if (point == masklay->act_point)
186                                         glColor3f(1.0f, 1.0f, 1.0f);
187                                 else
188                                         glColor3f(1.0f, 1.0f, 0.0f);
189                         }
190                         else {
191                                 glColor3f(0.5f, 0.5f, 0.0f);
192                         }
193
194                         glBegin(GL_POINTS);
195                         glVertex2fv(feather_point);
196                         glEnd();
197
198                         fp++;
199                 }
200         }
201         MEM_freeN(feather_points);
202
203         /* control points */
204         for (i = 0; i < spline->tot_point; i++) {
205
206                 /* watch it! this is intentionally not the deform array, only check for sel */
207                 MaskSplinePoint *point = &spline->points[i];
208                 MaskSplinePoint *point_deform = &points_array[i];
209                 BezTriple *bezt = &point_deform->bezt;
210
211                 float handle[2];
212                 float vert[2];
213                 int has_handle = BKE_mask_point_has_handle(point);
214
215                 copy_v2_v2(vert, bezt->vec[1]);
216                 BKE_mask_point_handle(point_deform, handle);
217
218                 if (undistort) {
219                         mask_point_undistort_pos(sc, vert, vert);
220                         mask_point_undistort_pos(sc, handle, handle);
221                 }
222
223                 /* draw handle segment */
224                 if (has_handle) {
225
226                         /* this could be split into its own loop */
227                         if (draw_type == MASK_DT_OUTLINE) {
228                                 const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
229                                 glLineWidth(3);
230                                 glColor4ubv(rgb_gray);
231                                 glBegin(GL_LINES);
232                                 glVertex2fv(vert);
233                                 glVertex2fv(handle);
234                                 glEnd();
235                                 glLineWidth(1);
236                         }
237
238                         glColor3ubv(rgb_spline);
239                         glBegin(GL_LINES);
240                         glVertex2fv(vert);
241                         glVertex2fv(handle);
242                         glEnd();
243                 }
244
245                 /* draw CV point */
246                 if (MASKPOINT_ISSEL_KNOT(point)) {
247                         if (point == masklay->act_point)
248                                 glColor3f(1.0f, 1.0f, 1.0f);
249                         else
250                                 glColor3f(1.0f, 1.0f, 0.0f);
251                 }
252                 else
253                         glColor3f(0.5f, 0.5f, 0.0f);
254
255                 glBegin(GL_POINTS);
256                 glVertex2fv(vert);
257                 glEnd();
258
259                 /* draw handle points */
260                 if (has_handle) {
261                         if (MASKPOINT_ISSEL_HANDLE(point)) {
262                                 if (point == masklay->act_point)
263                                         glColor3f(1.0f, 1.0f, 1.0f);
264                                 else
265                                         glColor3f(1.0f, 1.0f, 0.0f);
266                         }
267                         else {
268                                 glColor3f(0.5f, 0.5f, 0.0f);
269                         }
270
271                         glBegin(GL_POINTS);
272                         glVertex2fv(handle);
273                         glEnd();
274                 }
275         }
276
277         glPointSize(1.0f);
278 }
279
280 /* #define USE_XOR */
281
282 static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const short is_active)
283 {
284         if (!is_active) {
285                 r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
286                 r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
287                 r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
288                 r_rgb[3] = rgb[3];
289         }
290         else {
291                 *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
292         }
293 }
294
295 static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*orig_points)[2], int tot_point,
296                                  const short is_feather, const short is_smooth, const short is_active,
297                                  const unsigned char rgb_spline[4], const char draw_type)
298 {
299         const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP;
300         const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
301 //      const unsigned char rgb_white[4] = {0xff, 0xff, 0xff, 0xff};
302         unsigned char rgb_tmp[4];
303         SpaceClip *sc = CTX_wm_space_clip(C);
304         float (*points)[2] = orig_points;
305
306         if (sc) {
307                 int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
308
309                 if (undistort) {
310                         int i;
311
312                         points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
313
314                         for (i = 0; i < tot_point; i++) {
315                                 mask_point_undistort_pos(sc, points[i], orig_points[i]);
316                         }
317                 }
318         }
319
320         glEnableClientState(GL_VERTEX_ARRAY);
321         glVertexPointer(2, GL_FLOAT, 0, points);
322
323         switch (draw_type) {
324
325                 case MASK_DT_OUTLINE:
326                         glLineWidth(3);
327
328                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
329                         glColor4ubv(rgb_tmp);
330
331                         glDrawArrays(draw_method, 0, tot_point);
332
333                         glLineWidth(1);
334                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
335                         glColor4ubv(rgb_tmp);
336                         glDrawArrays(draw_method, 0, tot_point);
337
338                         break;
339
340                 case MASK_DT_DASH:
341                 default:
342                         glEnable(GL_LINE_STIPPLE);
343
344 #ifdef USE_XOR
345                         glEnable(GL_COLOR_LOGIC_OP);
346                         glLogicOp(GL_OR);
347 #endif
348                         mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
349                         glColor4ubv(rgb_tmp);
350                         glLineStipple(3, 0xaaaa);
351                         glEnableClientState(GL_VERTEX_ARRAY);
352                         glVertexPointer(2, GL_FLOAT, 0, points);
353                         glDrawArrays(draw_method, 0, tot_point);
354
355 #ifdef USE_XOR
356                         glDisable(GL_COLOR_LOGIC_OP);
357 #endif
358                         mask_color_active_tint(rgb_tmp, rgb_black, is_active);
359                         glColor4ubv(rgb_tmp);
360                         glLineStipple(3, 0x5555);
361                         glDrawArrays(draw_method, 0, tot_point);
362
363                         glDisable(GL_LINE_STIPPLE);
364                         break;
365
366
367                 case MASK_DT_BLACK:
368                 case MASK_DT_WHITE:
369                         if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0;   }
370                         else                            { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
371                         /* alpha values seem too low but gl draws many points that compensate for it */
372                         if (is_feather) { rgb_tmp[3] = 64; }
373                         else            { rgb_tmp[3] = 128; }
374
375                         if (is_feather) {
376                                 rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
377                                 rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
378                                 rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
379                         }
380
381                         if (is_smooth == FALSE && is_feather) {
382                                 glEnable(GL_BLEND);
383                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
384                         }
385
386                         mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
387                         glColor4ubv(rgb_tmp);
388
389                         glEnableClientState(GL_VERTEX_ARRAY);
390                         glVertexPointer(2, GL_FLOAT, 0, points);
391                         glDrawArrays(draw_method, 0, tot_point);
392
393                         if (is_smooth == FALSE && is_feather) {
394                                 glDisable(GL_BLEND);
395                         }
396
397                         break;
398         }
399
400         glDisableClientState(GL_VERTEX_ARRAY);
401
402         if (points != orig_points)
403                 MEM_freeN(points);
404 }
405
406 static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
407                               const char draw_flag, const char draw_type,
408                               const short is_active,
409                               int width, int height)
410 {
411         const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
412                                         BKE_mask_spline_resolution(spline, width, height));
413
414         unsigned char rgb_tmp[4];
415
416         const short is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
417         const short is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH);
418         const short is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
419
420         int tot_diff_point;
421         float (*diff_points)[2];
422
423         int tot_feather_point;
424         float (*feather_points)[2];
425
426         diff_points = BKE_mask_spline_differentiate_with_resolution_ex(spline, &tot_diff_point, resol);
427
428         if (!diff_points)
429                 return;
430
431         if (is_smooth) {
432                 glEnable(GL_LINE_SMOOTH);
433                 glEnable(GL_BLEND);
434                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
435         }
436
437         feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution_ex(spline, &tot_feather_point, resol, (is_fill != FALSE));
438
439         /* draw feather */
440         mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
441         mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
442                              TRUE, is_smooth, is_active,
443                              rgb_tmp, draw_type);
444
445         if (!is_fill) {
446
447                 float *fp         = &diff_points[0][0];
448                 float *fp_feather = &feather_points[0][0];
449                 float tvec[2];
450                 int i;
451
452                 BLI_assert(tot_diff_point == tot_feather_point);
453
454                 for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
455                         sub_v2_v2v2(tvec, fp, fp_feather);
456                         add_v2_v2v2(fp_feather, fp, tvec);
457                 }
458
459                 /* same as above */
460                 mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
461                                      TRUE, is_smooth, is_active,
462                                      rgb_tmp, draw_type);
463         }
464
465         MEM_freeN(feather_points);
466
467         /* draw main curve */
468         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
469         mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
470                              FALSE, is_smooth, is_active,
471                              rgb_tmp, draw_type);
472         MEM_freeN(diff_points);
473
474         if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
475                 glDisable(GL_LINE_SMOOTH);
476                 glDisable(GL_BLEND);
477         }
478
479         (void)draw_type;
480 }
481
482 static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag,const char draw_type,
483                           int width, int height)
484 {
485         MaskLayer *masklay;
486         int i;
487
488         for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
489                 MaskSpline *spline;
490                 const short is_active = (i == mask->masklay_act);
491
492                 if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
493                         continue;
494                 }
495
496                 for (spline = masklay->splines.first; spline; spline = spline->next) {
497
498                         /* draw curve itself first... */
499                         draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
500
501 //                      draw_spline_parents(masklay, spline);
502
503                         if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
504                                 /* ...and then handles over the curve so they're nicely visible */
505                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type);
506                         }
507
508                         /* show undeform for testing */
509                         if (0) {
510                                 void *back = spline->points_deform;
511
512                                 spline->points_deform = NULL;
513                                 draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
514 //                              draw_spline_parents(masklay, spline);
515                                 draw_spline_points(C, masklay, spline, draw_flag, draw_type);
516                                 spline->points_deform = back;
517                         }
518                 }
519         }
520 }
521
522 void ED_mask_draw(const bContext *C,
523                   const char draw_flag, const char draw_type)
524 {
525         ScrArea *sa = CTX_wm_area(C);
526
527         Mask *mask = CTX_data_edit_mask(C);
528         int width, height;
529
530         if (!mask)
531                 return;
532
533         ED_mask_get_size(sa, &width, &height);
534
535         draw_masklays(C, mask, draw_flag, draw_type, width, height);
536 }
537
538 /* sets up the opengl context.
539  * width, height are to match the values from ED_mask_get_size() */
540 void ED_mask_draw_region(Mask *mask, ARegion *ar,
541                          const char draw_flag, const char draw_type,
542                          const int width_i, const int height_i,  /* convert directly into aspect corrected vars */
543                          const float aspx, const float aspy,
544                          const short do_scale_applied, const short do_post_draw,
545                          float stabmat[4][4], /* optional - only used by clip */
546                          const bContext *C    /* optional - only used when do_post_draw is set or called from clip editor */
547                          )
548 {
549         struct View2D *v2d = &ar->v2d;
550
551         /* aspect always scales vertically in movie and image spaces */
552         const float width = width_i, height = (float)height_i * (aspy / aspx);
553
554         int x, y;
555         /* int w, h; */
556         float zoomx, zoomy;
557
558         /* frame image */
559         float maxdim;
560         float xofs, yofs;
561
562         /* find window pixel coordinates of origin */
563         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
564
565
566         /* w = BLI_rctf_size_x(&v2d->tot); */
567         /* h = BLI_rctf_size_y(&v2d->tot);/*/
568
569
570         zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
571         zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur);
572
573         if (do_scale_applied) {
574                 zoomx /= width;
575                 zoomy /= height;
576         }
577
578         x += v2d->tot.xmin * zoomx;
579         y += v2d->tot.ymin * zoomy;
580
581         /* frame the image */
582         maxdim = max_ff(width, height);
583         if (width == height) {
584                 xofs = yofs = 0;
585         }
586         else if (width < height) {
587                 xofs = ((height - width) / -2.0f) * zoomx;
588                 yofs = 0.0f;
589         }
590         else { /* (width > height) */
591                 xofs = 0.0f;
592                 yofs = ((width - height) / -2.0f) * zoomy;
593         }
594
595         /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
596         glPushMatrix();
597         glTranslatef(x + xofs, y + yofs, 0);
598         glScalef(maxdim * zoomx, maxdim * zoomy, 0);
599
600         if (stabmat) {
601                 glMultMatrixf(stabmat);
602         }
603
604         /* draw! */
605         draw_masklays(C, mask, draw_flag, draw_type, width, height);
606
607         if (do_post_draw) {
608                 ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
609         }
610
611         glPopMatrix();
612 }
613
614 void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
615 {
616         const float framelen = ar->winx / (float)(efra - sfra + 1);
617
618         MaskLayer *masklay = BKE_mask_layer_active(mask);
619
620         glBegin(GL_LINES);
621         glColor4ub(255, 175, 0, 255);
622
623         if (masklay) {
624                 MaskLayerShape *masklay_shape;
625
626                 for (masklay_shape = masklay->splines_shapes.first;
627                      masklay_shape;
628                      masklay_shape = masklay_shape->next)
629                 {
630                         int frame = masklay_shape->frame;
631
632                         /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
633                         int height = (frame == cfra) ? 22 : 10;
634                         int x = (frame - sfra) * framelen;
635                         glVertex2i(x, 0);
636                         glVertex2i(x, height);
637                 }
638         }
639
640         glEnd();
641 }