Blender V5.0
view3d_cursor_snap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "DNA_object_types.h"
12
13#include "BLI_listbase.h"
14#include "BLI_math_geom.h"
15#include "BLI_math_matrix.h"
17
18#include "MEM_guardedalloc.h"
19
20#include "BKE_context.hh"
21#include "BKE_global.hh"
22#include "BKE_layer.hh"
23#include "BKE_main.hh"
24#include "BKE_object.hh"
25#include "BKE_scene.hh"
26#include "BKE_screen.hh"
27
28#include "GPU_immediate.hh"
29#include "GPU_matrix.hh"
30#include "GPU_state.hh"
31
32#include "ED_screen.hh"
33#include "ED_transform.hh"
35#include "ED_view3d.hh"
36
37#include "UI_resources.hh"
38
39#include "RNA_access.hh"
40
42
43#include "WM_api.hh"
44
45#define STATE_INTERN_GET(state) \
46\
47 (SnapStateIntern *)((char *)state - offsetof(SnapStateIntern, snap_state))
48
53
58
60 const Scene *scene;
62
64
65 /* Copy of the parameters of the last event state in order to detect updates. */
66 struct {
68 uint8_t modifier;
70
71#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
74#endif
75
77
79};
80
83 data.state_default.flag = V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL;
84 copy_v4_v4_uchar(data.state_default.target_color, blender::uchar4{255, 255, 255, 255});
85 copy_v4_v4_uchar(data.state_default.source_color, blender::uchar4{255, 255, 255, 128});
86 copy_v4_v4_uchar(data.state_default.color_box, blender::uchar4{255, 255, 255, 128});
87 copy_v3_fl(data.state_default.box_dimensions, 1.0f);
88 data.state_default.draw_point = true;
89 return data;
90}();
91
96static const float eps_view_align = 1e-2f;
97
101static void v3d_cursor_poject_surface_normal(const float normal[3],
102 const float obmat[4][4],
103 float r_mat[3][3])
104{
105 float mat[3][3];
106 copy_m3_m4(mat, obmat);
107 normalize_m3(mat);
108
109 float dot_best = fabsf(dot_v3v3(mat[0], normal));
110 int i_best = 0;
111 for (int i = 1; i < 3; i++) {
112 float dot_test = fabsf(dot_v3v3(mat[i], normal));
113 if (dot_test > dot_best) {
114 i_best = i;
115 dot_best = dot_test;
116 }
117 }
118 if (dot_v3v3(mat[i_best], normal) < 0.0f) {
119 negate_v3(mat[(i_best + 1) % 3]);
120 negate_v3(mat[(i_best + 2) % 3]);
121 }
122 copy_v3_v3(mat[i_best], normal);
123 orthogonalize_m3(mat, i_best);
124 normalize_m3(mat);
125
126 copy_v3_v3(r_mat[0], mat[(i_best + 1) % 3]);
127 copy_v3_v3(r_mat[1], mat[(i_best + 2) % 3]);
128 copy_v3_v3(r_mat[2], mat[i_best]);
129}
130
134static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3])
135{
136 float dot_best = -1.0f;
137 int axis_found = axis_align;
138 for (int i = 0; i < 3; i++) {
139 const float dot_test = fabsf(dot_v3v3(mat[i], v));
140 if (dot_test > dot_best) {
141 dot_best = dot_test;
142 axis_found = i;
143 }
144 }
145
146 if (axis_align != axis_found) {
147 float tmat[3][3];
148 copy_m3_m3(tmat, mat);
149 const int offset = mod_i(axis_found - axis_align, 3);
150 for (int i = 0; i < 3; i++) {
151 copy_v3_v3(mat[i], tmat[(i + offset) % 3]);
152 }
153 return true;
154 }
155 return false;
156}
157
158/* -------------------------------------------------------------------- */
161
162static void v3d_cursor_plane_draw_grid(const int resolution,
163 const float scale,
164 const float scale_fade,
165 const float matrix[4][4],
166 const int plane_axis,
167 const float color[4])
168{
169 BLI_assert(scale_fade <= scale);
170 const int resolution_min = resolution - 1;
171 float color_fade[4] = {UNPACK4(color)};
172 const float *center = matrix[3];
173
175 GPU_line_smooth(true);
176 GPU_line_width(1.0f);
177
179 const uint pos_id = GPU_vertformat_attr_add(
180 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
181 const uint col_id = GPU_vertformat_attr_add(
182 format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
183
185
186 const size_t coords_len = resolution * resolution;
187 float (*coords)[3] = static_cast<float (*)[3]>(
188 MEM_mallocN(sizeof(*coords) * coords_len, __func__));
189
190 const int axis_x = (plane_axis + 0) % 3;
191 const int axis_y = (plane_axis + 1) % 3;
192 const int axis_z = (plane_axis + 2) % 3;
193
194 int i;
195 const float resolution_div = 1.0f / float(resolution);
196 i = 0;
197 for (int x = 0; x < resolution; x++) {
198 const float x_fl = (x * resolution_div) - 0.5f;
199 for (int y = 0; y < resolution; y++) {
200 const float y_fl = (y * resolution_div) - 0.5f;
201 coords[i][axis_x] = 0.0f;
202 coords[i][axis_y] = x_fl * scale;
203 coords[i][axis_z] = y_fl * scale;
204 mul_m4_v3(matrix, coords[i]);
205 i += 1;
206 }
207 }
208 BLI_assert(i == int(coords_len));
209 immBeginAtMost(GPU_PRIM_LINES, coords_len * 4);
210 i = 0;
211 for (int x = 0; x < resolution_min; x++) {
212 for (int y = 0; y < resolution_min; y++) {
213
214/* Add #resolution_div to ensure we fade-out entirely. */
215#define FADE(v) \
216\
217 max_ff(0.0f, (1.0f - square_f(((len_v3v3(v, center) / scale_fade) + resolution_div) * 2.0f)))
218
219 const float *v0 = coords[(resolution * x) + y];
220 const float *v1 = coords[(resolution * (x + 1)) + y];
221 const float *v2 = coords[(resolution * x) + (y + 1)];
222
223 const float f0 = FADE(v0);
224 const float f1 = FADE(v1);
225 const float f2 = FADE(v2);
226
227 if (f0 > 0.0f || f1 > 0.0f) {
228 color_fade[3] = color[3] * f0;
229 immAttr4fv(col_id, color_fade);
230 immVertex3fv(pos_id, v0);
231 color_fade[3] = color[3] * f1;
232 immAttr4fv(col_id, color_fade);
233 immVertex3fv(pos_id, v1);
234 }
235 if (f0 > 0.0f || f2 > 0.0f) {
236 color_fade[3] = color[3] * f0;
237 immAttr4fv(col_id, color_fade);
238 immVertex3fv(pos_id, v0);
239
240 color_fade[3] = color[3] * f2;
241 immAttr4fv(col_id, color_fade);
242 immVertex3fv(pos_id, v2);
243 }
244
245#undef FADE
246
247 i++;
248 }
249 }
250
251 MEM_freeN(coords);
252
253 immEnd();
254
256
257 GPU_line_smooth(false);
259}
260
261static void v3d_cursor_plane_draw(const RegionView3D *rv3d,
262 const int plane_axis,
263 const float matrix[4][4])
264{
265 /* Draw */
266 float pixel_size;
267
268 if (rv3d->is_persp) {
269 float center[3];
270 negate_v3_v3(center, rv3d->ofs);
271 pixel_size = ED_view3d_pixel_size(rv3d, center);
272 }
273 else {
274 pixel_size = ED_view3d_pixel_size(rv3d, matrix[3]);
275 }
276
277 if (pixel_size > FLT_EPSILON) {
278
279 /* Arbitrary, 1.0 is a little too strong though. */
280 float color_alpha = 0.75f;
281 if (rv3d->is_persp) {
282 /* Scale down the alpha when this is drawn very small,
283 * since the add shader causes the small size to show too dense & bright. */
284 const float relative_pixel_scale = pixel_size / ED_view3d_pixel_size(rv3d, matrix[3]);
285 if (relative_pixel_scale < 1.0f) {
286 color_alpha *= max_ff(square_f(relative_pixel_scale), 0.3f);
287 }
288 }
289
290 {
291 /* Extra adjustment when it's near view-aligned as it seems overly bright. */
292 float view_vector[3];
293 ED_view3d_global_to_vector(rv3d, matrix[3], view_vector);
294 float view_dot = fabsf(dot_v3v3(matrix[plane_axis], view_vector));
295 color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot)));
296 }
297
298 const float scale_mod = U.gizmo_size * 2 * UI_SCALE_FAC / U.pixelsize;
299
300 float final_scale = (scale_mod * pixel_size);
301
302 const int lines_subdiv = 10;
303 int lines = lines_subdiv;
304
305 float final_scale_fade = final_scale;
306 final_scale = ceil_power_of_10(final_scale);
307
308 float fac = final_scale_fade / final_scale;
309
310 float color[4] = {1, 1, 1, color_alpha};
311 color[3] *= square_f(1.0f - fac);
312 if (color[3] > 0.0f) {
314 lines * lines_subdiv, final_scale, final_scale_fade, matrix, plane_axis, color);
315 }
316
317 color[3] = color_alpha;
318 /* When the grid is large, we only need the 2x lines in the middle. */
319 if (fac < 0.2f) {
320 lines = 1;
321 final_scale = final_scale_fade;
322 }
323 v3d_cursor_plane_draw_grid(lines, final_scale, final_scale_fade, matrix, plane_axis, color);
324 }
325}
326
327static void cursor_box_draw(const float dimensions[3], uchar color[4])
328{
330 const uint pos_id = GPU_vertformat_attr_add(
331 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
332
334 GPU_line_smooth(true);
335 GPU_line_width(1.0f);
336
338 immUniformColor4ubv(color);
339 imm_draw_cube_corners_3d(pos_id, blender::float3{0.0f, 0.0f, dimensions[2]}, dimensions, 0.15f);
341
342 GPU_line_smooth(false);
344}
345
347 uint attr_pos, const float loc[3], const float size, eSnapMode snap_type, const uchar color[4])
348{
349 if (snap_type == SCE_SNAP_TO_GRID) {
350 /* No drawing. */
351 return;
352 }
353
354 immUniformColor4ubv(color);
355
357
358 float model_view_new[4][4];
359 GPU_matrix_model_view_get(model_view_new);
360 translate_m4(model_view_new, UNPACK3(loc));
361 copy_v3_fl3(model_view_new[0], size, 0.0f, 0.0f);
362 copy_v3_fl3(model_view_new[1], 0.0f, size, 0.0f);
363 copy_v3_fl3(model_view_new[2], 0.0f, 0.0f, size);
364 GPU_matrix_set(model_view_new);
365
366 float size_b = 1.0f;
367 switch (snap_type) {
369 imm_draw_circle_wire_3d(attr_pos, 0.0f, 0.0f, 1.0f, 24);
370
372 immVertex3f(attr_pos, -size_b, -size_b, 0.0f);
373 immVertex3f(attr_pos, +size_b, +size_b, 0.0f);
374 immVertex3f(attr_pos, -size_b, +size_b, 0.0f);
375 immVertex3f(attr_pos, +size_b, -size_b, 0.0f);
376 immEnd();
377 break;
380 immVertex3f(attr_pos, -size_b, -size_b, 0.0f);
381 immVertex3f(attr_pos, -size_b, +size_b, 0.0f);
382 immVertex3f(attr_pos, +size_b, +size_b, 0.0f);
383 immVertex3f(attr_pos, +size_b, -size_b, 0.0f);
384 immEnd();
385 break;
388 immVertex3f(attr_pos, -size_b, -size_b, 0.0f);
389 immVertex3f(attr_pos, 0.0f, 0.866f * size_b, 0.0f);
390 immVertex3f(attr_pos, +size_b, -size_b, 0.0f);
391 immEnd();
392 break;
395 immVertex3f(attr_pos, -size_b, +size_b, 0.0f);
396 immVertex3f(attr_pos, -size_b, -size_b, 0.0f);
397 immVertex3f(attr_pos, +size_b, -size_b, 0.0f);
398 immEnd();
399
401 immVertex3f(attr_pos, -size_b, 0.0f, 0.0f);
402 immVertex3f(attr_pos, 0.0f, 0.0f, 0.0f);
403 immVertex3f(attr_pos, 0.0f, -size_b, 0.0f);
404 immEnd();
405 break;
406 case SCE_SNAP_TO_EDGE:
408 immVertex3f(attr_pos, -size_b, -size_b, 0.0f);
409 immVertex3f(attr_pos, +size_b, +size_b, 0.0f);
410 immVertex3f(attr_pos, -size_b, +size_b, 0.0f);
411 immVertex3f(attr_pos, +size_b, -size_b, 0.0f);
412 immEnd();
413 break;
414 case SCE_SNAP_TO_FACE:
415 default:
416 imm_draw_circle_wire_3d(attr_pos, 0.0f, 0.0f, 1.0f, 24);
417 break;
418 }
419
421}
422
424 const float source_loc[3],
425 const float target_loc[3],
426 const eSnapMode source_type,
427 const eSnapMode target_type,
428 const uchar source_color[4],
429 const uchar target_color[4])
430{
431 if (!source_loc && !target_loc) {
432 return;
433 }
434
435 /* The size of the symbol is larger than the vertex size.
436 * This prevents overlaps. */
437 float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
439 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
440
442 GPU_line_smooth(true);
443 GPU_line_width(1.5f);
445
446 if (target_loc) {
448 target_loc,
449 radius * ED_view3d_pixel_size(rv3d, target_loc),
450 target_type,
451 target_color);
452 }
453
454 if (source_loc) {
456 source_loc,
457 radius * ED_view3d_pixel_size(rv3d, source_loc),
458 source_type,
459 source_color);
460
461 if (target_loc && (target_type & SCE_SNAP_TO_EDGE_PERPENDICULAR)) {
462 /* Dashed line. */
464
466 float viewport_size[4];
467 GPU_viewport_size_get_f(viewport_size);
468 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
469 immUniform1f("dash_width", 6.0f * U.pixelsize);
470 immUniform1f("udash_factor", 1.0f / 4.0f);
471 immUniformColor4ubv(source_color);
472
474 immVertex3fv(pos, source_loc);
475 immVertex3fv(pos, target_loc);
476 immEnd();
477 }
478 }
479
480 GPU_line_smooth(false);
483}
484
486
487/* -------------------------------------------------------------------- */
490
491/* Checks if the current event is different from the one captured in the last update. */
494 const blender::int2 &mval,
495 uint8_t event_modifier)
496{
497 if (mval != data_intern->last_eventstate.mval) {
498 return true;
499 }
500
501#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
502 if (!(state && (state->flag & V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE))) {
503 if (event_modifier != data_intern->last_eventstate.modifier) {
504 return true;
505 }
506 }
507#endif
508
509 return false;
510}
511
512/* Copies the current eventstate. */
514 const blender::int2 &mval)
515{
516 cursor_snap->last_eventstate.mval = mval;
517}
518
519#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
521 uint8_t event_modifier)
522{
523 data_intern->last_eventstate.modifier = event_modifier;
524}
525
526static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, uint8_t event_modifier)
527{
528 if (event_modifier == data_intern->last_eventstate.modifier) {
529 /* Nothing has changed. */
530 return data_intern->snap_data.is_snap_invert;
531 }
532
533 /* Save new eventstate. */
534 data_intern->last_eventstate.modifier = event_modifier;
535
536 const int snap_on = data_intern->snap_on;
537
538 const wmWindowManager *wm = static_cast<wmWindowManager *>(G.main->wm.first);
539 wmKeyMap *keymap = WM_keymap_active(wm, data_intern->keymap);
540 LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &keymap->items) {
541 if (kmi->flag & KMI_INACTIVE) {
542 continue;
543 }
544
545 if (kmi->propvalue == snap_on) {
546 if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && (event_modifier & KM_CTRL)) ||
547 (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && (event_modifier & KM_SHIFT)) ||
548 (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && (event_modifier & KM_ALT)) ||
549 ((kmi->type == EVT_OSKEY) && (event_modifier & KM_OSKEY)))
550 {
551 return true;
552 }
553 }
554 }
555 return false;
556}
557#endif
558
560
561/* -------------------------------------------------------------------- */
564
566{
567 if (tool_settings->snap_mode_tools == SCE_SNAP_TO_NONE) {
568 /* Use the snap modes defined in the scene instead. */
569 eSnapMode snap_mode = eSnapMode(tool_settings->snap_mode);
570 if ((snap_mode & SCE_SNAP_TO_INCREMENT) && (tool_settings->snap_flag & SCE_SNAP_ABS_GRID)) {
571 /* Convert snap to increment to snap to grid. */
572 snap_mode |= SCE_SNAP_TO_GRID;
573 }
574 return snap_mode;
575 }
576 return eSnapMode(tool_settings->snap_mode_tools);
577}
578
580{
581 SnapCursorDataIntern *data_intern = &g_data_intern;
582 if (data_intern->snap_context_v3d && (data_intern->scene != scene)) {
584 data_intern->snap_context_v3d = nullptr;
585 }
586 if (data_intern->snap_context_v3d == nullptr) {
588 data_intern->scene = scene;
589 }
590}
591
593{
594 /* If any of the states require the plane, calculate the `plane_omat`. */
596 if (state->snap_state.draw_plane || state->snap_state.draw_box) {
597 return true;
598 }
599 }
600 return false;
601}
602
604 const bContext *C,
605 Depsgraph *depsgraph,
606 Scene *scene,
607 const ARegion *region,
608 View3D *v3d,
609 const blender::int2 &mval,
610 uint8_t event_modifier)
611{
612 SnapCursorDataIntern *data_intern = &g_data_intern;
613 V3DSnapCursorData *snap_data = &data_intern->snap_data;
614 ToolSettings *tool_settings = scene->toolsettings;
615
616 eSnapMode snap_elements = v3d_cursor_snap_elements(tool_settings);
617 const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
618
619 snap_data->is_enabled = true;
621#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
622 snap_data->is_snap_invert = v3d_cursor_is_snap_invert(data_intern, event_modifier);
623#endif
624
625 if (snap_data->is_snap_invert != ((tool_settings->snap_flag & SCE_SNAP) == 0)) {
626 snap_data->is_enabled = false;
627 if (!calc_plane_omat) {
628 snap_data->type_target = SCE_SNAP_TO_NONE;
629 return;
630 }
631 snap_elements = SCE_SNAP_TO_NONE;
632 }
633 }
634
635 const bool use_surface_nor = tool_settings->plane_orient == V3D_PLACE_ORIENT_SURFACE;
636 const bool use_surface_co = snap_data->is_enabled ||
637 tool_settings->plane_depth == V3D_PLACE_DEPTH_SURFACE;
638
639 float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
640 eSnapMode snap_elem = SCE_SNAP_TO_NONE;
641 int snap_elem_index[3] = {-1, -1, -1};
642 int index = -1;
643
644 const blender::float2 mval_fl = blender::float2(mval);
645 zero_v3(no);
646 zero_v3(face_nor);
647 unit_m3(omat);
648
649 if (use_surface_nor || use_surface_co) {
651
652 data_intern->snap_elem_hidden = SCE_SNAP_TO_NONE;
653 if (calc_plane_omat && !(snap_elements & SCE_SNAP_TO_FACE)) {
654 data_intern->snap_elem_hidden = SCE_SNAP_TO_FACE;
655 snap_elements |= SCE_SNAP_TO_FACE;
656 }
657
658 if (snap_elements & (SCE_SNAP_TO_GEOM | SCE_SNAP_TO_GRID)) {
659 float prev_co[3] = {0.0f};
660 if (state->prevpoint) {
661 copy_v3_v3(prev_co, state->prevpoint);
662 }
663 else {
664 snap_elements &= ~SCE_SNAP_TO_EDGE_PERPENDICULAR;
665 }
666
673
674 float dist_px = 12.0f * U.pixelsize;
675
677 params.snap_target_select = SCE_SNAP_TARGET_ALL;
678 params.edit_mode_type = edit_mode_type;
679 params.occlusion_test = (state->flag & V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE) ?
683 data_intern->snap_context_v3d,
684 depsgraph,
685 region,
686 v3d,
687 snap_elements,
688 &params,
689 nullptr,
690 mval_fl,
691 prev_co,
692 &dist_px,
693 co,
694 no,
695 &index,
696 nullptr,
697 obmat,
698 face_nor);
699 if ((snap_elem & data_intern->snap_elem_hidden) && (snap_elements & SCE_SNAP_TO_GRID)) {
700 BLI_assert(snap_elem != SCE_SNAP_TO_GRID);
703 data_intern->snap_context_v3d,
704 depsgraph,
705 region,
706 v3d,
708 &params,
709 co,
710 mval_fl,
711 prev_co,
712 &dist_px,
713 co,
714 no);
715 }
716 }
717 }
718#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
719 else {
720 v3d_cursor_eventstate_save_modifier(data_intern, event_modifier);
721 }
722#endif
723
724 if (calc_plane_omat) {
725 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
726 bool orient_surface = use_surface_nor && (snap_elem != SCE_SNAP_TO_NONE);
727 if (orient_surface) {
728 copy_m3_m4(omat, obmat);
729 }
730 else {
731 ViewLayer *view_layer = CTX_data_view_layer(C);
734 const int orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
735 const int pivot_point = scene->toolsettings->transform_pivot_point;
737 scene, view_layer, v3d, rv3d, ob, nullptr, orient_index, pivot_point, omat);
738
739 if (tool_settings->use_plane_axis_auto) {
740 mat3_align_axis_to_v3(omat, tool_settings->plane_axis, rv3d->viewinv[2]);
741 }
742 }
743
744 /* Non-orthogonal matrices cause the preview and final result not to match.
745 *
746 * While making orthogonal doesn't always work well (especially with gimbal orientation for
747 * e.g.) it's a corner case, without better alternatives as objects don't support shear. */
748 orthogonalize_m3(omat, tool_settings->plane_axis);
749
750 if (orient_surface) {
751 if (!is_zero_v3(face_nor)) {
752 /* Negate the face normal according to the view. */
753 float ray_dir[3];
754 if (rv3d->is_persp) {
755 BLI_assert_msg(snap_elem != SCE_SNAP_TO_NONE,
756 "Use of variable `co` without it being computed");
757
758 sub_v3_v3v3(ray_dir, co, rv3d->viewinv[3]); /* No need to normalize. */
759 }
760 else {
761 negate_v3_v3(ray_dir, rv3d->viewinv[2]);
762 }
763
764 if (dot_v3v3(ray_dir, face_nor) >= 0.0f) {
765 negate_v3(face_nor);
766 }
767 }
768 else if (!is_zero_v3(no)) {
769 copy_v3_v3(face_nor, no);
770 }
771 else {
772 face_nor[tool_settings->plane_axis] = 1.0f;
773 }
774 v3d_cursor_poject_surface_normal(face_nor, obmat, omat);
775 }
776 }
777
778 if (!use_surface_co) {
779 snap_elem = SCE_SNAP_TO_NONE;
780 }
781
782 float *co_depth = (snap_elem != SCE_SNAP_TO_NONE) ? co : scene->cursor.location;
783 snap_elem &= ~data_intern->snap_elem_hidden;
784 if (snap_elem == SCE_SNAP_TO_NONE) {
785 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
786 const float *plane_normal = omat[tool_settings->plane_axis];
787 bool do_plane_isect = (tool_settings->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
788 (rv3d->is_persp ||
789 (fabsf(dot_v3v3(plane_normal, rv3d->viewinv[2])) > eps_view_align));
790
791 if (do_plane_isect) {
792 float plane[4];
793 plane_from_point_normal_v3(plane, co_depth, plane_normal);
794 do_plane_isect = ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, rv3d->is_persp, co);
795 }
796
797 if (!do_plane_isect) {
798 ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, co);
799 }
800 }
801 else if (snap_elem & SCE_SNAP_TO_VERTEX) {
802 snap_elem_index[0] = index;
803 }
804 else if (snap_elem &
806 {
807 snap_elem_index[1] = index;
808 }
809 else if (snap_elem == SCE_SNAP_TO_FACE) {
810 snap_elem_index[2] = index;
811 }
812
813 snap_data->type_target = snap_elem;
814 copy_v3_v3(snap_data->loc, co);
815 copy_v3_v3(snap_data->nor, no);
816 copy_m4_m4(snap_data->obmat, obmat);
817 copy_v3_v3_int(snap_data->elem_index, snap_elem_index);
818
819 copy_m3_m3(snap_data->plane_omat, omat);
820
821 v3d_cursor_eventstate_save_xy(data_intern, mval);
822}
823
825
826/* -------------------------------------------------------------------- */
829
831{
832 if (G.moving) {
833 return false;
834 }
835
836 ScrArea *area = CTX_wm_area(C);
837 if (area->spacetype != SPACE_VIEW3D) {
838 return false;
839 }
840
841 ARegion *region = CTX_wm_region(C);
842 if (region->regiontype != RGN_TYPE_WINDOW) {
843 if (!region->overlap) {
844 return false;
845 }
846 /* Sometimes the cursor may be on an invisible part of an overlapping region. */
847 wmWindow *win = CTX_wm_window(C);
848 const wmEvent *event = win->eventstate;
849 if (ED_region_overlap_isect_xy(region, event->xy)) {
850 return false;
851 }
852 /* Find the visible region under the cursor.
853 * TODO(Germano): Shouldn't this be the region in context? */
855 }
856
857 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
858 if (rv3d->rflag & RV3D_NAVIGATING) {
859 /* Don't draw the cursor while navigating. It can be distracting. */
860 return false;
861 };
862
863 /* Call this callback last and don't reuse the `state` as the caller can free the cursor. */
865 if (state->poll && !state->poll(region, state->poll_data)) {
866 return false;
867 }
868
869 return true;
870}
871
873 const blender::int2 &xy,
874 const blender::float2 & /*tilt*/,
875 void * /*customdata*/)
876{
877 using namespace blender;
878 ScrArea *area = CTX_wm_area(C);
880 if (region->alignment == RGN_ALIGN_QSPLIT) {
881 /* Quad-View. */
883 if (region == nullptr) {
884 return;
885 }
886 }
887
888 const int2 mval(xy.x - region->winrct.xmin, xy.y - region->winrct.ymin);
889
890 SnapCursorDataIntern *data_intern = &g_data_intern;
892 V3DSnapCursorData *snap_data = &data_intern->snap_data;
895
896 const wmWindow *win = CTX_wm_window(C);
897 const wmEvent *event = win->eventstate;
898 if (event && v3d_cursor_eventstate_has_changed(data_intern, state, mval, event->modifier)) {
899 View3D *v3d = CTX_wm_view3d(C);
900 v3d_cursor_snap_update(state, C, depsgraph, scene, region, v3d, mval, event->modifier);
901 }
902
903 const bool draw_plane = state->draw_plane || state->draw_box;
904 if (snap_data->type_target == SCE_SNAP_TO_NONE && !draw_plane) {
905 return;
906 }
907
908 /* Setup viewport & matrix. */
909 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
910 wmViewport(&region->winrct);
912 GPU_matrix_set(rv3d->viewmat);
913
914 float matrix[4][4];
915 if (draw_plane) {
916 copy_m4_m3(matrix, snap_data->plane_omat);
917 copy_v3_v3(matrix[3], snap_data->loc);
918
919 v3d_cursor_plane_draw(rv3d, scene->toolsettings->plane_axis, matrix);
920 }
921
922 if (snap_data->type_target != SCE_SNAP_TO_NONE && (state->draw_point || state->draw_box)) {
923 const float *source_loc = (snap_data->type_target & SCE_SNAP_TO_EDGE_PERPENDICULAR) ?
924 state->prevpoint :
925 nullptr;
926
928 source_loc,
929 snap_data->loc,
930 snap_data->type_source,
931 snap_data->type_target,
932 state->source_color,
933 state->target_color);
934 }
935
936 if (state->draw_box) {
937 GPU_matrix_mul(matrix);
938 cursor_box_draw(state->box_dimensions, state->color_box);
939 }
940
941 /* Restore matrix. */
942 wmWindowViewport(win);
943}
944
946
948{
949 SnapCursorDataIntern *data_intern = &g_data_intern;
950 if (BLI_listbase_is_empty(&data_intern->state_intern)) {
951 return &g_data_intern.state_default;
952 }
953 return &((SnapStateIntern *)data_intern->state_intern.last)->snap_state;
954}
955
957{
958 if (state == &g_data_intern.state_default) {
960 return;
961 }
962
963 SnapStateIntern *state_intern = STATE_INTERN_GET(state);
964 if (state_intern == (SnapStateIntern *)g_data_intern.state_intern.last) {
965 return;
966 }
967
968 if (!BLI_remlink_safe(&g_data_intern.state_intern, state_intern)) {
970 return;
971 }
972
973 BLI_addtail(&g_data_intern.state_intern, state_intern);
974}
975
977{
978 SnapCursorDataIntern *data_intern = &g_data_intern;
979
980 if (!data_intern->handle) {
981 if (!data_intern->is_initiated) {
982 /* Only initiate intern data once.
983 * TODO: ED_view3d_cursor_snap_init */
984
985#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
986 wmKeyConfig *keyconf = ((wmWindowManager *)G.main->wm.first)->runtime->defaultconf;
987
988 data_intern->keymap = WM_modalkeymap_find(keyconf, "Generic Gizmo Tweak Modal Map");
990 static_cast<const EnumPropertyItem *>(data_intern->keymap->modal_items),
991 "SNAP_ON",
992 &data_intern->snap_on);
993#endif
994 data_intern->is_initiated = true;
995 }
996
999 data_intern->handle = pc;
1000 }
1001}
1002
1004{
1005 SnapCursorDataIntern *data_intern = &g_data_intern;
1006 if (data_intern->handle) {
1007 if (G_MAIN->wm.first) {
1008 WM_paint_cursor_end(data_intern->handle);
1009 }
1010 data_intern->handle = nullptr;
1011 }
1012 if (data_intern->snap_context_v3d) {
1014 data_intern->snap_context_v3d = nullptr;
1015 }
1016}
1017
1019{
1020 g_data_intern.state_default = *state;
1021
1022 /* These values are temporarily set by the tool.
1023 * They are not convenient as default values.
1024 * So reset to null. */
1025 g_data_intern.state_default.prevpoint = nullptr;
1026 g_data_intern.state_default.draw_plane = false;
1027 g_data_intern.state_default.draw_box = false;
1028 g_data_intern.state_default.poll = nullptr;
1029 g_data_intern.state_default.poll_data = nullptr;
1030}
1031
1033{
1034 SnapCursorDataIntern *data_intern = &g_data_intern;
1035 if (!data_intern->handle) {
1037 }
1038
1039 SnapStateIntern *state_intern = static_cast<SnapStateIntern *>(
1040 MEM_mallocN(sizeof(*state_intern), __func__));
1041 state_intern->snap_state = g_data_intern.state_default;
1042 BLI_addtail(&g_data_intern.state_intern, state_intern);
1043
1044 return &state_intern->snap_state;
1045}
1046
1048{
1049 SnapCursorDataIntern *data_intern = &g_data_intern;
1050 if (BLI_listbase_is_empty(&data_intern->state_intern)) {
1051 return;
1052 }
1053
1054 SnapStateIntern *state_intern = STATE_INTERN_GET(state);
1055 BLI_remlink(&data_intern->state_intern, state_intern);
1056 MEM_freeN(state_intern);
1057 if (BLI_listbase_is_empty(&data_intern->state_intern)) {
1059 }
1060}
1061
1063 const float prev_point[3])
1064{
1065 SnapCursorDataIntern *data_intern = &g_data_intern;
1066 if (!state) {
1068 }
1069 if (prev_point) {
1070 copy_v3_v3(data_intern->prevpoint_stack, prev_point);
1071 state->prevpoint = data_intern->prevpoint_stack;
1072 }
1073 else {
1074 state->prevpoint = nullptr;
1075 }
1076}
1077
1079 const bContext *C,
1080 const ARegion *region,
1081 const blender::int2 &mval)
1082{
1083 SnapCursorDataIntern *data_intern = &g_data_intern;
1084 const wmEvent *event = CTX_wm_window(C)->eventstate;
1085 if (event && v3d_cursor_eventstate_has_changed(data_intern, state, mval, event->modifier)) {
1088 View3D *v3d = CTX_wm_view3d(C);
1089
1090 if (!state) {
1092 }
1093 v3d_cursor_snap_update(state, C, depsgraph, scene, region, v3d, mval, event->modifier);
1094 }
1095}
1096
1098{
1099 SnapCursorDataIntern *data_intern = &g_data_intern;
1100 return &data_intern->snap_data;
1101}
1102
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
#define G_MAIN
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
int BKE_scene_orientation_get_index(Scene *scene, int slot_index)
Definition scene.cc:2439
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:875
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
bool BLI_remlink_safe(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:154
MINLINE float max_ff(float a, float b)
MINLINE int mod_i(int i, int n)
MINLINE float square_f(float a)
float ceil_power_of_10(float f)
Definition math_base.cc:74
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void unit_m3(float m[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void orthogonalize_m3(float R[3][3], int axis)
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void normalize_m3(float R[3][3]) ATTR_NONNULL()
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
unsigned char uchar
unsigned int uint
#define UNPACK4(a)
#define UNPACK3(a)
#define ELEM(...)
Scene * DEG_get_input_scene(const Depsgraph *graph)
Object is a sort of wrapper for general info.
@ SCE_ORIENT_DEFAULT
#define SCE_SNAP_TO_GEOM
#define SCE_SNAP_TO_VERTEX
@ SCE_SNAP
@ SCE_SNAP_ABS_GRID
@ SCE_SNAP_TARGET_ALL
@ SCE_SNAP_TO_EDGE
@ SCE_SNAP_TO_FACE
@ SCE_SNAP_TO_EDGE_ENDPOINT
@ SCE_SNAP_TO_INCREMENT
@ SCE_SNAP_TO_GRID
@ SCE_SNAP_TO_EDGE_MIDPOINT
@ SCE_SNAP_TO_EDGE_PERPENDICULAR
@ SCE_SNAP_TO_POINT
@ SCE_SNAP_TO_NONE
@ RGN_ALIGN_QSPLIT
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
#define UI_SCALE_FAC
@ V3D_PLACE_ORIENT_SURFACE
@ RV3D_NAVIGATING
@ V3D_PLACE_DEPTH_CURSOR_VIEW
@ V3D_PLACE_DEPTH_SURFACE
bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2])
Definition area_query.cc:50
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float r_out[3])
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
@ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL
Definition ED_view3d.hh:333
@ V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE
Definition ED_view3d.hh:330
@ V3D_SNAPCURSOR_OCCLUSION_ALWAYS_TRUE
Definition ED_view3d.hh:331
@ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE
Definition ED_view3d.hh:334
bool ED_view3d_win_to_3d_on_plane(const ARegion *region, const float plane[4], const float mval[2], bool do_clip, float r_out[3])
void immUniformColor4ubv(const unsigned char rgba[4])
void immEnd()
void immUnbindProgram()
void immAttr4fv(uint attr_id, const float data[4])
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniform2f(const char *name, float x, float y)
void immVertex3f(uint attr_id, float x, float y, float z)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immVertex3fv(uint attr_id, const float data[3])
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_cube_corners_3d(uint pos, const float center[3], const float aspect[3], float factor)
#define GPU_matrix_model_view_get(x)
#define GPU_matrix_set(x)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
#define GPU_matrix_projection_set(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINE_LOOP
@ GPU_PRIM_LINES
@ GPU_PRIM_LINE_STRIP
@ GPU_SHADER_3D_SMOOTH_COLOR
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_line_width(float width)
Definition gpu_state.cc:166
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
@ GPU_BLEND_ADDITIVE
Definition GPU_state.hh:89
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.
#define C
Definition RandGen.cpp:29
@ TH_VERTEX_SIZE
float UI_GetThemeValuef(int colorid)
@ KM_CTRL
Definition WM_types.hh:279
@ KM_ALT
Definition WM_types.hh:280
@ KM_OSKEY
Definition WM_types.hh:282
@ KM_SHIFT
Definition WM_types.hh:278
#define U
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
nullptr float
uint pos
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong state[N]
#define G(x, y, z)
eSnapMode snap_object_project_view3d_ex(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], int *r_index, const Object **r_ob, float r_obmat[4][4], float r_face_nor[3])
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)
short calc_orientation_from_type_ex(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, const RegionView3D *rv3d, Object *ob, Object *obedit, short orientation_index, int pivot_point, float r_mat[3][3])
blender::VecBase< uint8_t, 4 > uchar4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static CursorSnapshot cursor_snap
#define fabsf
bool RNA_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value)
void * regiondata
void * last
float viewmat[4][4]
float viewinv[4][4]
float winmat[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
V3DSnapCursorState state_default
blender::ed::transform::SnapObjectContext * snap_context_v3d
V3DSnapCursorData snap_data
struct SnapCursorDataIntern::@371036144025202176171137130161162244366300312012 last_eventstate
SnapStateIntern * next
SnapStateIntern * prev
V3DSnapCursorState snap_state
eSnapMode type_target
Definition ED_view3d.hh:340
eSnapMode type_source
Definition ED_view3d.hh:339
float plane_omat[3][3]
Definition ED_view3d.hh:345
float obmat[4][4]
Definition ED_view3d.hh:343
int ymin
int xmin
const void * modal_items
struct wmEvent * eventstate
i
Definition text_draw.cc:230
V3DSnapCursorState * ED_view3d_cursor_snap_state_create()
static bool v3d_cursor_eventstate_has_changed(SnapCursorDataIntern *data_intern, V3DSnapCursorState *state, const blender::int2 &mval, uint8_t event_modifier)
void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
#define FADE(v)
static void cursor_point_draw(uint attr_pos, const float loc[3], const float size, eSnapMode snap_type, const uchar color[4])
static const float eps_view_align
V3DSnapCursorState * ED_view3d_cursor_snap_state_active_get()
static void cursor_box_draw(const float dimensions[3], uchar color[4])
void ED_view3d_cursor_snap_state_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3])
static void v3d_cursor_poject_surface_normal(const float normal[3], const float obmat[4][4], float r_mat[3][3])
#define STATE_INTERN_GET(state)
static void v3d_cursor_plane_draw(const RegionView3D *rv3d, const int plane_axis, const float matrix[4][4])
static void v3d_cursor_snap_activate()
static eSnapMode v3d_cursor_snap_elements(ToolSettings *tool_settings)
static SnapCursorDataIntern g_data_intern
static bool mat3_align_axis_to_v3(float mat[3][3], const int axis_align, const float v[3])
static bool v3d_cursor_snap_calc_plane()
static bool v3d_cursor_snap_poll_fn(bContext *C)
static void v3d_cursor_snap_context_ensure(Scene *scene)
void ED_view3d_cursor_snap_state_free(V3DSnapCursorState *state)
static void v3d_cursor_eventstate_save_modifier(SnapCursorDataIntern *data_intern, uint8_t event_modifier)
static void v3d_cursor_snap_free()
void ED_view3d_cursor_snap_state_active_set(V3DSnapCursorState *state)
void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d, const float source_loc[3], const float target_loc[3], const eSnapMode source_type, const eSnapMode target_type, const uchar source_color[4], const uchar target_color[4])
static void v3d_cursor_snap_draw_fn(bContext *C, const blender::int2 &xy, const blender::float2 &, void *)
static void v3d_cursor_eventstate_save_xy(SnapCursorDataIntern *cursor_snap, const blender::int2 &mval)
static void v3d_cursor_plane_draw_grid(const int resolution, const float scale, const float scale_fade, const float matrix[4][4], const int plane_axis, const float color[4])
static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, uint8_t event_modifier)
static void v3d_cursor_snap_update(V3DSnapCursorState *state, const bContext *C, Depsgraph *depsgraph, Scene *scene, const ARegion *region, View3D *v3d, const blender::int2 &mval, uint8_t event_modifier)
V3DSnapCursorData * ED_view3d_cursor_snap_data_get()
void ED_view3d_cursor_snap_data_update(V3DSnapCursorState *state, const bContext *C, const ARegion *region, const blender::int2 &mval)
blender::ed::transform::SnapObjectContext * ED_view3d_cursor_snap_context_ensure(Scene *scene)
int xy[2]
Definition wm_draw.cc:178
@ EVT_RIGHTCTRLKEY
@ EVT_OSKEY
@ EVT_LEFTCTRLKEY
@ EVT_RIGHTALTKEY
@ EVT_LEFTALTKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:959
bool WM_paint_cursor_end(wmPaintCursor *handle)
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
void wmViewport(const rcti *winrct)
void wmWindowViewport(const wmWindow *win)