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) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edtransform
22  */
23 
24 #include "BLI_math.h"
25 
26 #include "GPU_immediate.h"
27 #include "GPU_matrix.h"
28 #include "GPU_state.h"
29 
30 #include "BKE_context.h"
31 
32 #include "DNA_screen_types.h"
33 #include "DNA_userdef_types.h"
34 
35 #include "UI_interface.h"
36 #include "UI_resources.h"
37 
38 #include "transform.h"
39 #include "transform_draw_cursors.h" /* Own include. */
40 
41 enum eArrowDirection {
42   UP,
43   DOWN,
44   LEFT,
45   RIGHT,
46 };
47 
48 struct ArrowDims {
49   int offset;
50   int length;
51   int size;
52 };
53 
54 #define POS_INDEX 0
55 /* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
56  * private to this file  - merwin
57  */
58 
drawArrow(enum eArrowDirection dir,const struct ArrowDims * arrow_dims)59 static void drawArrow(enum eArrowDirection dir, const struct ArrowDims *arrow_dims)
60 {
61   int offset = arrow_dims->offset;
62   int length = arrow_dims->length;
63   int size = arrow_dims->size;
64 
65   immBegin(GPU_PRIM_LINES, 6);
66 
67   switch (dir) {
68     case LEFT:
69       offset = -offset;
70       length = -length;
71       size = -size;
72       ATTR_FALLTHROUGH;
73     case RIGHT:
74       immVertex2f(POS_INDEX, offset, 0);
75       immVertex2f(POS_INDEX, offset + length, 0);
76       immVertex2f(POS_INDEX, offset + length, 0);
77       immVertex2f(POS_INDEX, offset + length - size, -size);
78       immVertex2f(POS_INDEX, offset + length, 0);
79       immVertex2f(POS_INDEX, offset + length - size, size);
80       break;
81 
82     case DOWN:
83       offset = -offset;
84       length = -length;
85       size = -size;
86       ATTR_FALLTHROUGH;
87     case UP:
88       immVertex2f(POS_INDEX, 0, offset);
89       immVertex2f(POS_INDEX, 0, offset + length);
90       immVertex2f(POS_INDEX, 0, offset + length);
91       immVertex2f(POS_INDEX, -size, offset + length - size);
92       immVertex2f(POS_INDEX, 0, offset + length);
93       immVertex2f(POS_INDEX, size, offset + length - size);
94       break;
95   }
96 
97   immEnd();
98 }
99 
drawArrowHead(enum eArrowDirection dir,int size)100 static void drawArrowHead(enum eArrowDirection dir, int size)
101 {
102   immBegin(GPU_PRIM_LINES, 4);
103 
104   switch (dir) {
105     case LEFT:
106       size = -size;
107       ATTR_FALLTHROUGH;
108     case RIGHT:
109       immVertex2f(POS_INDEX, 0, 0);
110       immVertex2f(POS_INDEX, -size, -size);
111       immVertex2f(POS_INDEX, 0, 0);
112       immVertex2f(POS_INDEX, -size, size);
113       break;
114 
115     case DOWN:
116       size = -size;
117       ATTR_FALLTHROUGH;
118     case UP:
119       immVertex2f(POS_INDEX, 0, 0);
120       immVertex2f(POS_INDEX, -size, -size);
121       immVertex2f(POS_INDEX, 0, 0);
122       immVertex2f(POS_INDEX, size, -size);
123       break;
124   }
125 
126   immEnd();
127 }
128 
drawArc(float angle_start,float angle_end,int segments,float size)129 static void drawArc(float angle_start, float angle_end, int segments, float size)
130 {
131   float delta = (angle_end - angle_start) / segments;
132   float angle;
133   int a;
134 
135   immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
136 
137   for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
138     immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
139   }
140   immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
141 
142   immEnd();
143 }
144 
145 /**
146  * Poll callback for cursor drawing:
147  * #WM_paint_cursor_activate
148  */
transform_draw_cursor_poll(bContext * C)149 bool transform_draw_cursor_poll(bContext *C)
150 {
151   ARegion *region = CTX_wm_region(C);
152 
153   if (region && region->regiontype == RGN_TYPE_WINDOW) {
154     return 1;
155   }
156   return 0;
157 }
158 
159 /**
160  * Cursor and help-line drawing, callback for:
161  * #WM_paint_cursor_activate
162  */
transform_draw_cursor_draw(bContext * UNUSED (C),int x,int y,void * customdata)163 void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
164 {
165   TransInfo *t = (TransInfo *)customdata;
166 
167   if (t->helpline != HLP_NONE) {
168     struct ArrowDims arrow_dims = {
169         .offset = 5 * UI_DPI_FAC,
170         .length = 10 * UI_DPI_FAC,
171         .size = 5 * UI_DPI_FAC,
172     };
173 
174     float cent[2];
175     const float mval[3] = {x, y, 0.0f};
176     float tmval[2] = {
177         (float)t->mval[0],
178         (float)t->mval[1],
179     };
180 
181     projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
182     /* Offset the values for the area region. */
183     const float offset[2] = {
184         t->region->winrct.xmin,
185         t->region->winrct.ymin,
186     };
187 
188     for (int i = 0; i < 2; i++) {
189       cent[i] += offset[i];
190       tmval[i] += offset[i];
191     }
192 
193     GPU_line_smooth(true);
194     GPU_blend(GPU_BLEND_ALPHA);
195 
196     GPU_matrix_push();
197 
198     /* Dashed lines first. */
199     if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
200       const uint shdr_pos = GPU_vertformat_attr_add(
201           immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
202 
203       UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
204       BLI_assert(shdr_pos == POS_INDEX);
205 
206       GPU_line_width(1.0f);
207 
208       immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
209 
210       float viewport_size[4];
211       GPU_viewport_size_get_f(viewport_size);
212       immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
213 
214       immUniform1i("colors_len", 0); /* "simple" mode */
215       immUniformThemeColor3(TH_VIEW_OVERLAY);
216       immUniform1f("dash_width", 6.0f * UI_DPI_FAC);
217       immUniform1f("dash_factor", 0.5f);
218 
219       immBegin(GPU_PRIM_LINES, 2);
220       immVertex2fv(POS_INDEX, cent);
221       immVertex2f(POS_INDEX, tmval[0], tmval[1]);
222       immEnd();
223 
224       immUnbindProgram();
225     }
226 
227     /* And now, solid lines. */
228     uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
229     UNUSED_VARS_NDEBUG(pos); /* silence warning */
230     BLI_assert(pos == POS_INDEX);
231     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
232 
233     switch (t->helpline) {
234       case HLP_SPRING:
235         immUniformThemeColor3(TH_VIEW_OVERLAY);
236 
237         GPU_matrix_translate_3fv(mval);
238         GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
239 
240         GPU_line_width(3.0f);
241         drawArrow(UP, &arrow_dims);
242         drawArrow(DOWN, &arrow_dims);
243         break;
244       case HLP_HARROW:
245         immUniformThemeColor3(TH_VIEW_OVERLAY);
246         GPU_matrix_translate_3fv(mval);
247 
248         GPU_line_width(3.0f);
249         drawArrow(RIGHT, &arrow_dims);
250         drawArrow(LEFT, &arrow_dims);
251         break;
252       case HLP_VARROW:
253         immUniformThemeColor3(TH_VIEW_OVERLAY);
254 
255         GPU_matrix_translate_3fv(mval);
256 
257         GPU_line_width(3.0f);
258         drawArrow(UP, &arrow_dims);
259         drawArrow(DOWN, &arrow_dims);
260         break;
261       case HLP_CARROW: {
262         /* Draw arrow based on direction defined by custom-points. */
263         immUniformThemeColor3(TH_VIEW_OVERLAY);
264 
265         GPU_matrix_translate_3fv(mval);
266 
267         GPU_line_width(3.0f);
268 
269         const int *data = t->mouse.data;
270         const float dx = data[2] - data[0], dy = data[3] - data[1];
271         const float angle = -atan2f(dx, dy);
272 
273         GPU_matrix_push();
274 
275         GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
276 
277         drawArrow(UP, &arrow_dims);
278         drawArrow(DOWN, &arrow_dims);
279 
280         GPU_matrix_pop();
281         break;
282       }
283       case HLP_ANGLE: {
284         float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
285         float angle = atan2f(dy, dx);
286         float dist = hypotf(dx, dy);
287         float delta_angle = min_ff(15.0f / (dist / UI_DPI_FAC), (float)M_PI / 4.0f);
288         float spacing_angle = min_ff(5.0f / (dist / UI_DPI_FAC), (float)M_PI / 12.0f);
289 
290         immUniformThemeColor3(TH_VIEW_OVERLAY);
291 
292         GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
293 
294         GPU_line_width(3.0f);
295         drawArc(angle - delta_angle, angle - spacing_angle, 10, dist);
296         drawArc(angle + spacing_angle, angle + delta_angle, 10, dist);
297 
298         GPU_matrix_push();
299 
300         GPU_matrix_translate_3f(
301             cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
302         GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
303 
304         drawArrowHead(DOWN, arrow_dims.size);
305 
306         GPU_matrix_pop();
307 
308         GPU_matrix_translate_3f(
309             cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
310         GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
311 
312         drawArrowHead(UP, arrow_dims.size);
313         break;
314       }
315       case HLP_TRACKBALL: {
316         uchar col[3], col2[3];
317         UI_GetThemeColor3ubv(TH_GRID, col);
318 
319         GPU_matrix_translate_3fv(mval);
320 
321         GPU_line_width(3.0f);
322 
323         UI_make_axis_color(col, col2, 'X');
324         immUniformColor3ubv(col2);
325 
326         drawArrow(RIGHT, &arrow_dims);
327         drawArrow(LEFT, &arrow_dims);
328 
329         UI_make_axis_color(col, col2, 'Y');
330         immUniformColor3ubv(col2);
331 
332         drawArrow(UP, &arrow_dims);
333         drawArrow(DOWN, &arrow_dims);
334         break;
335       }
336     }
337 
338     immUnbindProgram();
339     GPU_matrix_pop();
340 
341     GPU_line_smooth(false);
342     GPU_blend(GPU_BLEND_NONE);
343   }
344 }
345