Blender V5.0
cage2d_gizmo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2014 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
15
16#include "MEM_guardedalloc.h"
17
18#include "BLI_dial_2d.h"
19#include "BLI_math_base_safe.h"
20#include "BLI_math_matrix.h"
21#include "BLI_math_rotation.h"
22#include "BLI_math_vector.h"
24#include "BLI_rect.h"
25
26#include "BKE_context.hh"
27
28#include "GPU_immediate.hh"
29#include "GPU_immediate_util.hh"
30#include "GPU_matrix.hh"
31#include "GPU_select.hh"
32#include "GPU_state.hh"
33
34#include "RNA_access.hh"
35#include "RNA_define.hh"
36
37#include "WM_api.hh"
38#include "WM_types.hh"
39
40#include "ED_gizmo_library.hh"
41#include "ED_screen.hh"
42
43/* own includes */
45
46#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
47/* The same as in `draw_cache.cc`. */
48#define CIRCLE_RESOL 32
49
50static int gizmo_cage2d_transform_flag_get(const wmGizmo *gz);
51
52static void gizmo_calc_rect_view_scale(const wmGizmo *gz, float scale[2])
53{
54 float matrix_final_no_offset[4][4];
55 float x_axis[3], y_axis[3];
56 WM_gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset);
57 mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, gz->matrix_offset[0]);
58 mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, gz->matrix_offset[1]);
59
60 float len_x_axis = len_v3(x_axis);
61 float len_y_axis = len_v3(y_axis);
62
63 /* Set scale to zero if axis length is zero. */
64 scale[0] = safe_divide(1.0f, len_x_axis);
65 scale[1] = safe_divide(1.0f, len_y_axis);
66}
67
68static void gizmo_calc_rect_view_margin(const wmGizmo *gz, float margin[2])
69{
70 float handle_size;
71 handle_size = 0.15f;
72 handle_size *= gz->scale_final;
73 float scale_xy[2];
74 gizmo_calc_rect_view_scale(gz, scale_xy);
75
76 margin[0] = (handle_size * scale_xy[0]);
77 margin[1] = (handle_size * scale_xy[1]);
78}
79
80/* -------------------------------------------------------------------- */
85
86static void cage2d_draw_box_corners(const rctf *r,
87 const float margin[2],
88 const float color[3],
89 const float line_width)
90{
91 /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
93 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
94
96 immUniformColor3fv(color);
97
98 float viewport[4];
100 immUniform2fv("viewportSize", &viewport[2]);
101
102 immUniform1f("lineWidth", line_width * U.pixelsize);
103
105
106 immVertex3f(pos, r->xmin, r->ymin + margin[1], 0.0f);
107 immVertex3f(pos, r->xmin, r->ymin, 0.0f);
108 immVertex3f(pos, r->xmin, r->ymin, 0.0f);
109 immVertex3f(pos, r->xmin + margin[0], r->ymin, 0.0f);
110
111 immVertex3f(pos, r->xmax, r->ymin + margin[1], 0.0f);
112 immVertex3f(pos, r->xmax, r->ymin, 0.0f);
113 immVertex3f(pos, r->xmax, r->ymin, 0.0f);
114 immVertex3f(pos, r->xmax - margin[0], r->ymin, 0.0f);
115
116 immVertex3f(pos, r->xmax, r->ymax - margin[1], 0.0f);
117 immVertex3f(pos, r->xmax, r->ymax, 0.0f);
118 immVertex3f(pos, r->xmax, r->ymax, 0.0f);
119 immVertex3f(pos, r->xmax - margin[0], r->ymax, 0.0f);
120
121 immVertex3f(pos, r->xmin, r->ymax - margin[1], 0.0f);
122 immVertex3f(pos, r->xmin, r->ymax, 0.0f);
123 immVertex3f(pos, r->xmin, r->ymax, 0.0f);
124 immVertex3f(pos, r->xmin + margin[0], r->ymax, 0.0f);
125
126 immEnd();
127
129}
130
131static void cage2d_draw_box_interaction(const float color[4],
132 const int highlighted,
133 const float size[2],
134 const float margin[2],
135 const float line_width,
136 const bool is_solid,
137 const int draw_options)
138{
139 /* 4 verts for translate, otherwise only 3 are used. */
140 float verts[4][2];
141 uint verts_len = 0;
142 GPUPrimType prim_type = GPU_PRIM_NONE;
143
144 switch (highlighted) {
146 rctf r;
147 r.xmin = -size[0];
148 r.xmax = -size[0] + margin[0];
149 r.ymin = -size[1] + margin[1];
150 r.ymax = size[1] - margin[1];
151
152 ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
153 ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax);
154 verts_len = 2;
155 if (is_solid) {
156 ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
157 ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin);
158 verts_len += 2;
159 prim_type = GPU_PRIM_TRI_FAN;
160 }
161 else {
162 prim_type = GPU_PRIM_LINE_STRIP;
163 }
164 break;
165 }
167 rctf r;
168 r.xmin = size[0] - margin[0];
169 r.xmax = size[0];
170 r.ymin = -size[1] + margin[1];
171 r.ymax = size[1] - margin[1];
172
173 ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin);
174 ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
175 verts_len = 2;
176 if (is_solid) {
177 ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax);
178 ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
179 verts_len += 2;
180 prim_type = GPU_PRIM_TRI_FAN;
181 }
182 else {
183 prim_type = GPU_PRIM_LINE_STRIP;
184 }
185 break;
186 }
188 rctf r;
189 r.xmin = -size[0] + margin[0];
190 r.xmax = size[0] - margin[0];
191 r.ymin = -size[1];
192 r.ymax = -size[1] + margin[1];
193
194 ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
195 ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin);
196 verts_len = 2;
197 if (is_solid) {
198 ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
199 ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax);
200 verts_len += 2;
201 prim_type = GPU_PRIM_TRI_FAN;
202 }
203 else {
204 prim_type = GPU_PRIM_LINE_STRIP;
205 }
206 break;
207 }
209 rctf r;
210 r.xmin = -size[0] + margin[0];
211 r.xmax = size[0] - margin[0];
212 r.ymin = size[1] - margin[1];
213 r.ymax = size[1];
214
215 ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax);
216 ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
217 verts_len = 2;
218 if (is_solid) {
219 ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin);
220 ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
221 verts_len += 2;
222 prim_type = GPU_PRIM_TRI_FAN;
223 }
224 else {
225 prim_type = GPU_PRIM_LINE_STRIP;
226 }
227 break;
228 }
230 rctf r;
231 r.xmin = -size[0];
232 r.xmax = -size[0] + margin[0];
233 r.ymin = -size[1];
234 r.ymax = -size[1] + margin[1];
235
236 ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin);
237 ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
238 ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax);
239 verts_len = 3;
240 if (is_solid) {
241 ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
242 verts_len += 1;
243 prim_type = GPU_PRIM_TRI_FAN;
244 }
245 else {
246 prim_type = GPU_PRIM_LINE_STRIP;
247 }
248 break;
249 }
251 rctf r;
252 r.xmin = -size[0];
253 r.xmax = -size[0] + margin[0];
254 r.ymin = size[1] - margin[1];
255 r.ymax = size[1];
256
257 ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymax);
258 ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin);
259 ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymin);
260 verts_len = 3;
261 if (is_solid) {
262 ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax);
263 verts_len += 1;
264 prim_type = GPU_PRIM_TRI_FAN;
265 }
266 else {
267 prim_type = GPU_PRIM_LINE_STRIP;
268 }
269 break;
270 }
272 rctf r;
273 r.xmin = size[0] - margin[0];
274 r.xmax = size[0];
275 r.ymin = -size[1];
276 r.ymax = -size[1] + margin[1];
277
278 ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
279 ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax);
280 ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
281 verts_len = 3;
282 if (is_solid) {
283 ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin);
284 verts_len += 1;
285 prim_type = GPU_PRIM_TRI_FAN;
286 }
287 else {
288 prim_type = GPU_PRIM_LINE_STRIP;
289 }
290 break;
291 }
293 rctf r;
294 r.xmin = size[0] - margin[0];
295 r.xmax = size[0];
296 r.ymin = size[1] - margin[1];
297 r.ymax = size[1];
298
299 ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax);
300 ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymin);
301 ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin);
302 verts_len = 3;
303 if (is_solid) {
304 ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymax);
305 verts_len += 1;
306 prim_type = GPU_PRIM_TRI_FAN;
307 }
308 else {
309 prim_type = GPU_PRIM_LINE_STRIP;
310 }
311 break;
312 }
314 const float rotate_pt[2] = {0.0f, size[1] + margin[1]};
315 rctf r_rotate{};
316 r_rotate.xmin = rotate_pt[0] - margin[0] / 2.0f;
317 r_rotate.xmax = rotate_pt[0] + margin[0] / 2.0f;
318 r_rotate.ymin = rotate_pt[1] - margin[1] / 2.0f;
319 r_rotate.ymax = rotate_pt[1] + margin[1] / 2.0f;
320
321 ARRAY_SET_ITEMS(verts[0], r_rotate.xmin, r_rotate.ymin);
322 ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax);
323 ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax);
324 ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin);
325
326 verts_len = 4;
327 if (is_solid) {
328 prim_type = GPU_PRIM_TRI_FAN;
329 }
330 else {
331 prim_type = GPU_PRIM_LINE_STRIP;
332 }
333 break;
334 }
335
338 ARRAY_SET_ITEMS(verts[0], -margin[0] / 2, -margin[1] / 2);
339 ARRAY_SET_ITEMS(verts[1], margin[0] / 2, margin[1] / 2);
340 ARRAY_SET_ITEMS(verts[2], -margin[0] / 2, margin[1] / 2);
341 ARRAY_SET_ITEMS(verts[3], margin[0] / 2, -margin[1] / 2);
342 verts_len = 4;
343 if (is_solid) {
344 prim_type = GPU_PRIM_TRI_FAN;
345 }
346 else {
347 prim_type = GPU_PRIM_LINES;
348 }
349 }
350 else {
351 /* Only used for 3D view selection, never displayed to the user. */
352 ARRAY_SET_ITEMS(verts[0], -size[0], -size[1]);
353 ARRAY_SET_ITEMS(verts[1], -size[0], size[1]);
354 ARRAY_SET_ITEMS(verts[2], size[0], size[1]);
355 ARRAY_SET_ITEMS(verts[3], size[0], -size[1]);
356 verts_len = 4;
357 if (is_solid) {
358 prim_type = GPU_PRIM_TRI_FAN;
359 }
360 else {
361 /* unreachable */
362 BLI_assert(0);
363 prim_type = GPU_PRIM_LINE_STRIP;
364 }
365 }
366 break;
367 default:
368 return;
369 }
370
371 BLI_assert(prim_type != GPU_PRIM_NONE);
372
374 struct {
375 uint pos, col;
376 } attr_id{};
377 attr_id.pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
379 format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32);
381
382 {
383 if (is_solid) {
384
385 if (margin[0] == 0.0f && margin[1] == 0.0) {
386 prim_type = GPU_PRIM_POINTS;
387 }
388 else if (margin[0] == 0.0f || margin[1] == 0.0) {
389 prim_type = GPU_PRIM_LINE_STRIP;
390 }
391 else {
392 BLI_assert(ELEM(prim_type, GPU_PRIM_TRI_FAN));
393 }
394
395 immBegin(prim_type, verts_len);
396 immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
397 for (uint i = 0; i < verts_len; i++) {
399 }
400 immEnd();
401 }
402 else {
404
405 float viewport[4];
406 GPU_viewport_size_get_f(viewport);
407 immUniform2fv("viewportSize", &viewport[2]);
408
409 immUniform1f("lineWidth", (line_width * 3.0f) * U.pixelsize);
410
411 immBegin(prim_type, verts_len);
412 immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
413 for (uint i = 0; i < verts_len; i++) {
415 }
416 immEnd();
417
418 immUniform1f("lineWidth", line_width * U.pixelsize);
419
420 immBegin(prim_type, verts_len);
421 immAttr3fv(attr_id.col, color);
422 for (uint i = 0; i < verts_len; i++) {
424 }
425 immEnd();
426 }
427 }
428
430}
431
433
434/* -------------------------------------------------------------------- */
439
441 uint pos, float x, float y, float rad_x, float rad_y, bool solid)
442{
443 if (rad_x == 0 && rad_y == 0) {
445 immVertex2f(pos, x, y);
446 immEnd();
447 return;
448 }
449
450 if (rad_x == 0 || rad_y == 0) {
451 /* Do not draw anything if only on of the radii is zero. */
452 return;
453 }
454
455 if (solid) {
456 /* NOTE(Metal/AMD): Small Triangle-list primitives more optimal for GPU HW than Triangle-strip.
457 */
459 immVertex2f(pos, x - rad_x, y - rad_y);
460 immVertex2f(pos, x - rad_x, y + rad_y);
461 immVertex2f(pos, x + rad_x, y + rad_y);
462
463 immVertex2f(pos, x - rad_x, y - rad_y);
464 immVertex2f(pos, x + rad_x, y + rad_y);
465 immVertex2f(pos, x + rad_x, y - rad_y);
466 immEnd();
467 }
468 else {
469 /* NOTE(Metal/AMD): Small Line-list primitives more optimal for GPU HW than Line-strip. */
471 immVertex2f(pos, x - rad_x, y - rad_y);
472 immVertex2f(pos, x - rad_x, y + rad_y);
473
474 immVertex2f(pos, x - rad_x, y + rad_y);
475 immVertex2f(pos, x + rad_x, y + rad_y);
476
477 immVertex2f(pos, x + rad_x, y + rad_y);
478 immVertex2f(pos, x + rad_x, y - rad_y);
479
480 immVertex2f(pos, x + rad_x, y - rad_y);
481 immVertex2f(pos, x - rad_x, y - rad_y);
482 immEnd();
483 }
484}
485
486static void cage2d_draw_rect_wire(const rctf *r,
487 const float margin[2],
488 const float color[3],
489 const int transform_flag,
490 const int draw_options,
491 const float line_width)
492{
493 /* NOTE(Metal): Prefer using 3D coordinates with 3D shader input, even if rendering 2D gizmo's.
494 */
496 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
497
499 immUniformColor3fv(color);
500
501 float viewport[4];
502 GPU_viewport_size_get_f(viewport);
503 immUniform2fv("viewportSize", &viewport[2]);
504 immUniform1f("lineWidth", line_width * U.pixelsize);
505
506 /* Small 'lines' primitives more efficient for hardware processing than line-strip. */
508 immVertex3f(pos, r->xmin, r->ymin, 0.0f);
509 immVertex3f(pos, r->xmax, r->ymin, 0.0f);
510
511 immVertex3f(pos, r->xmax, r->ymin, 0.0f);
512 immVertex3f(pos, r->xmax, r->ymax, 0.0f);
513
514 immVertex3f(pos, r->xmax, r->ymax, 0.0f);
515 immVertex3f(pos, r->xmin, r->ymax, 0.0f);
516
517 immVertex3f(pos, r->xmin, r->ymax, 0.0f);
518 immVertex3f(pos, r->xmin, r->ymin, 0.0f);
519 immEnd();
520
521 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
523 immVertex3f(pos, BLI_rctf_cent_x(r), r->ymax, 0.0f);
524 immVertex3f(pos, BLI_rctf_cent_x(r), r->ymax + margin[1], 0.0f);
525
526 immVertex3f(pos, BLI_rctf_cent_x(r), r->ymax + margin[1], 0.0f);
527 immVertex3f(pos, BLI_rctf_cent_x(r), r->ymax, 0.0f);
528 immEnd();
529 }
530
531 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
533 const float rad[2] = {margin[0] / 2, margin[1] / 2};
534 const float center[2] = {BLI_rctf_cent_x(r), BLI_rctf_cent_y(r)};
535
537 immVertex3f(pos, center[0] - rad[0], center[1] - rad[1], 0.0f);
538 immVertex3f(pos, center[0] + rad[0], center[1] + rad[1], 0.0f);
539 immVertex3f(pos, center[0] + rad[0], center[1] - rad[1], 0.0f);
540 immVertex3f(pos, center[0] - rad[0], center[1] + rad[1], 0.0f);
541 immEnd();
542 }
543 }
544
546}
547
548static void cage2d_draw_circle_wire(const float color[3],
549 const float size[2],
550 const float margin[2],
551 const int transform_flag,
552 const int draw_options,
553 const float line_width)
554{
556 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
557
558 const bool use_points = is_zero_v2(margin);
561 immUniformColor3fv(color);
562
563 if (use_points) {
564 /* Draw a central point. */
565 immUniform1f("size", 1.0 * U.pixelsize);
567 immVertex3f(pos, 0.0f, 0.0f, 0.0f);
568 immEnd();
569 }
570 else {
571 float viewport[4];
572 GPU_viewport_size_get_f(viewport);
573 immUniform2fv("viewportSize", &viewport[2]);
574 immUniform1f("lineWidth", line_width * U.pixelsize);
576 }
577
578 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
580 immVertex3f(pos, 0.0f, size[1], 0.0f);
581 immVertex3f(pos, 0.0f, size[1] + margin[1], 0.0f);
582
583 immVertex3f(pos, 0.0f, size[1] + margin[1], 0.0f);
584 immVertex3f(pos, 0.0f, size[1], 0.0f);
585 immEnd();
586 }
587
588 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
590 const float rad[2] = {margin[0] / 2, margin[1] / 2};
591 const float center[2] = {0.0f, 0.0f};
592
594 immVertex3f(pos, center[0] - rad[0], center[1] - rad[1], 0.0f);
595 immVertex3f(pos, center[0] + rad[0], center[1] + rad[1], 0.0f);
596 immVertex3f(pos, center[0] + rad[0], center[1] - rad[1], 0.0f);
597 immVertex3f(pos, center[0] - rad[0], center[1] + rad[1], 0.0f);
598 immEnd();
599 }
600 }
601
603}
604
613
615 const float margin[2],
616 const float color[3],
617 bool solid)
618{
620 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
621 void (*circle_fn)(uint, float, float, float, float, int) = (solid) ?
624 const int resolu = 12;
625 const float rad[2] = {margin[0] / 3, margin[1] / 3};
626
628 immUniformColor3fv(color);
629
630 const float handle[2] = {
632 r->ymax + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE),
633 };
634 circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu);
635
637}
638
640 const float margin[2],
641 const float color[3],
642 bool solid)
643{
645 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
646 const float rad[2] = {margin[0] / 3, margin[1] / 3};
647
649 immUniformColor3fv(color);
650
651 /* Should really divide by two, but looks too bulky. */
652 {
653 imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid);
654 imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid);
655 imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid);
656 imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid);
657 }
658
660}
661
663 const int highlighted,
664 const float size[2],
665 const float margin[2],
666 const float color[3],
667 bool solid)
668{
670 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
671
673 immUniformColor3fv(color);
674
675 switch (highlighted) {
678 const float rad[2] = {0.2f * margin[0], 0.4f * size[1]};
679 imm_draw_point_aspect_2d(pos, r->xmin, 0.0f, rad[0], rad[1], solid);
680 imm_draw_point_aspect_2d(pos, r->xmax, 0.0f, rad[0], rad[1], solid);
681 break;
682 }
685 const float rad[2] = {0.4f * size[0], 0.2f * margin[1]};
686 imm_draw_point_aspect_2d(pos, 0.0f, r->ymin, rad[0], rad[1], solid);
687 imm_draw_point_aspect_2d(pos, 0.0f, r->ymax, rad[0], rad[1], solid);
688 break;
689 }
690 }
691
693}
694
696
698 const bool select,
699 const bool highlight,
700 const int select_id)
701{
702 // const bool use_clamp = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) == 0;
703 float dims[2];
704 RNA_float_get_array(gz->ptr, "dimensions", dims);
705 float matrix_final[4][4];
706
707 const int transform_flag = gizmo_cage2d_transform_flag_get(gz);
708 const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
709 const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
710
711 const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f};
712
713 WM_gizmo_calc_matrix_final(gz, matrix_final);
714
716 GPU_matrix_mul(matrix_final);
717
718 float margin[2];
719 gizmo_calc_rect_view_margin(gz, margin);
720
721 /* Handy for quick testing draw (if it's outside bounds). */
722 if (false) {
725 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
727 immUniformColor4f(1, 1, 1, 0.5f);
728 float s = 0.5f;
729 immRectf(pos, -s, -s, s, s);
732 }
733
734 if (select) {
735 /* Expand for hot-spot. */
736 const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
737 if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
738 /* Only scaling is needed for now. */
740
741 cage2d_draw_circle_wire(gz->color, size_real, margin, 0, draw_options, gz->line_width);
742 }
743 else {
744 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE) {
745 int scale_parts[] = {
750
755 };
756 for (int i = 0; i < ARRAY_SIZE(scale_parts); i++) {
757 GPU_select_load_id(select_id | scale_parts[i]);
759 gz->color, scale_parts[i], size, margin, gz->line_width, true, draw_options);
760 }
761 }
762 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
763 const int transform_part = ED_GIZMO_CAGE2D_PART_TRANSLATE;
764 GPU_select_load_id(select_id | transform_part);
766 gz->color, transform_part, size, margin, gz->line_width, true, draw_options);
767 }
768 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
771 size_real,
772 margin,
773 gz->line_width,
774 true,
775 draw_options);
776 }
777 }
778 }
779 else {
780 rctf r;
781 r.xmin = -size_real[0];
782 r.ymin = -size_real[1];
783 r.xmax = size_real[0];
784 r.ymax = size_real[1];
785
786 if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
787 float color[4], black[3] = {0, 0, 0};
788 gizmo_color_get(gz, highlight, color);
789
790 /* corner gizmos */
791 cage2d_draw_box_corners(&r, margin, black, gz->line_width + 3.0f);
792
793 /* corner gizmos */
794 cage2d_draw_box_corners(&r, margin, color, gz->line_width);
795
796 bool show = false;
798 /* Only show if we're drawing the center handle
799 * otherwise the entire rectangle is the hot-spot. */
801 show = true;
802 }
803 }
804 else {
805 show = true;
806 }
807
808 if (show) {
810 gz->color, gz->highlight_part, size_real, margin, gz->line_width, false, draw_options);
811 }
812
813 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
816 size_real,
817 margin,
818 gz->line_width,
819 false,
820 draw_options);
821 }
822 }
823 else {
824 float color[4], black[3] = {0, 0, 0};
825 gizmo_color_get(gz, highlight, color);
826
828
829 float outline_line_width = gz->line_width + 3.0f;
830
831 if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX_TRANSFORM) {
832 cage2d_draw_rect_wire(&r, margin, black, transform_flag, draw_options, outline_line_width);
833 cage2d_draw_rect_wire(&r, margin, color, transform_flag, draw_options, gz->line_width);
834
835 /* Edge handles. */
836 cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, color, true);
837 cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, black, false);
838
839 /* Only draw corner handles when hovering over the corners. */
841 cage2d_draw_rect_corner_handles(&r, margin, color, true);
842 cage2d_draw_rect_corner_handles(&r, margin, black, false);
843 }
844
845 /* Rotate handles. */
846 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
847 cage2d_draw_rect_rotate_handle(&r, margin, color, true);
848 cage2d_draw_rect_rotate_handle(&r, margin, black, false);
849 }
850 }
851 else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
853 black, size_real, margin, transform_flag, draw_options, outline_line_width);
855 color, size_real, margin, transform_flag, draw_options, gz->line_width);
856
857 /* Edge handles. */
858 cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, color, true);
859 cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, black, false);
860
861 /* Draw corner handles. */
862 if (draw_options & ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES) {
863 cage2d_draw_rect_corner_handles(&r, margin, color, true);
864 cage2d_draw_rect_corner_handles(&r, margin, black, false);
865 }
866
867 /* Rotation handles. */
868 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
869 cage2d_draw_rect_rotate_handle(&r, margin, color, true);
870 cage2d_draw_rect_rotate_handle(&r, margin, black, false);
871 }
872 }
873 else {
874 BLI_assert(0);
875 }
877 }
878 }
879
881}
882
886static void gizmo_cage2d_draw_select(const bContext * /*C*/, wmGizmo *gz, int select_id)
887{
888 gizmo_cage2d_draw_intern(gz, true, false, select_id);
889}
890
891static void gizmo_cage2d_draw(const bContext * /*C*/, wmGizmo *gz)
892{
893 const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
894 gizmo_cage2d_draw_intern(gz, false, is_highlight, -1);
895}
896
898{
899 int highlight_part = gz->highlight_part;
900
903 }
904
905 switch (highlight_part) {
914
915 /* TODO: diagonal cursor. */
923 return WM_CURSOR_CROSS;
924 default:
925 return WM_CURSOR_DEFAULT;
926 }
927}
928
929static int gizmo_cage2d_test_select(bContext *C, wmGizmo *gz, const int mval[2])
930{
931 float point_local[2];
932 float dims[2];
933 RNA_float_get_array(gz->ptr, "dimensions", dims);
934 const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f};
935
936 if (gizmo_window_project_2d(C, gz, blender::float2(blender::int2(mval)), 2, true, point_local) ==
937 false)
938 {
939 return -1;
940 }
941
942 float margin[2];
943 gizmo_calc_rect_view_margin(gz, margin);
944
945 /* Expand for hots-pot. */
946 const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
947
948 const int transform_flag = gizmo_cage2d_transform_flag_get(gz);
949 const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
950
951 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
952 rctf r;
954 r.xmin = -margin[0] / 2;
955 r.ymin = -margin[1] / 2;
956 r.xmax = margin[0] / 2;
957 r.ymax = margin[1] / 2;
958 }
959 else {
960 r.xmin = -size[0] + margin[0];
961 r.ymin = -size[1] + margin[1];
962 r.xmax = size[0] - margin[0];
963 r.ymax = size[1] - margin[1];
964 if (!BLI_rctf_is_valid(&r)) {
965 /* Typically happens when gizmo width or height is very small. */
967 }
968 }
969 bool isect = BLI_rctf_isect_pt_v(&r, point_local);
970 if (isect) {
972 }
973 }
974
975 /* if gizmo does not have a scale intersection, don't do it */
977 rctf r_xmin{};
978 r_xmin.xmin = -size[0];
979 r_xmin.ymin = -size[1];
980 r_xmin.xmax = -size[0] + margin[0];
981 r_xmin.ymax = size[1];
982
983 rctf r_xmax{};
984 r_xmax.xmin = size[0] - margin[0];
985 r_xmax.ymin = -size[1];
986 r_xmax.xmax = size[0];
987 r_xmax.ymax = size[1];
988
989 rctf r_ymin{};
990 r_ymin.xmin = -size[0];
991 r_ymin.ymin = -size[1];
992 r_ymin.xmax = size[0];
993 r_ymin.ymax = -size[1] + margin[1];
994
995 rctf r_ymax{};
996 r_ymax.xmin = -size[0];
997 r_ymax.ymin = size[1] - margin[1];
998 r_ymax.xmax = size[0];
999 r_ymax.ymax = size[1];
1000
1001 const bool draw_corners = draw_options & ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES;
1002
1003 if (BLI_rctf_isect_pt_v(&r_xmin, point_local)) {
1004 if (draw_corners) {
1005 if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
1007 }
1008 if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
1010 }
1011 }
1013 }
1014 if (BLI_rctf_isect_pt_v(&r_xmax, point_local)) {
1015 if (draw_corners) {
1016 if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
1018 }
1019 if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
1021 }
1022 }
1024 }
1025 if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
1027 }
1028 if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
1030 }
1031 }
1032
1033 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
1034 /* Rotate:
1035 * (*) <-- hot spot is here!
1036 * +---+
1037 * | |
1038 * +---+ */
1039 const float r_rotate_pt[2] = {0.0f, size_real[1] + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE)};
1040 rctf r_rotate{};
1041 r_rotate.xmin = r_rotate_pt[0] - margin[0] / 2.0f;
1042 r_rotate.xmax = r_rotate_pt[0] + margin[0] / 2.0f;
1043 r_rotate.ymin = r_rotate_pt[1] - margin[1] / 2.0f;
1044 r_rotate.ymax = r_rotate_pt[1] + margin[1] / 2.0f;
1045
1046 if (BLI_rctf_isect_pt_v(&r_rotate, point_local)) {
1048 }
1049 }
1050
1051 return -1;
1052}
1053
1054namespace {
1055
1056struct RectTransformInteraction {
1057 float orig_mouse[2];
1058 float orig_matrix_offset[4][4];
1059 float orig_matrix_final_no_offset[4][4];
1060 Dial *dial;
1061 bool use_temp_uniform;
1062};
1063
1064} // namespace
1065
1067{
1068 RectTransformInteraction *data = static_cast<RectTransformInteraction *>(gz->interaction_data);
1069 int transform_flag = RNA_enum_get(gz->ptr, "transform");
1070 if (data) {
1071 if (data->use_temp_uniform) {
1073 }
1074 }
1075 return transform_flag;
1076}
1077
1082
1084{
1085 RectTransformInteraction *data = MEM_callocN<RectTransformInteraction>("cage_interaction");
1086
1087 copy_m4_m4(data->orig_matrix_offset, gz->matrix_offset);
1088 WM_gizmo_calc_matrix_final_no_offset(gz, data->orig_matrix_final_no_offset);
1089
1091 C, gz, blender::float2(blender::int2(event->mval)), 2, false, data->orig_mouse) == 0)
1092 {
1093 zero_v2(data->orig_mouse);
1094 }
1095
1096 gz->interaction_data = data;
1097
1099}
1100
1101static void gizmo_constrain_from_scale_part(int part, bool r_constrain_axis[2])
1102{
1103 r_constrain_axis[0] = (part > ED_GIZMO_CAGE2D_PART_SCALE_MAX_X &&
1105 true :
1106 false;
1107 r_constrain_axis[1] = (part > ED_GIZMO_CAGE2D_PART_SCALE &&
1109 true :
1110 false;
1111}
1112
1113static void gizmo_pivot_from_scale_part(int part, float r_pt[2])
1114{
1115 switch (part) {
1117 ARRAY_SET_ITEMS(r_pt, 0.0, 0.0);
1118 break;
1119 }
1121 ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
1122 break;
1123 }
1125 ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
1126 break;
1127 }
1129 ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
1130 break;
1131 }
1133 ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
1134 break;
1135 }
1137 ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
1138 break;
1139 }
1141 ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
1142 break;
1143 }
1145 ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
1146 break;
1147 }
1149 ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
1150 break;
1151 }
1152 default:
1153 BLI_assert(0);
1154 }
1155}
1156
1158 wmGizmo *gz,
1159 const wmEvent *event,
1160 eWM_GizmoFlagTweak /*tweak_flag*/)
1161{
1162 RectTransformInteraction *data = static_cast<RectTransformInteraction *>(gz->interaction_data);
1163 int transform_flag = RNA_enum_get(gz->ptr, "transform");
1164 if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM) == 0) {
1165 /* WARNING: Checking the events modifier only makes sense as long as `tweak_flag`
1166 * remains unused (this controls #WM_GIZMO_TWEAK_PRECISE by default). */
1167 const bool use_temp_uniform = (event->modifier & KM_SHIFT) != 0;
1168 const bool changed = data->use_temp_uniform != use_temp_uniform;
1169 data->use_temp_uniform = use_temp_uniform;
1170 if (use_temp_uniform) {
1172 }
1173
1174 if (changed) {
1175 /* Always refresh. */
1176 }
1177 else if (event->type != MOUSEMOVE) {
1179 }
1180 }
1181
1182 float point_local[2];
1183
1184 float dims[2];
1185 RNA_float_get_array(gz->ptr, "dimensions", dims);
1186
1187 {
1188 float matrix_back[4][4];
1189 copy_m4_m4(matrix_back, gz->matrix_offset);
1190 copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
1191
1192 /* The mouse coords are projected into the matrix so we don't need to worry about axis
1193 * alignment. */
1194 bool ok = gizmo_window_project_2d(
1195 C, gz, blender::float2(blender::int2(event->mval)), 2, false, point_local);
1196 copy_m4_m4(gz->matrix_offset, matrix_back);
1197 if (!ok) {
1199 }
1200 }
1201
1202 wmGizmoProperty *gz_prop;
1203
1204 gz_prop = WM_gizmo_target_property_find(gz, "matrix");
1205 if (gz_prop->type != nullptr) {
1207 }
1208
1210 /* do this to prevent clamping from changing size */
1211 copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
1212 gz->matrix_offset[3][0] = data->orig_matrix_offset[3][0] +
1213 (point_local[0] - data->orig_mouse[0]);
1214 gz->matrix_offset[3][1] = data->orig_matrix_offset[3][1] +
1215 (point_local[1] - data->orig_mouse[1]);
1216 }
1218
1219#define MUL_V2_V3_M4_FINAL(test_co, mouse_co) \
1220 mul_v3_m4v3(test_co, data->orig_matrix_final_no_offset, blender::float3{UNPACK2(mouse_co), 0.0})
1221
1222 float test_co[3];
1223
1224 if (data->dial == nullptr) {
1225 MUL_V2_V3_M4_FINAL(test_co, data->orig_matrix_offset[3]);
1226
1227 data->dial = BLI_dial_init(test_co, FLT_EPSILON);
1228
1229 MUL_V2_V3_M4_FINAL(test_co, data->orig_mouse);
1230 BLI_dial_angle(data->dial, test_co);
1231 }
1232
1233 /* rotate */
1234 MUL_V2_V3_M4_FINAL(test_co, point_local);
1235 const float angle = BLI_dial_angle(data->dial, test_co);
1236
1237 float matrix_space_inv[4][4];
1238 float matrix_rotate[4][4];
1239 float pivot[3];
1240
1241 copy_v3_v3(pivot, data->orig_matrix_offset[3]);
1242
1243 invert_m4_m4(matrix_space_inv, gz->matrix_space);
1244
1245 unit_m4(matrix_rotate);
1246 mul_m4_m4m4(matrix_rotate, matrix_rotate, matrix_space_inv);
1247 rotate_m4(matrix_rotate, 'Z', -angle);
1248 mul_m4_m4m4(matrix_rotate, matrix_rotate, gz->matrix_space);
1249
1250 zero_v3(matrix_rotate[3]);
1251 transform_pivot_set_m4(matrix_rotate, pivot);
1252
1253 mul_m4_m4m4(gz->matrix_offset, matrix_rotate, data->orig_matrix_offset);
1254
1255#undef MUL_V2_V3_M4_FINAL
1256 }
1257 else {
1258 /* scale */
1259 copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
1260 const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
1261
1262 float pivot[2];
1263 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE) {
1265 mul_v2_v2(pivot, dims);
1266 }
1267 else {
1268 zero_v2(pivot);
1269 }
1270
1271 float curr_mouse[2];
1272 copy_v2_v2(curr_mouse, data->orig_mouse);
1273
1274 /* Rotate current and original mouse coordinates around gizmo center. */
1275 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_ROTATE) {
1276 float rot[3][3];
1277 float loc[3];
1278 float size[3];
1280
1281 invert_m3(rot);
1282 sub_v2_v2(point_local, loc);
1283 mul_m3_v2(rot, point_local);
1284 add_v2_v2(point_local, loc);
1285
1286 sub_v2_v2(curr_mouse, loc);
1287 mul_m3_v2(rot, curr_mouse);
1288 add_v2_v2(curr_mouse, loc);
1289 }
1290
1291 bool constrain_axis[2] = {false};
1293
1294 float size_new[2], size_orig[2];
1295 for (int i = 0; i < 2; i++) {
1296 size_orig[i] = len_v3(data->orig_matrix_offset[i]);
1297 size_new[i] = size_orig[i];
1298 if (constrain_axis[i] == false) {
1299 /* Original cursor position relative to pivot. */
1300 const float delta_orig = curr_mouse[i] - data->orig_matrix_offset[3][i] -
1301 pivot[i] * size_orig[i];
1302 const float delta_curr = point_local[i] - data->orig_matrix_offset[3][i] -
1303 pivot[i] * size_orig[i];
1304
1305 if ((transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED) == 0) {
1306 if (signum_i(delta_orig) != signum_i(delta_curr)) {
1307 size_new[i] = 0.0f;
1308 continue;
1309 }
1310 }
1311 /* Original cursor position does not exactly lie on the cage boundary due to margin. */
1312 size_new[i] = delta_curr / (signf(delta_orig) * 0.5f * dims[i] - pivot[i]);
1313 }
1314 }
1315
1316 float scale[2] = {1.0f, 1.0f};
1317 for (int i = 0; i < 2; i++) {
1318 if (size_orig[i] == 0) {
1319 size_orig[i] = 1.0f;
1320 gz->matrix_offset[i][i] = 1.0f;
1321 }
1322 scale[i] = size_new[i] / size_orig[i];
1323 }
1324
1325 if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM) {
1326 if (constrain_axis[0] == false && constrain_axis[1] == false) {
1327 if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
1328 /* So that the cursor lies on the circle. */
1329 scale[1] = scale[0] = len_v2(scale);
1330 }
1331 else {
1332 scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
1333 }
1334 }
1335 else if (constrain_axis[0] == false) {
1336 scale[1] = scale[0];
1337 }
1338 else if (constrain_axis[1] == false) {
1339 scale[0] = scale[1];
1340 }
1341 else {
1342 BLI_assert(0);
1343 }
1344 }
1345
1346 /* Scale around pivot. */
1347 float matrix_scale[4][4];
1348 unit_m4(matrix_scale);
1349
1350 mul_v3_fl(matrix_scale[0], scale[0]);
1351 mul_v3_fl(matrix_scale[1], scale[1]);
1352
1353 transform_pivot_set_m4(matrix_scale, blender::float3(UNPACK2(pivot), 0.0f));
1354 mul_m4_m4_post(gz->matrix_offset, matrix_scale);
1355 }
1356
1357 if (gz_prop->type != nullptr) {
1359 }
1360
1361 /* tag the region for redraw */
1363
1365}
1366
1368{
1369 if (STREQ(gz_prop->type->idname, "matrix")) {
1370 if (WM_gizmo_target_property_array_length(gz, gz_prop) == 16) {
1372 }
1373 else {
1374 BLI_assert(0);
1375 }
1376 }
1377 else {
1378 BLI_assert(0);
1379 }
1380}
1381
1382static void gizmo_cage2d_exit(bContext *C, wmGizmo *gz, const bool cancel)
1383{
1384 RectTransformInteraction *data = static_cast<RectTransformInteraction *>(gz->interaction_data);
1385
1386 if (data->dial) {
1387 BLI_dial_free(data->dial);
1388 data->dial = nullptr;
1389 }
1390
1391 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "matrix");
1392
1393 if (!cancel) {
1394 if (WM_gizmo_target_property_is_valid(gz_prop)) {
1396 }
1397 return;
1398 }
1399
1400 /* reset properties */
1401 if (gz_prop->type != nullptr) {
1402 WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &data->orig_matrix_offset[0][0]);
1403 }
1404
1405 copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
1406}
1407
1408/* -------------------------------------------------------------------- */
1411
1413{
1414 /* identifiers */
1415 gzt->idname = "GIZMO_GT_cage_2d";
1416
1417 /* API callbacks. */
1418 gzt->draw = gizmo_cage2d_draw;
1425 gzt->exit = gizmo_cage2d_exit;
1427
1428 gzt->struct_size = sizeof(wmGizmo);
1429
1430 /* rna */
1431 static const EnumPropertyItem rna_enum_draw_style[] = {
1432 {ED_GIZMO_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""},
1433 {ED_GIZMO_CAGE2D_STYLE_BOX_TRANSFORM, "BOX_TRANSFORM", 0, "Box Transform", ""},
1434 {ED_GIZMO_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""},
1435 {0, nullptr, 0, nullptr, nullptr},
1436 };
1437 static const EnumPropertyItem rna_enum_transform[] = {
1438 {ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Move", ""},
1439 {ED_GIZMO_CAGE_XFORM_FLAG_ROTATE, "ROTATE", 0, "Rotate", ""},
1440 {ED_GIZMO_CAGE_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""},
1441 {ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""},
1442 {0, nullptr, 0, nullptr, nullptr},
1443 };
1444 static const EnumPropertyItem rna_enum_draw_options[] = {
1445 {ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""},
1446 {ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES, "CORNER_HANDLES", 0, "Corner Handles", ""},
1447 {0, nullptr, 0, nullptr, nullptr},
1448 };
1449 static const float unit_v2[2] = {1.0f, 1.0f};
1451 gzt->srna, "dimensions", 2, unit_v2, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX);
1452 RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform, 0, "Transform Options", "");
1453 RNA_def_enum(gzt->srna,
1454 "draw_style",
1455 rna_enum_draw_style,
1457 "Draw Style",
1458 "");
1460 "draw_options",
1461 rna_enum_draw_options,
1463 "Draw Options",
1464 "");
1465
1466 WM_gizmotype_target_property_def(gzt, "matrix", PROP_FLOAT, 16);
1467}
1468
1473
ARegion * CTX_wm_region(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_dial_free(Dial *dial)
struct Dial Dial
Definition BLI_dial_2d.h:36
Dial * BLI_dial_init(const float start_position[2], float threshold)
float BLI_dial_angle(Dial *dial, const float current_position[2])
MINLINE float signf(float f)
MINLINE int signum_i(float a)
MINLINE float safe_divide(float a, float b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m3_v2(const float m[3][3], float r[2])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void rotate_m4(float mat[4][4], char axis, float angle)
void mul_m4_m4_post(float R[4][4], const float B[4][4])
void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m3(float mat[3][3])
void unit_m4(float m[4][4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE bool is_zero_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void zero_v2(float r[2])
MINLINE void zero_v3(float r[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
bool BLI_rctf_is_valid(const struct rctf *rect)
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:185
void BLI_rctf_sanitize(struct rctf *rect)
Definition rct.cc:434
unsigned int uint
#define UNPACK2(a)
#define ARRAY_SIZE(arr)
#define ARRAY_SET_ITEMS(...)
#define ELEM(...)
#define STREQ(a, b)
@ OPERATOR_RUNNING_MODAL
@ ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES
@ ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y
@ ED_GIZMO_CAGE2D_PART_TRANSLATE
@ ED_GIZMO_CAGE2D_PART_ROTATE
@ ED_GIZMO_CAGE2D_PART_SCALE
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y
@ ED_GIZMO_CAGE2D_STYLE_BOX_TRANSFORM
@ ED_GIZMO_CAGE2D_STYLE_BOX
@ ED_GIZMO_CAGE2D_STYLE_CIRCLE
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE
@ ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE
@ ED_GIZMO_CAGE_XFORM_FLAG_ROTATE
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE_SIGNED
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:654
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniformColor4f(float r, float g, float b, float a)
void immVertex2f(uint attr_id, float x, float y)
void immVertex3f(uint attr_id, float x, float y, float z)
void immVertex2fv(uint attr_id, const float data[2])
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immAttr3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immAttr3f(uint attr_id, float x, float y, float z)
void immUniformColor3fv(const float rgb[3])
void imm_draw_circle_wire_aspect_3d(uint pos, float x, float y, float radius_x, float radius_y, int nsegments)
void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
GPUPrimType
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_NONE
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
@ GPU_PRIM_TRIS
bool GPU_select_load_id(unsigned int id)
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_FLAT_COLOR
@ GPU_SHADER_3D_POLYLINE_FLAT_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:164
#define C
Definition RandGen.cpp:29
eWM_GizmoFlagTweak
Gizmo tweak flag. Bit-flag passed to gizmo while tweaking.
@ WM_GIZMO_DRAW_NO_SCALE
@ WM_GIZMO_DRAW_MODAL
@ WM_GIZMOGROUPTYPE_3D
@ WM_GIZMO_STATE_HIGHLIGHT
@ KM_SHIFT
Definition WM_types.hh:278
#define U
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static void gizmo_calc_rect_view_margin(const wmGizmo *gz, float margin[2])
void ED_gizmotypes_cage_2d()
static void gizmo_constrain_from_scale_part(int part, bool r_constrain_axis[2])
static void GIZMO_GT_cage_2d(wmGizmoType *gzt)
#define GIZMO_MARGIN_OFFSET_SCALE
static void cage2d_draw_rect_edge_handles(const rctf *r, const int highlighted, const float size[2], const float margin[2], const float color[3], bool solid)
static int gizmo_cage2d_get_cursor(wmGizmo *gz)
static void cage2d_draw_box_interaction(const float color[4], const int highlighted, const float size[2], const float margin[2], const float line_width, const bool is_solid, const int draw_options)
static void cage2d_draw_box_corners(const rctf *r, const float margin[2], const float color[3], const float line_width)
static wmOperatorStatus gizmo_cage2d_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
static void cage2d_draw_rect_rotate_handle(const rctf *r, const float margin[2], const float color[3], bool solid)
static bool is_corner_highlighted(const int highlighted)
static void cage2d_draw_circle_wire(const float color[3], const float size[2], const float margin[2], const int transform_flag, const int draw_options, const float line_width)
static wmOperatorStatus gizmo_cage2d_modal(bContext *C, wmGizmo *gz, const wmEvent *event, eWM_GizmoFlagTweak)
static void cage2d_draw_rect_wire(const rctf *r, const float margin[2], const float color[3], const int transform_flag, const int draw_options, const float line_width)
static void gizmo_pivot_from_scale_part(int part, float r_pt[2])
static void gizmo_cage2d_draw(const bContext *, wmGizmo *gz)
static int gizmo_cage2d_test_select(bContext *C, wmGizmo *gz, const int mval[2])
#define CIRCLE_RESOL
static void gizmo_calc_rect_view_scale(const wmGizmo *gz, float scale[2])
static void gizmo_cage2d_draw_select(const bContext *, wmGizmo *gz, int select_id)
static void imm_draw_point_aspect_2d(uint pos, float x, float y, float rad_x, float rad_y, bool solid)
#define MUL_V2_V3_M4_FINAL(test_co, mouse_co)
static void gizmo_cage2d_setup(wmGizmo *gz)
static void cage2d_draw_rect_corner_handles(const rctf *r, const float margin[2], const float color[3], bool solid)
static void gizmo_cage2d_exit(bContext *C, wmGizmo *gz, const bool cancel)
static void gizmo_cage2d_draw_intern(wmGizmo *gz, const bool select, const bool highlight, const int select_id)
static int gizmo_cage2d_transform_flag_get(const wmGizmo *gz)
static void gizmo_cage2d_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
nullptr float
#define rot(x, k)
static float verts[][3]
void gizmo_color_get(const wmGizmo *gz, bool highlight, float r_color[4])
bool gizmo_window_project_2d(bContext *C, const wmGizmo *gz, const float mval[2], int axis, bool use_offset, float r_co[2])
uint pos
uint col
struct @021025263243242147216143265077100330027142264337::@240232116316110053135047106323056371161236243121 attr_id
#define select(A, B, C)
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum_flag(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
#define FLT_MAX
Definition stdcycles.h:14
float xmax
float xmin
float ymax
float ymin
wmEventType type
Definition WM_types.hh:757
int mval[2]
Definition WM_types.hh:763
eWM_GizmoFlagGroupTypeFlag flag
wmGizmoGroupType * type
const wmGizmoPropertyType * type
StructRNA * srna
wmGizmoFnDraw draw
wmGizmoFnModal modal
wmGizmoFnSetup setup
const char * idname
wmGizmoFnTestSelect test_select
wmGizmoFnExit exit
wmGizmoFnCursorGet cursor_get
wmGizmoFnInvoke invoke
wmGizmoFnDrawSelect draw_select
wmGizmoFnPropertyUpdate property_update
wmGizmoGroup * parent_gzgroup
void * interaction_data
eWM_GizmoFlagState state
float matrix_offset[4][4]
float scale_final
float color[4]
PointerRNA * ptr
float matrix_space[4][4]
float line_width
eWM_GizmoFlag flag
i
Definition text_draw.cc:230
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:52
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
@ MOUSEMOVE
void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
Definition wm_gizmo.cc:572
void WM_gizmo_calc_matrix_final_no_offset(const wmGizmo *gz, float r_mat[4][4])
Definition wm_gizmo.cc:559
void WM_gizmo_target_property_anim_autokey(bContext *C, const wmGizmo *, wmGizmoProperty *gz_prop)
bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
void WM_gizmo_target_property_float_get_array(const wmGizmo *gz, wmGizmoProperty *gz_prop, float *value)
int WM_gizmo_target_property_array_length(const wmGizmo *, wmGizmoProperty *gz_prop)
void WM_gizmotype_target_property_def(wmGizmoType *gzt, const char *idname, int data_type, int array_length)
void WM_gizmo_target_property_float_set_array(bContext *C, const wmGizmo *gz, wmGizmoProperty *gz_prop, const float *value)
wmGizmoProperty * WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
void WM_gizmotype_append(void(*gtfunc)(wmGizmoType *))