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