Blender V4.3
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
19#include "MEM_guardedalloc.h"
20
21#include "BLI_math_matrix.h"
23
24#include "BKE_context.hh"
25
26#include "GPU_immediate.hh"
27#include "GPU_immediate_util.hh"
28#include "GPU_matrix.hh"
29#include "GPU_select.hh"
30#include "GPU_state.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "WM_api.hh"
36#include "WM_types.hh"
37
38#include "ED_gizmo_library.hh"
39#include "ED_screen.hh"
41#include "ED_view3d.hh"
42
43/* own includes */
45
46#define MVAL_MAX_PX_DIST 12.0f
47#define RING_2D_RESOLUTION 32
48
51 /* Added to 'matrix_basis' when calculating the matrix. */
52 float prop_co[3];
53};
54
55static void gizmo_move_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
56{
57 MoveGizmo3D *move = (MoveGizmo3D *)gz;
58
59 copy_m4_m4(r_matrix, move->gizmo.matrix_basis);
60 add_v3_v3(r_matrix[3], move->prop_co);
61}
62
63static int gizmo_move_modal(bContext *C,
64 wmGizmo *gz,
65 const wmEvent *event,
66 eWM_GizmoFlagTweak tweak_flag);
67
69 struct {
70 float mval[2];
71 /* Only for when using properties. */
72 float prop_co[3];
73 float matrix_final[4][4];
75 struct {
78
79 /* We could have other snap contexts, for now only support 3D view. */
81};
82
83/* -------------------------------------------------------------------- */
84
85static void move_geom_draw(const wmGizmo *gz,
86 const float color[4],
87 const bool select,
88 const int draw_options)
89{
90#ifdef USE_GIZMO_CUSTOM_DIAL
91 UNUSED_VARS(move3d, col, axis_modal_mat);
92 wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_move3d, select);
93#else
94 const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
95 const bool filled = (draw_style != ED_GIZMO_MOVE_STYLE_CROSS_2D) &&
96 (draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
99
101 /* NOTE(Metal): Prefer using 3D coordinates with 3D shader, even if rendering 2D gizmo's. */
103
106
107 float viewport[4];
108 GPU_viewport_size_get_f(viewport);
109 immUniform2fv("viewportSize", &viewport[2]);
110 immUniform1f("lineWidth", gz->line_width * U.pixelsize);
111
112 immUniformColor4fv(color);
113
114 /* Use the final scale as a radius if it's not already applied to the final matrix. */
115 const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
116
117 if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) {
118 if (filled) {
119 imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
120 }
121 else {
122 imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, radius, RING_2D_RESOLUTION);
123 }
124 }
125 else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) {
126 const float radius_diag = M_SQRT1_2 * radius;
128 immVertex3f(pos, radius_diag, radius_diag, 0.0f);
129 immVertex3f(pos, -radius_diag, -radius_diag, 0.0f);
130
131 immVertex3f(pos, -radius_diag, radius_diag, 0.0f);
132 immVertex3f(pos, radius_diag, -radius_diag, 0.0f);
133 immEnd();
134 }
135 else {
136 BLI_assert(0);
137 }
138
140
142#endif
143}
144
145static void move3d_get_translate(const wmGizmo *gz,
146 const wmEvent *event,
147 const ARegion *region,
148 float co_delta[3])
149{
150 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
151 const float xy_delta[2] = {
152 event->mval[0] - inter->init.mval[0],
153 event->mval[1] - inter->init.mval[1],
154 };
155
156 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
157 float co_ref[3];
158 mul_v3_mat3_m4v3(co_ref, gz->matrix_space, inter->init.prop_co);
159 const float zfac = ED_view3d_calc_zfac(rv3d, co_ref);
160
161 ED_view3d_win_to_delta(region, xy_delta, zfac, co_delta);
162
163 float matrix_space_inv[3][3];
164 copy_m3_m4(matrix_space_inv, gz->matrix_space);
165 invert_m3(matrix_space_inv);
166 mul_m3_v3(matrix_space_inv, co_delta);
167}
168
169static void move3d_draw_intern(const bContext *C,
170 wmGizmo *gz,
171 const bool select,
172 const bool highlight)
173{
174 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
175 const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
176 const bool align_view = (draw_options & ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW) != 0;
177 float color[4];
178 float matrix_final[4][4];
179 float matrix_align[4][4];
180
181 gizmo_color_get(gz, highlight, color);
182 WM_gizmo_calc_matrix_final(gz, matrix_final);
183
185 GPU_matrix_mul(matrix_final);
186
187 if (align_view) {
188 float matrix_final_unit[4][4];
190 normalize_m4_m4(matrix_final_unit, matrix_final);
191 mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit);
192 zero_v3(matrix_align[3]);
193 transpose_m4(matrix_align);
194 GPU_matrix_mul(matrix_align);
195 }
196
198 move_geom_draw(gz, color, select, draw_options);
201
202 if (gz->interaction_data) {
205
206 if (align_view) {
207 GPU_matrix_mul(matrix_align);
208 }
209
211 move_geom_draw(gz, blender::float4(0.5f, 0.5f, 0.5f, 0.5f), select, draw_options);
214 }
215}
216
217static void gizmo_move_draw_select(const bContext *C, wmGizmo *gz, int select_id)
218{
219 GPU_select_load_id(select_id);
220 move3d_draw_intern(C, gz, true, false);
221}
222
223static void gizmo_move_draw(const bContext *C, wmGizmo *gz)
224{
225 const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
226 const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
227
228 (void)is_modal;
229
231 move3d_draw_intern(C, gz, false, is_highlight);
233}
234
236 wmGizmo *gz,
237 const wmEvent *event,
238 eWM_GizmoFlagTweak tweak_flag)
239{
240 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
241 if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
243 }
244 MoveGizmo3D *move = (MoveGizmo3D *)gz;
245 ARegion *region = CTX_wm_region(C);
246
247 float prop_delta[3];
248 if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
249 move3d_get_translate(gz, event, region, prop_delta);
250 }
251 else {
252 float mval_proj_init[2], mval_proj_curr[2];
253 if ((gizmo_window_project_2d(C, gz, inter->init.mval, 2, false, mval_proj_init) == false) ||
255 C, gz, blender::float2(blender::int2(event->mval)), 2, false, mval_proj_curr) ==
256 false))
257 {
259 }
260 sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init);
261 if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) {
262 mul_v2_fl(prop_delta, gz->scale_final);
263 }
264 prop_delta[2] = 0.0f;
265 }
266
267 if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
268 mul_v3_fl(prop_delta, 0.1f);
269 }
270
271 add_v3_v3v3(move->prop_co, inter->init.prop_co, prop_delta);
272
273 if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
274 if (inter->snap_context_v3d) {
275 float dist_px = MVAL_MAX_PX_DIST * U.pixelsize;
276 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
277 float co[3];
279 params.snap_target_select = SCE_SNAP_TARGET_ALL;
280 params.edit_mode_type = SNAP_GEOM_EDIT;
281 params.occlusion_test = SNAP_OCCLUSION_AS_SEEM;
283 inter->snap_context_v3d,
285 region,
286 CTX_wm_view3d(C),
288 &params,
289 nullptr,
290 mval_fl,
291 nullptr,
292 &dist_px,
293 co,
294 nullptr))
295 {
296 float matrix_space_inv[4][4];
297 invert_m4_m4(matrix_space_inv, gz->matrix_space);
298 mul_v3_m4v3(move->prop_co, matrix_space_inv, co);
299 }
300 }
301 }
302
303 /* set the property for the operator and call its modal function */
304 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
306 WM_gizmo_target_property_float_set_array(C, gz, gz_prop, move->prop_co);
307 }
308 else {
309 zero_v3(move->prop_co);
310 }
311
313
314 inter->prev.tweak_flag = tweak_flag;
315
317}
318
319static void gizmo_move_exit(bContext *C, wmGizmo *gz, const bool cancel)
320{
321 MoveInteraction *inter = static_cast<MoveInteraction *>(gz->interaction_data);
322 bool use_reset_value = false;
323 const float *reset_value = nullptr;
324 if (cancel) {
325 /* Set the property for the operator and call its modal function. */
326 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
328 use_reset_value = true;
329 reset_value = inter->init.prop_co;
330 }
331 }
332
333 if (use_reset_value) {
334 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
336 WM_gizmo_target_property_float_set_array(C, gz, gz_prop, reset_value);
337 }
338 }
339
340 if (inter->snap_context_v3d) {
342 inter->snap_context_v3d = nullptr;
343 }
344
345 if (!cancel) {
346 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
349 }
350 }
351}
352
353static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
354{
355 const bool use_snap = RNA_boolean_get(gz->ptr, "use_snap");
356
357 MoveInteraction *inter = static_cast<MoveInteraction *>(
358 MEM_callocN(sizeof(MoveInteraction), __func__));
359 inter->init.mval[0] = event->mval[0];
360 inter->init.mval[1] = event->mval[1];
361
362#if 0
363 copy_v3_v3(inter->init.prop_co, move->prop_co);
364#else
365 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
368 }
369#endif
370
372
373 if (use_snap) {
374 ScrArea *area = CTX_wm_area(C);
375 if (area) {
376 switch (area->spacetype) {
377 case SPACE_VIEW3D: {
379 break;
380 }
381 default:
382 /* Not yet supported. */
383 BLI_assert(0);
384 }
385 }
386 }
387
388 gz->interaction_data = inter;
389
391}
392
393static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2])
394{
395 float point_local[2];
396
397 if (gizmo_window_project_2d(C, gz, blender::float2(blender::int2(mval)), 2, true, point_local) ==
398 false)
399 {
400 return -1;
401 }
402
403 /* The 'gz->scale_final' is already applied to the projection
404 * when #WM_GIZMO_DRAW_NO_SCALE isn't set. */
405 const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f;
406 if (len_squared_v2(point_local) < radius) {
407 return 0;
408 }
409
410 return -1;
411}
412
414{
415 MoveGizmo3D *move = (MoveGizmo3D *)gz;
417 WM_gizmo_target_property_float_get_array(gz, gz_prop, move->prop_co);
418 }
419 else {
420 zero_v3(move->prop_co);
421 }
422}
423
424static int gizmo_move_cursor_get(wmGizmo * /*gz*/)
425{
427}
428
429/* -------------------------------------------------------------------- */
434{
435 /* identifiers */
436 gzt->idname = "GIZMO_GT_move_3d";
437
438 /* api callbacks */
439 gzt->draw = gizmo_move_draw;
445 gzt->modal = gizmo_move_modal;
446 gzt->exit = gizmo_move_exit;
448
449 gzt->struct_size = sizeof(MoveGizmo3D);
450
451 /* rna */
452 static const EnumPropertyItem rna_enum_draw_style[] = {
453 {ED_GIZMO_MOVE_STYLE_RING_2D, "RING_2D", 0, "Ring", ""},
454 {ED_GIZMO_MOVE_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""},
455 {0, nullptr, 0, nullptr, nullptr},
456 };
457 static const EnumPropertyItem rna_enum_draw_options[] = {
458 {ED_GIZMO_MOVE_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
459 {ED_GIZMO_MOVE_DRAW_FLAG_FILL_SELECT, "FILL_SELECT", 0, "Use fill for selection test", ""},
460 {ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""},
461 {0, nullptr, 0, nullptr, nullptr},
462 };
463
465 gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_MOVE_STYLE_RING_2D, "Draw Style", "");
466 RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
467 RNA_def_boolean(gzt->srna, "use_snap", false, "Use Snap", "");
468
470}
471
476
477 /* 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:50
#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_DRAW_FLAG_FILL_SELECT
@ ED_GIZMO_MOVE_DRAW_FLAG_FILL
@ ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW
@ ED_GIZMO_MOVE_STYLE_CROSS_2D
@ ED_GIZMO_MOVE_STYLE_RING_2D
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:669
SnapObjectContext * ED_transform_snap_object_context_create(Scene *scene, int flag)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
eSnapMode ED_transform_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])
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
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(eGPUBuiltinShader 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(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:67
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
unsigned int U
Definition btGjkEpa3.h:78
draw_view in_light_buf[] 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])
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
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 int gizmo_move_modal(bContext *C, wmGizmo *gz, const wmEvent *event, eWM_GizmoFlagTweak tweak_flag)
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 int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
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
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)
wmGizmo gizmo
float prop_co[3]
SnapObjectContext * snap_context_v3d
struct MoveInteraction::@327 init
eWM_GizmoFlagTweak tweak_flag
float matrix_final[4][4]
struct MoveInteraction::@328 prev
float viewmat[4][4]
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
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 scale_final
PointerRNA * ptr
float matrix_space[4][4]
float line_width
eWM_GizmoFlag flag
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:51
@ MOUSEMOVE
void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
Definition wm_gizmo.cc:569
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 *))