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