Cleanup: remove redundant, invalid info from headers
[blender.git] / source / blender / windowmanager / intern / wm_gesture.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file blender/windowmanager/intern/wm_gesture.c
21  *  \ingroup wm
22  *
23  * Gestures (cursor motions) creating, evaluating and drawing, shared between operators.
24  */
25
26 #include "DNA_screen_types.h"
27 #include "DNA_vec_types.h"
28 #include "DNA_userdef_types.h"
29 #include "DNA_windowmanager_types.h"
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_bitmap_draw_2d.h"
34 #include "BLI_blenlib.h"
35 #include "BLI_math.h"
36 #include "BLI_utildefines.h"
37 #include "BLI_lasso_2d.h"
38
39 #include "BKE_context.h"
40
41
42 #include "WM_api.h"
43 #include "WM_types.h"
44
45 #include "wm.h"
46 #include "wm_subwindow.h"
47 #include "wm_draw.h"
48 #include "GPU_basic_shader.h"
49
50
51 #include "BIF_glutil.h"
52
53
54 /* context checked on having screen, window and area */
55 wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
56 {
57         wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
58         wmWindow *window = CTX_wm_window(C);
59         ARegion *ar = CTX_wm_region(C);
60         int sx, sy;
61
62         BLI_addtail(&window->gesture, gesture);
63
64         gesture->type = type;
65         gesture->event_type = event->type;
66         gesture->swinid = ar->swinid;    /* means only in area-region context! */
67         gesture->userdata_free = true;   /* Free if userdata is set. */
68         gesture->modal_state = GESTURE_MODAL_NOP;
69
70         wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
71
72         if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
73                   WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
74         {
75                 rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
76
77                 gesture->customdata = rect;
78                 rect->xmin = event->x - sx;
79                 rect->ymin = event->y - sy;
80                 if (type == WM_GESTURE_CIRCLE) {
81                         /* caller is responsible for initializing 'xmax' to radius. */
82                 }
83                 else {
84                         rect->xmax = event->x - sx;
85                         rect->ymax = event->y - sy;
86                 }
87         }
88         else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
89                 short *lasso;
90                 gesture->points_alloc = 1024;
91                 gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc, "lasso points");
92                 lasso[0] = event->x - sx;
93                 lasso[1] = event->y - sy;
94                 gesture->points = 1;
95         }
96
97         return gesture;
98 }
99
100 void WM_gesture_end(bContext *C, wmGesture *gesture)
101 {
102         wmWindow *win = CTX_wm_window(C);
103
104         if (win->tweak == gesture)
105                 win->tweak = NULL;
106         BLI_remlink(&win->gesture, gesture);
107         MEM_freeN(gesture->customdata);
108         if (gesture->userdata && gesture->userdata_free) {
109                 MEM_freeN(gesture->userdata);
110         }
111         MEM_freeN(gesture);
112 }
113
114 void WM_gestures_remove(bContext *C)
115 {
116         wmWindow *win = CTX_wm_window(C);
117
118         while (win->gesture.first)
119                 WM_gesture_end(C, win->gesture.first);
120 }
121
122
123 /* tweak and line gestures */
124 int wm_gesture_evaluate(wmGesture *gesture)
125 {
126         if (gesture->type == WM_GESTURE_TWEAK) {
127                 rcti *rect = gesture->customdata;
128                 int dx = BLI_rcti_size_x(rect);
129                 int dy = BLI_rcti_size_y(rect);
130                 if (abs(dx) + abs(dy) > U.tweak_threshold) {
131                         int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
132                         int val = EVT_GESTURE_W;
133
134                         if (theta == 0) val = EVT_GESTURE_E;
135                         else if (theta == 1) val = EVT_GESTURE_NE;
136                         else if (theta == 2) val = EVT_GESTURE_N;
137                         else if (theta == 3) val = EVT_GESTURE_NW;
138                         else if (theta == -1) val = EVT_GESTURE_SE;
139                         else if (theta == -2) val = EVT_GESTURE_S;
140                         else if (theta == -3) val = EVT_GESTURE_SW;
141
142 #if 0
143                         /* debug */
144                         if (val == 1) printf("tweak north\n");
145                         if (val == 2) printf("tweak north-east\n");
146                         if (val == 3) printf("tweak east\n");
147                         if (val == 4) printf("tweak south-east\n");
148                         if (val == 5) printf("tweak south\n");
149                         if (val == 6) printf("tweak south-west\n");
150                         if (val == 7) printf("tweak west\n");
151                         if (val == 8) printf("tweak north-west\n");
152 #endif
153                         return val;
154                 }
155         }
156         return 0;
157 }
158
159
160 /* ******************* gesture draw ******************* */
161
162 static void wm_gesture_draw_rect(wmGesture *gt)
163 {
164         rcti *rect = (rcti *)gt->customdata;
165
166         glEnable(GL_BLEND);
167         glColor4f(1.0, 1.0, 1.0, 0.05);
168         glBegin(GL_QUADS);
169         glVertex2s(rect->xmax, rect->ymin);
170         glVertex2s(rect->xmax, rect->ymax);
171         glVertex2s(rect->xmin, rect->ymax);
172         glVertex2s(rect->xmin, rect->ymin);
173         glEnd();
174         glDisable(GL_BLEND);
175
176         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
177         glColor3ub(96, 96, 96);
178         GPU_basic_shader_line_stipple(1, 0xCCCC);
179         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
180         glColor3ub(255, 255, 255);
181         GPU_basic_shader_line_stipple(1, 0x3333);
182         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
183         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
184 }
185
186 static void wm_gesture_draw_line(wmGesture *gt)
187 {
188         rcti *rect = (rcti *)gt->customdata;
189
190         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
191         glColor3ub(96, 96, 96);
192         GPU_basic_shader_line_stipple(1, 0xAAAA);
193         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
194         glColor3ub(255, 255, 255);
195         GPU_basic_shader_line_stipple(1, 0x5555);
196         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
197
198         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
199
200 }
201
202 static void wm_gesture_draw_circle(wmGesture *gt)
203 {
204         rcti *rect = (rcti *)gt->customdata;
205
206         glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
207
208         glEnable(GL_BLEND);
209         glColor4f(1.0, 1.0, 1.0, 0.05);
210         glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
211         glDisable(GL_BLEND);
212
213         // for USE_GLSL works bad because of no relation between lines
214         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
215         glColor3ub(96, 96, 96);
216         GPU_basic_shader_line_stipple(1, 0xAAAA);
217         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
218         glColor3ub(255, 255, 255);
219         GPU_basic_shader_line_stipple(1, 0x5555);
220         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
221
222         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
223         glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
224
225 }
226
227 struct LassoFillData {
228         unsigned char *px;
229         int width;
230 };
231
232 static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
233 {
234         struct LassoFillData *data = user_data;
235         unsigned char *col = &(data->px[(y * data->width) + x]);
236         memset(col, 0x10, x_end - x);
237 }
238
239 static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
240 {
241         const short *lasso = (short *)gt->customdata;
242         const int tot = gt->points;
243         int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
244         int i;
245         rcti rect;
246         rcti rect_win;
247
248         for (i = 0; i < tot; i++, lasso += 2) {
249                 moves[i][0] = lasso[0];
250                 moves[i][1] = lasso[1];
251         }
252
253         BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot);
254
255         wm_subwindow_rect_get(win, gt->swinid, &rect_win);
256         BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin);
257         BLI_rcti_isect(&rect_win, &rect, &rect);
258         BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin);
259
260         /* highly unlikely this will fail, but could crash if (tot == 0) */
261         if (BLI_rcti_is_empty(&rect) == false) {
262                 const int w = BLI_rcti_size_x(&rect);
263                 const int h = BLI_rcti_size_y(&rect);
264                 unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
265                 struct LassoFillData lasso_fill_data = {pixel_buf, w};
266
267                 BLI_bitmap_draw_2d_poly_v2i_n(
268                        rect.xmin, rect.ymin, rect.xmax, rect.ymax,
269                        (const int (*)[2])moves, tot,
270                        draw_filled_lasso_px_cb, &lasso_fill_data);
271
272                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
273
274                 glColor4f(1, 1, 1, 1);
275                 glPixelTransferf(GL_RED_BIAS, 1);
276                 glPixelTransferf(GL_GREEN_BIAS, 1);
277                 glPixelTransferf(GL_BLUE_BIAS, 1);
278
279                 GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
280
281                 glEnable(GL_BLEND);
282                 glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
283                 glDisable(GL_BLEND);
284
285                 GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
286
287                 glPixelTransferf(GL_RED_BIAS, 0);
288                 glPixelTransferf(GL_GREEN_BIAS, 0);
289                 glPixelTransferf(GL_BLUE_BIAS, 0);
290
291                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
292
293                 MEM_freeN(pixel_buf);
294         }
295
296         MEM_freeN(moves);
297 }
298
299
300 static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
301 {
302         const short *lasso = (short *)gt->customdata;
303         int i;
304
305         if (filled) {
306                 draw_filled_lasso(win, gt);
307         }
308
309         // for USE_GLSL can't check this yet
310         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
311         glColor3ub(96, 96, 96);
312         GPU_basic_shader_line_stipple(1, 0xAAAA);
313         glBegin(GL_LINE_STRIP);
314         for (i = 0; i < gt->points; i++, lasso += 2)
315                 glVertex2sv(lasso);
316         if (gt->type == WM_GESTURE_LASSO)
317                 glVertex2sv((short *)gt->customdata);
318         glEnd();
319
320         glColor3ub(255, 255, 255);
321         GPU_basic_shader_line_stipple(1, 0x5555);
322         glBegin(GL_LINE_STRIP);
323         lasso = (short *)gt->customdata;
324         for (i = 0; i < gt->points; i++, lasso += 2)
325                 glVertex2sv(lasso);
326         if (gt->type == WM_GESTURE_LASSO)
327                 glVertex2sv((short *)gt->customdata);
328         glEnd();
329
330         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
331
332 }
333
334 static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
335 {
336         rcti *rect = (rcti *)gt->customdata;
337         const int winsize_x = WM_window_pixels_x(win);
338         const int winsize_y = WM_window_pixels_y(win);
339
340         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
341         glColor3ub(96, 96, 96);
342         GPU_basic_shader_line_stipple(1, 0xCCCC);
343         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
344         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
345
346         glColor3ub(255, 255, 255);
347         GPU_basic_shader_line_stipple(1, 0x3333);
348         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
349         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
350         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
351 }
352
353 /* called in wm_draw.c */
354 void wm_gesture_draw(wmWindow *win)
355 {
356         wmGesture *gt = (wmGesture *)win->gesture.first;
357
358         GPU_basic_shader_line_width(1);
359         for (; gt; gt = gt->next) {
360                 /* all in subwindow space */
361                 wmSubWindowSet(win, gt->swinid);
362
363                 if (gt->type == WM_GESTURE_RECT)
364                         wm_gesture_draw_rect(gt);
365 //              else if (gt->type == WM_GESTURE_TWEAK)
366 //                      wm_gesture_draw_line(gt);
367                 else if (gt->type == WM_GESTURE_CIRCLE)
368                         wm_gesture_draw_circle(gt);
369                 else if (gt->type == WM_GESTURE_CROSS_RECT) {
370                         if (gt->is_active) {
371                                 wm_gesture_draw_rect(gt);
372                         }
373                         else {
374                                 wm_gesture_draw_cross(win, gt);
375                         }
376                 }
377                 else if (gt->type == WM_GESTURE_LINES)
378                         wm_gesture_draw_lasso(win, gt, false);
379                 else if (gt->type == WM_GESTURE_LASSO)
380                         wm_gesture_draw_lasso(win, gt, true);
381                 else if (gt->type == WM_GESTURE_STRAIGHTLINE)
382                         wm_gesture_draw_line(gt);
383         }
384 }
385
386 void wm_gesture_tag_redraw(bContext *C)
387 {
388         wmWindow *win = CTX_wm_window(C);
389         bScreen *screen = CTX_wm_screen(C);
390         ARegion *ar = CTX_wm_region(C);
391
392         if (screen)
393                 screen->do_draw_gesture = true;
394
395         wm_tag_redraw_overlay(win, ar);
396 }