Blender V5.0
move3d_gizmo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
18
19#include "MEM_guardedalloc.h"
20
21#include "BLI_math_matrix.h"
22#include "BLI_math_vector.h"
24
25#include "BKE_context.hh"
26
27#include "GPU_immediate.hh"
28#include "GPU_immediate_util.hh"
29#include "GPU_matrix.hh"
30#include "GPU_select.hh"
31#include "GPU_state.hh"
32
33#include "RNA_access.hh"
34#include "RNA_define.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_gizmo_library.hh"
40#include "ED_screen.hh"
42#include "ED_view3d.hh"
43
44/* own includes */
46
47#define MVAL_MAX_PX_DIST 12.0f
48#define RING_2D_RESOLUTION 32
49
52 /* Added to 'matrix_basis' when calculating the matrix. */
53 float prop_co[3];
54};
55
56static void gizmo_move_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
57{
58 MoveGizmo3D *move = (MoveGizmo3D *)gz;
59
60 copy_m4_m4(r_matrix, move->gizmo.matrix_basis);
61 add_v3_v3(r_matrix[3], move->prop_co);
62}
63
65 wmGizmo *gz,
66 const wmEvent *event,
67 eWM_GizmoFlagTweak tweak_flag);
68
70 struct {
71 float mval[2];
72 /* Only for when using properties. */
73 float prop_co[3];
74 float matrix_final[4][4];
76 struct {
79
80 /* We could have other snap contexts, for now only support 3D view. */
82};
83
84/* -------------------------------------------------------------------- */
85
86static void move_geom_draw(const wmGizmo *gz,
87 const float color[4],
88 const bool select,
89 const int draw_options)
90{
91#ifdef USE_GIZMO_CUSTOM_DIAL
92 UNUSED_VARS(move3d, col, axis_modal_mat);
93 wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_move3d, select);
94#else
95 const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
96 const bool filled = (draw_style != ED_GIZMO_MOVE_STYLE_CROSS_2D) &&
97 (draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
100
102 /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
103 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
104
107
108 float viewport[4];
109 GPU_viewport_size_get_f(viewport);
110 immUniform2fv("viewportSize", &viewport[2]);
111 immUniform1f("lineWidth", (gz->line_width * U.pixelsize) + WM_gizmo_select_bias(select));
112
113 immUniformColor4fv(color);
114
115 /* Use the final scale as a radius if it's not already applied to the final matrix. */
116 const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
117
118 if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) {
119 if (filled) {
120 imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
121 }
122 else {
123 imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
124 }
125 }
126 else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) {
127 const float radius_diag = M_SQRT1_2 * radius;
129 immVertex3f(pos, radius_diag, radius_diag, 0.0f);
130 immVertex3f(pos, -radius_diag, -radius_diag, 0.0f);
131
132 immVertex3f(pos, -radius_diag, radius_diag, 0.0f);
133 immVertex3f(pos, radius_diag, -radius_diag, 0.0f);
134 immEnd();
135 }
136 else {
137 BLI_assert(0);
138 }
139
141
143#endif
144}
145
146static void move3d_get_translate(const wmGizmo *gz,
147 const wmEvent *event,
148 const ARegion *region,
149 float co_delta[3])
150{
151 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
152 const float xy_delta[2] = {
153 event->mval[0] - inter->init.mval[0],
154 event->mval[1] - inter->init.mval[1],
155 };
156
157 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
158 float co_ref[3];
159 mul_v3_mat3_m4v3(co_ref, gz->matrix_space, inter->init.prop_co);
160 const float zfac = ED_view3d_calc_zfac(rv3d, co_ref);
161
162 ED_view3d_win_to_delta(region, xy_delta, zfac, co_delta);
163
164 float matrix_space_inv[3][3];
165 copy_m3_m4(matrix_space_inv, gz->matrix_space);
166 invert_m3(matrix_space_inv);
167 mul_m3_v3(matrix_space_inv, co_delta);
168}
169
170static void move3d_draw_intern(const bContext *C,
171 wmGizmo *gz,
172 const bool select,
173 const bool highlight)
174{
175 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
176 const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
177 const bool align_view = (draw_options & ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW) != 0;
178 float color[4];
179 float matrix_final[4][4];
180 float matrix_align[4][4];
181
182 gizmo_color_get(gz, highlight, color);
183 WM_gizmo_calc_matrix_final(gz, matrix_final);
184
186 GPU_matrix_mul(matrix_final);
187
188 if (align_view) {
189 float matrix_final_unit[4][4];
191 normalize_m4_m4(matrix_final_unit, matrix_final);
192 mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit);
193 zero_v3(matrix_align[3]);
194 transpose_m4(matrix_align);
195 GPU_matrix_mul(matrix_align);
196 }
197
199 move_geom_draw(gz, color, select, draw_options);
202
203 if (gz->interaction_data) {
206
207 if (align_view) {
208 GPU_matrix_mul(matrix_align);
209 }
210
212 move_geom_draw(gz, blender::float4(0.5f, 0.5f, 0.5f, 0.5f), select, draw_options);
215 }
216}
217
218static void gizmo_move_draw_select(const bContext *C, wmGizmo *gz, int select_id)
219{
220 GPU_select_load_id(select_id);
221 move3d_draw_intern(C, gz, true, false);
222}
223
224static void gizmo_move_draw(const bContext *C, wmGizmo *gz)
225{
226 const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
227 const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
228
229 (void)is_modal;
230
232 move3d_draw_intern(C, gz, false, is_highlight);
234}
235
237 wmGizmo *gz,
238 const wmEvent *event,
239 eWM_GizmoFlagTweak tweak_flag)
240{
241 using namespace blender::ed;
242 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
243 if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
245 }
246 MoveGizmo3D *move = (MoveGizmo3D *)gz;
247 ARegion *region = CTX_wm_region(C);
248
249 float prop_delta[3];
250 if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
251 move3d_get_translate(gz, event, region, prop_delta);
252 }
253 else {
254 float mval_proj_init[2], mval_proj_curr[2];
255 if ((gizmo_window_project_2d(C, gz, inter->init.mval, 2, false, mval_proj_init) == false) ||
257 C, gz, blender::float2(blender::int2(event->mval)), 2, false, mval_proj_curr) ==
258 false))
259 {
261 }
262 sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init);
263 if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) {
264 mul_v2_fl(prop_delta, gz->scale_final);
265 }
266 prop_delta[2] = 0.0f;
267 }
268
269 if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
270 mul_v3_fl(prop_delta, 0.1f);
271 }
272
273 add_v3_v3v3(move->prop_co, inter->init.prop_co, prop_delta);
274
275 if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
276 if (inter->snap_context_v3d) {
277 float dist_px = MVAL_MAX_PX_DIST * U.pixelsize;
278 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
279 float co[3];
281 params.snap_target_select = SCE_SNAP_TARGET_ALL;
282 params.edit_mode_type = transform::SNAP_GEOM_EDIT;
285 inter->snap_context_v3d,
287 region,
290 &params,
291 nullptr,
292 mval_fl,
293 nullptr,
294 &dist_px,
295 co,
296 nullptr))
297 {
298 float matrix_space_inv[4][4];
299 invert_m4_m4(matrix_space_inv, gz->matrix_space);
300 mul_v3_m4v3(move->prop_co, matrix_space_inv, co);
301 }
302 }
303 }
304
305 /* set the property for the operator and call its modal function */
306 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
309 }
310 else {
311 zero_v3(move->prop_co);
312 }
313
315
316 inter->prev.tweak_flag = tweak_flag;
317
319}
320
321static void gizmo_move_exit(bContext *C, wmGizmo *gz, const bool cancel)
322{
323 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
324 bool use_reset_value = false;
325 const float *reset_value = nullptr;
326 if (cancel) {
327 /* Set the property for the operator and call its modal function. */
328 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
330 use_reset_value = true;
331 reset_value = inter->init.prop_co;
332 }
333 }
334
335 if (use_reset_value) {
336 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
338 WM_gizmo_target_property_float_set_array(C, gz, gz_prop, reset_value);
339 }
340 }
341
342 if (inter->snap_context_v3d) {
344 inter->snap_context_v3d = nullptr;
345 }
346
347 if (!cancel) {
348 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
351 }
352 }
353}
354
356{
357 const bool use_snap = RNA_boolean_get(gz->ptr, "use_snap");
358
360 inter->init.mval[0] = event->mval[0];
361 inter->init.mval[1] = event->mval[1];
362
363#if 0
364 copy_v3_v3(inter->init.prop_co, move->prop_co);
365#else
366 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
369 }
370#endif
371
373
374 if (use_snap) {
375 ScrArea *area = CTX_wm_area(C);
376 if (area) {
377 switch (area->spacetype) {
378 case SPACE_VIEW3D: {
380 CTX_data_scene(C), 0);
381 break;
382 }
383 default:
384 /* Not yet supported. */
385 BLI_assert(0);
386 }
387 }
388 }
389
390 gz->interaction_data = inter;
391
393}
394
395static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2])
396{
397 float point_local[2];
398
399 if (gizmo_window_project_2d(C, gz, blender::float2(blender::int2(mval)), 2, true, point_local) ==
400 false)
401 {
402 return -1;
403 }
404
405 /* The 'gz->scale_final' is already applied to the projection
406 * when #WM_GIZMO_DRAW_NO_SCALE isn't set. */
407 const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
408 if (len_squared_v2(point_local) < radius) {
409 return 0;
410 }
411
412 return -1;
413}
414
416{
417 MoveGizmo3D *move = (MoveGizmo3D *)gz;
420 }
421 else {
422 zero_v3(move->prop_co);
423 }
424}
425
426static int gizmo_move_cursor_get(wmGizmo * /*gz*/)
427{
429}
430
431/* -------------------------------------------------------------------- */
434
436{
437 /* identifiers */
438 gzt->idname = "GIZMO_GT_move_3d";
439
440 /* API callbacks. */
441 gzt->draw = gizmo_move_draw;
447 gzt->modal = gizmo_move_modal;
448 gzt->exit = gizmo_move_exit;
450
451 gzt->struct_size = sizeof(MoveGizmo3D);
452
453 /* rna */
454 static const EnumPropertyItem rna_enum_draw_style[] = {
455 {ED_GIZMO_MOVE_STYLE_RING_2D, "RING_2D", 0, "Ring", ""},
456 {ED_GIZMO_MOVE_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""},
457 {0, nullptr, 0, nullptr, nullptr},
458 };
459 static const EnumPropertyItem rna_enum_draw_options[] = {
460 {ED_GIZMO_MOVE_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
461 {ED_GIZMO_MOVE_DRAW_FLAG_FILL_SELECT, "FILL_SELECT", 0, "Use fill for selection test", ""},
462 {ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""},
463 {0, nullptr, 0, nullptr, nullptr},
464 };
465
467 gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_MOVE_STYLE_RING_2D, "Draw Style", "");
468 RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
469 RNA_def_boolean(gzt->srna, "use_snap", false, "Use Snap", "");
470
472}
473
478 /* Move Gizmo API */
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define M_SQRT1_2
void mul_m3_v3(const float M[3][3], float r[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) ATTR_NONNULL()
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void transpose_m4(float R[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])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
#define UNUSED_VARS(...)
#define SCE_SNAP_TO_VERTEX
@ SCE_SNAP_TARGET_ALL
@ SCE_SNAP_TO_EDGE
@ SCE_SNAP_TO_FACE
@ SPACE_VIEW3D
@ OPERATOR_RUNNING_MODAL
@ ED_GIZMO_MOVE_STYLE_CROSS_2D
@ ED_GIZMO_MOVE_STYLE_RING_2D
@ ED_GIZMO_MOVE_DRAW_FLAG_FILL_SELECT
@ ED_GIZMO_MOVE_DRAW_FLAG_FILL
@ ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:654
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex3f(uint attr_id, float x, float y, float z)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immBegin(GPUPrimType, uint vertex_len)
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
bool GPU_select_load_id(unsigned int id)
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_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)
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_TWEAK_PRECISE
@ WM_GIZMO_TWEAK_SNAP
@ WM_GIZMO_DRAW_NO_SCALE
@ WM_GIZMO_STATE_HIGHLIGHT
@ WM_GIZMO_STATE_MODAL
#define U
nullptr float
void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info, const bool, const float color[4])
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])
static float WM_gizmo_select_bias(bool select)
uint pos
uint col
#define select(A, B, C)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
static wmOperatorStatus gizmo_move_modal(bContext *C, wmGizmo *gz, const wmEvent *event, eWM_GizmoFlagTweak tweak_flag)
static wmOperatorStatus gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2])
void ED_gizmotypes_move_3d()
static void gizmo_move_exit(bContext *C, wmGizmo *gz, const bool cancel)
static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
static void gizmo_move_draw_select(const bContext *C, wmGizmo *gz, int select_id)
static void GIZMO_GT_move_3d(wmGizmoType *gzt)
static void move_geom_draw(const wmGizmo *gz, const float color[4], const bool select, const int draw_options)
static void gizmo_move_draw(const bContext *C, wmGizmo *gz)
static void move3d_draw_intern(const bContext *C, wmGizmo *gz, const bool select, const bool highlight)
static int gizmo_move_cursor_get(wmGizmo *)
static void gizmo_move_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
static void move3d_get_translate(const wmGizmo *gz, const wmEvent *event, const ARegion *region, float co_delta[3])
#define MVAL_MAX_PX_DIST
#define RING_2D_RESOLUTION
void snap_object_context_destroy(SnapObjectContext *sctx)
eSnapMode snap_object_project_view3d(SnapObjectContext *sctx, Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const eSnapMode snap_to, const SnapObjectParams *params, const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
SnapObjectContext * snap_object_context_create(Scene *scene, int flag)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
static void init(bNodeTree *, bNode *node)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
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)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void * regiondata
wmGizmo gizmo
float prop_co[3]
struct MoveInteraction::@251071062217200072365042223366371067205173111037 prev
blender::ed::transform::SnapObjectContext * snap_context_v3d
eWM_GizmoFlagTweak tweak_flag
float matrix_final[4][4]
struct MoveInteraction::@317337045344106004360361262275076231221003102035 init
float viewmat[4][4]
wmEventType type
Definition WM_types.hh:757
int mval[2]
Definition WM_types.hh:763
StructRNA * srna
wmGizmoFnDraw draw
wmGizmoFnModal modal
wmGizmoFnMatrixBasisGet matrix_basis_get
const char * idname
wmGizmoFnTestSelect test_select
wmGizmoFnExit exit
wmGizmoFnCursorGet cursor_get
wmGizmoFnInvoke invoke
wmGizmoFnDrawSelect draw_select
wmGizmoFnPropertyUpdate property_update
void * interaction_data
eWM_GizmoFlagState state
float matrix_basis[4][4]
float scale_final
PointerRNA * ptr
float matrix_space[4][4]
float line_width
eWM_GizmoFlag flag
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:52
@ MOUSEMOVE
void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
Definition wm_gizmo.cc:572
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)
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 *))