a26ae5ea3c0c515979059573bf03895d1d80e2e5
[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
36 #include "BKE_context.h"
37 #include "BKE_mask.h"
38
39 #include "DNA_mask_types.h"
40 #include "DNA_object_types.h"   /* SELECT */
41
42 #include "ED_mask.h"  /* own include */
43 #include "BIF_gl.h"
44
45 #include "UI_resources.h"
46
47 #include "mask_intern.h"  /* own include */
48
49 static void mask_spline_color_get(MaskLayer *masklay, MaskSpline *spline, const int is_sel,
50                                   unsigned char r_rgb[4])
51 {
52         if (is_sel) {
53                 if (masklay->act_spline == spline) {
54                         r_rgb[0] = r_rgb[1] = r_rgb[2] = 255;
55                 }
56                 else {
57                         r_rgb[0] = 255;
58                         r_rgb[1] = r_rgb[2] = 0;
59                 }
60         }
61         else {
62                 r_rgb[0] = 128;
63                 r_rgb[1] = r_rgb[2] = 0;
64         }
65
66         r_rgb[3] = 255;
67 }
68
69 static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay), MaskSpline *UNUSED(spline), const int is_sel,
70                                           unsigned char r_rgb[4])
71 {
72         if (is_sel) {
73                 r_rgb[1] = 255;
74                 r_rgb[0] = r_rgb[2] = 0;
75         }
76         else {
77                 r_rgb[1] = 128;
78                 r_rgb[0] = r_rgb[2] = 0;
79         }
80
81         r_rgb[3] = 255;
82 }
83
84 #if 0
85 static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
86 {
87         int i;
88         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
89
90         if (!spline->tot_point)
91                 return;
92
93         glColor3ub(0, 0, 0);
94         glEnable(GL_LINE_STIPPLE);
95         glLineStipple(1, 0xAAAA);
96
97         glBegin(GL_LINES);
98
99         for (i = 0; i < spline->tot_point; i++) {
100                 MaskSplinePoint *point = &points_array[i];
101                 BezTriple *bezt = &point->bezt;
102
103                 if (point->parent.flag & MASK_PARENT_ACTIVE) {
104                         glVertex2f(bezt->vec[1][0],
105                                    bezt->vec[1][1]);
106
107                         glVertex2f(bezt->vec[1][0] - point->parent.offset[0],
108                                    bezt->vec[1][1] - point->parent.offset[1]);
109                 }
110         }
111
112         glEnd();
113
114         glDisable(GL_LINE_STIPPLE);
115 }
116 #endif
117
118 /* return non-zero if spline is selected */
119 static void draw_spline_points(MaskLayer *masklay, MaskSpline *spline)
120 {
121         const int is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
122         unsigned char rgb_spline[4];
123         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
124
125         int i, hsize, tot_feather_point;
126         float (*feather_points)[2], (*fp)[2];
127
128         if (!spline->tot_point)
129                 return;
130
131         hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
132
133         glPointSize(hsize);
134
135         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
136
137         /* feather points */
138         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
139         for (i = 0; i < spline->tot_point; i++) {
140
141                 /* watch it! this is intentionally not the deform array, only check for sel */
142                 MaskSplinePoint *point = &spline->points[i];
143
144                 int j;
145
146                 for (j = 0; j < point->tot_uw + 1; j++) {
147                         int sel = FALSE;
148
149                         if (j == 0) {
150                                 sel = MASKPOINT_ISSEL_ANY(point);
151                         }
152                         else {
153                                 sel = point->uw[j - 1].flag & SELECT;
154                         }
155
156                         if (sel) {
157                                 if (point == masklay->act_point)
158                                         glColor3f(1.0f, 1.0f, 1.0f);
159                                 else
160                                         glColor3f(1.0f, 1.0f, 0.0f);
161                         }
162                         else {
163                                 glColor3f(0.5f, 0.5f, 0.0f);
164                         }
165
166                         glBegin(GL_POINTS);
167                         glVertex2fv(*fp);
168                         glEnd();
169
170                         fp++;
171                 }
172         }
173         MEM_freeN(feather_points);
174
175         /* control points */
176         for (i = 0; i < spline->tot_point; i++) {
177
178                 /* watch it! this is intentionally not the deform array, only check for sel */
179                 MaskSplinePoint *point = &spline->points[i];
180                 MaskSplinePoint *point_deform = &points_array[i];
181                 BezTriple *bezt = &point_deform->bezt;
182
183                 float handle[2];
184                 float *vert = bezt->vec[1];
185                 int has_handle = BKE_mask_point_has_handle(point);
186
187                 BKE_mask_point_handle(point_deform, handle);
188
189                 /* draw handle segment */
190                 if (has_handle) {
191                         glColor3ubv(rgb_spline);
192
193                         glBegin(GL_LINES);
194                         glVertex3fv(vert);
195                         glVertex3fv(handle);
196                         glEnd();
197                 }
198
199                 /* draw CV point */
200                 if (MASKPOINT_ISSEL_KNOT(point)) {
201                         if (point == masklay->act_point)
202                                 glColor3f(1.0f, 1.0f, 1.0f);
203                         else
204                                 glColor3f(1.0f, 1.0f, 0.0f);
205                 }
206                 else
207                         glColor3f(0.5f, 0.5f, 0.0f);
208
209                 glBegin(GL_POINTS);
210                 glVertex3fv(vert);
211                 glEnd();
212
213                 /* draw handle points */
214                 if (has_handle) {
215                         if (MASKPOINT_ISSEL_HANDLE(point)) {
216                                 if (point == masklay->act_point)
217                                         glColor3f(1.0f, 1.0f, 1.0f);
218                                 else
219                                         glColor3f(1.0f, 1.0f, 0.0f);
220                         }
221                         else {
222                                 glColor3f(0.5f, 0.5f, 0.0f);
223                         }
224
225                         glBegin(GL_POINTS);
226                         glVertex3fv(handle);
227                         glEnd();
228                 }
229         }
230
231         glPointSize(1.0f);
232 }
233
234 /* #define USE_XOR */
235
236 static void mask_draw_curve_type(MaskSpline *spline, float (*points)[2], int tot_point,
237                                  const short is_feather, const short is_smooth,
238                                  const unsigned char rgb_spline[4], const char draw_type)
239 {
240         const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP;
241         unsigned char rgb_tmp[4];
242
243         glEnableClientState(GL_VERTEX_ARRAY);
244         glVertexPointer(2, GL_FLOAT, 0, points);
245
246         switch (draw_type) {
247
248                 case MASK_DT_OUTLINE:
249                         glLineWidth(3);
250                         cpack(0x0);
251
252                         glDrawArrays(draw_method, 0, tot_point);
253
254                         glLineWidth(1);
255                         glColor4ubv(rgb_spline);
256                         glDrawArrays(draw_method, 0, tot_point);
257
258                         break;
259
260                 case MASK_DT_DASH:
261                 default:
262                         glEnable(GL_LINE_STIPPLE);
263
264 #ifdef USE_XOR
265                         glEnable(GL_COLOR_LOGIC_OP);
266                         glLogicOp(GL_OR);
267 #endif
268                         glColor4ubv(rgb_spline);
269                         glLineStipple(3, 0xaaaa);
270                         glEnableClientState(GL_VERTEX_ARRAY);
271                         glVertexPointer(2, GL_FLOAT, 0, points);
272                         glDrawArrays(draw_method, 0, tot_point);
273
274 #ifdef USE_XOR
275                         glDisable(GL_COLOR_LOGIC_OP);
276 #endif
277                         glColor4ub(0, 0, 0, 255);
278                         glLineStipple(3, 0x5555);
279                         glDrawArrays(draw_method, 0, tot_point);
280
281                         glDisable(GL_LINE_STIPPLE);
282                         break;
283
284
285                 case MASK_DT_BLACK:
286                 case MASK_DT_WHITE:
287                         if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0;   }
288                         else                            { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
289                         /* alpha values seem too low but gl draws many points that compensate for it */
290                         if (is_feather) { rgb_tmp[3] = 64; }
291                         else            { rgb_tmp[3] = 128; }
292
293                         if (is_feather) {
294                                 rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
295                                 rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
296                                 rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
297                         }
298
299                         if (is_smooth == FALSE && is_feather) {
300                                 glEnable(GL_BLEND);
301                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302                         }
303
304                         glColor4ubv(rgb_tmp);
305                         glEnableClientState(GL_VERTEX_ARRAY);
306                         glVertexPointer(2, GL_FLOAT, 0, points);
307                         glDrawArrays(draw_method, 0, tot_point);
308
309                         glDrawArrays(draw_method, 0, tot_point);
310
311                         if (is_smooth == FALSE && is_feather) {
312                                 glDisable(GL_BLEND);
313                         }
314
315                         break;
316         }
317
318         glDisableClientState(GL_VERTEX_ARRAY);
319
320 }
321
322 static void draw_spline_curve(MaskLayer *masklay, MaskSpline *spline,
323                               const char draw_flag, const char draw_type,
324                               int width, int height)
325 {
326         unsigned char rgb_tmp[4];
327
328         const short is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
329         const short is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH);
330
331         int tot_diff_point;
332         float (*diff_points)[2];
333
334         int tot_feather_point;
335         float (*feather_points)[2];
336
337         diff_points = BKE_mask_spline_differentiate_with_resolution(spline, width, height, &tot_diff_point);
338
339         if (!diff_points)
340                 return;
341
342         if (is_smooth) {
343                 glEnable(GL_LINE_SMOOTH);
344                 glEnable(GL_BLEND);
345                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
346         }
347
348         feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, width, height, &tot_feather_point);
349
350         /* draw feather */
351         mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
352         mask_draw_curve_type(spline, feather_points, tot_feather_point,
353                              TRUE, is_smooth,
354                              rgb_tmp, draw_type);
355         MEM_freeN(feather_points);
356
357         /* draw main curve */
358         mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
359         mask_draw_curve_type(spline, diff_points, tot_diff_point,
360                              FALSE, is_smooth,
361                              rgb_tmp, draw_type);
362         MEM_freeN(diff_points);
363
364         if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
365                 glDisable(GL_LINE_SMOOTH);
366                 glDisable(GL_BLEND);
367         }
368
369         (void)draw_type;
370 }
371
372 static void draw_masklays(Mask *mask, const char draw_flag, const char draw_type,
373                           int width, int height)
374 {
375         MaskLayer *masklay;
376
377         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
378                 MaskSpline *spline;
379
380                 if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
381                         continue;
382                 }
383
384                 for (spline = masklay->splines.first; spline; spline = spline->next) {
385
386                         /* draw curve itself first... */
387                         draw_spline_curve(masklay, spline, draw_flag, draw_type, width, height);
388
389 //                      draw_spline_parents(masklay, spline);
390
391                         if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
392                                 /* ...and then handles over the curve so they're nicely visible */
393                                 draw_spline_points(masklay, spline);
394                         }
395
396                         /* show undeform for testing */
397                         if (0) {
398                                 void *back = spline->points_deform;
399
400                                 spline->points_deform = NULL;
401                                 draw_spline_curve(masklay, spline, draw_flag, draw_type, width, height);
402 //                              draw_spline_parents(masklay, spline);
403                                 draw_spline_points(masklay, spline);
404                                 spline->points_deform = back;
405                         }
406                 }
407         }
408 }
409
410 void ED_mask_draw(const bContext *C,
411                   const char draw_flag, const char draw_type)
412 {
413         Mask *mask = CTX_data_edit_mask(C);
414         int width, height;
415
416         if (!mask)
417                 return;
418
419         /* TODO: for now, in the future better to make sure all utility functions
420          *       are using const specifier for non-changing pointers
421          */
422         ED_mask_size((bContext *)C, &width, &height);
423
424         draw_masklays(mask, draw_flag, draw_type, width, height);
425 }