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