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