Changeset View
Standalone View
source/blender/editors/space_view3d/view3d_placement.c
| Show All 24 Lines | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_collection_types.h" | #include "DNA_collection_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_vfont_types.h" | #include "DNA_vfont_types.h" | ||||
| #include "BLI_listbase.h" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_object.h" | |||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "RNA_enum_types.h" | #include "RNA_enum_types.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_toolsystem.h" | #include "WM_toolsystem.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| Show All 12 Lines | |||||
| #include "GPU_immediate.h" | #include "GPU_immediate.h" | ||||
| #include "GPU_matrix.h" | #include "GPU_matrix.h" | ||||
| #include "GPU_state.h" | #include "GPU_state.h" | ||||
| #include "view3d_intern.h" | #include "view3d_intern.h" | ||||
| static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; | static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; | ||||
| static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup); | |||||
| static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw); | static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw); | ||||
| /** | /** | ||||
| * Dot products below this will be considered view aligned. | * Dot products below this will be considered view aligned. | ||||
| * In this case we can't usefully project the mouse cursor onto the plane, | * In this case we can't usefully project the mouse cursor onto the plane, | ||||
| * so use a fall-back plane instead. | * so use a fall-back plane instead. | ||||
| */ | */ | ||||
| static const float eps_view_align = 1e-2f; | static const float eps_view_align = 1e-2f; | ||||
| ▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region) | static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region) | ||||
| { | { | ||||
| wmGizmoMap *gzmap = region->gizmo_map; | wmGizmoMap *gzmap = region->gizmo_map; | ||||
| return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL; | return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL; | ||||
| } | } | ||||
| static wmGizmo *idp_snap_gizmo_from_region(ARegion *region) | |||||
| { | |||||
| /* Assign snap gizmo which is may be used as part of the tool. */ | |||||
| wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region); | |||||
| if ((gzgroup == NULL) || (gzgroup->gizmos.first == NULL)) { | |||||
| return NULL; | |||||
| } | |||||
| return gzgroup->gizmos.first; | |||||
| } | |||||
| static void idp_paintcursor_from_gizmo_visible_set(wmGizmo *gz, bool visible) | |||||
| { | |||||
| /* Can be NULL when gizmos are disabled. */ | |||||
| if (gz->parent_gzgroup->customdata != NULL) { | |||||
| preview_plane_cursor_visible_set(gz->parent_gzgroup, visible); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Calculate 3D view incremental (grid) snapping. | * Calculate 3D view incremental (grid) snapping. | ||||
| * | * | ||||
| * \note This could be moved to a public function. | * \note This could be moved to a public function. | ||||
| */ | */ | ||||
| static bool idp_snap_calc_incremental( | static bool idp_snap_calc_incremental( | ||||
| Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3]) | Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3]) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | static void draw_line_loop(const float coords[][3], int coords_len, const float color[4]) | ||||
| GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO); | GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO); | ||||
| GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | ||||
| GPU_batch_uniform_4fv(batch, "color", color); | GPU_batch_uniform_4fv(batch, "color", color); | ||||
| float viewport[4]; | float viewport[4]; | ||||
| GPU_viewport_size_get_f(viewport); | GPU_viewport_size_get_f(viewport); | ||||
| GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | ||||
| GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); | GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get()); | ||||
Severin: This wasn't respecting the line width set with `GPU_line_width()`. | |||||
| GPU_batch_draw(batch); | GPU_batch_draw(batch); | ||||
| GPU_batch_discard(batch); | GPU_batch_discard(batch); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| } | } | ||||
| static void draw_line_pairs(const float coords_a[][3], | static void draw_line_pairs(const float coords_a[][3], | ||||
| Show All 16 Lines | static void draw_line_pairs(const float coords_a[][3], | ||||
| GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); | GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); | ||||
| GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | ||||
| GPU_batch_uniform_4fv(batch, "color", color); | GPU_batch_uniform_4fv(batch, "color", color); | ||||
| float viewport[4]; | float viewport[4]; | ||||
| GPU_viewport_size_get_f(viewport); | GPU_viewport_size_get_f(viewport); | ||||
| GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | ||||
| GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); | GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get()); | ||||
| GPU_batch_draw(batch); | GPU_batch_draw(batch); | ||||
| GPU_batch_discard(batch); | GPU_batch_discard(batch); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| } | } | ||||
| static void draw_line_bounds(const BoundBox *bounds, const float color[4]) | static void draw_line_bounds(const BoundBox *bounds, const float color[4]) | ||||
| Show All 31 Lines | static void draw_line_bounds(const BoundBox *bounds, const float color[4]) | ||||
| GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); | GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); | ||||
| GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); | ||||
| GPU_batch_uniform_4fv(batch, "color", color); | GPU_batch_uniform_4fv(batch, "color", color); | ||||
| float viewport[4]; | float viewport[4]; | ||||
| GPU_viewport_size_get_f(viewport); | GPU_viewport_size_get_f(viewport); | ||||
| GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); | ||||
| GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); | GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get()); | ||||
| GPU_batch_draw(batch); | GPU_batch_draw(batch); | ||||
| GPU_batch_discard(batch); | GPU_batch_discard(batch); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| } | } | ||||
| static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds) | static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds) | ||||
| ▲ Show 20 Lines • Show All 455 Lines • ▼ Show 20 Lines | static void view3d_interactive_add_calc_plane(bContext *C, | ||||
| if (snap_context_free) { | if (snap_context_free) { | ||||
| ED_transform_snap_object_context_destroy(snap_context); | ED_transform_snap_object_context_destroy(snap_context); | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Public Placement Plane Functionality | |||||
| * \{ */ | |||||
| void ED_view3d_placement_plane_calc(bContext *C, | |||||
| const int mval[2], | |||||
| const int plane_axis, | |||||
| float r_co_src[3], | |||||
| float r_mat_orient[3][3]) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ARegion *region = CTX_wm_region(C); | |||||
| View3D *v3d = CTX_wm_view3d(C); | |||||
| /* TODO what if there is no snap gizmo? */ | |||||
| wmGizmo *snap_gizmo = idp_snap_gizmo_from_region(region); | |||||
SeverinAuthorUnsubmitted Done Inline Actionsview3d_interactive_add_calc_plane() actually seems to handle that case just fine, so can just remove the TODO comment I think. Severin: `view3d_interactive_add_calc_plane()` actually seems to handle that case just fine, so can just… | |||||
| const float mval_fl[] = {mval[0], mval[1]}; | |||||
| /* TODO Options here should be input parameters. */ | |||||
| view3d_interactive_add_calc_plane(C, | |||||
| scene, | |||||
| v3d, | |||||
| region, | |||||
| mval_fl, | |||||
| snap_gizmo, | |||||
| PLACE_SNAP_TO_GEOMETRY, | |||||
| PLACE_DEPTH_SURFACE, | |||||
| PLACE_ORIENT_SURFACE, | |||||
| plane_axis, | |||||
| false, | |||||
| r_co_src, | |||||
| r_mat_orient); | |||||
| } | |||||
| static void placement_plane_adjust_to_boundbox(const BoundBox *boundbox, | |||||
| const enum ePlaceDirection direction, | |||||
| const float scale[3], | |||||
| const int plane_axis, | |||||
| const float plane_mat_orient[3][3], | |||||
| float r_co_src[3]) | |||||
| { | |||||
| BLI_assert(ELEM(direction, PLACE_DIRECTION_NEG, PLACE_DIRECTION_POS)); | |||||
| const bool is_negative_up = scale[plane_axis] < 0; | |||||
| /* Calculate the offset for all axes. */ | |||||
| float offset_vec[3] = {0}; | |||||
| { | |||||
| /* Move the offset to put the return coordinate to the center of the bounding box. */ | |||||
| BKE_boundbox_calc_center_aabb(boundbox, offset_vec); | |||||
| /* Push offset at the plane axis so the bounding box surface is where the snapping point is. */ | |||||
| float size[3]; | |||||
| BKE_boundbox_calc_size_aabb(boundbox, size); | |||||
| offset_vec[plane_axis] -= size[plane_axis] * (is_negative_up ? -1 : 1); | |||||
| /* Scale offset with the object scale. */ | |||||
| mul_v3_v3(offset_vec, scale); | |||||
| if (direction == PLACE_DIRECTION_NEG) { | |||||
| mul_v3_fl(offset_vec, -1); | |||||
| } | |||||
| } | |||||
| /* Rotate the offset vector to the plane rotation. */ | |||||
| mul_v3_m3v3(offset_vec, plane_mat_orient, offset_vec); | |||||
| /* Finally, add the rotated offset to the returned position. */ | |||||
| add_v3_v3(r_co_src, offset_vec); | |||||
| } | |||||
| void ED_view3d_placement_plane_boundbox_calc(bContext *C, | |||||
| const int mval[2], | |||||
| const BoundBox *boundbox, | |||||
| const enum ePlaceDirection direction, | |||||
| const float scale[3], | |||||
| float r_co_src[3], | |||||
| float r_mat_orient[3][3]) | |||||
| { | |||||
| const int plane_axis = 2; | |||||
| ED_view3d_placement_plane_calc(C, mval, plane_axis, r_co_src, r_mat_orient); | |||||
| placement_plane_adjust_to_boundbox( | |||||
| boundbox, direction, scale, plane_axis, r_mat_orient, r_co_src); | |||||
| } | |||||
| /** \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Add Object Modal Operator | /** \name Add Object Modal Operator | ||||
| * \{ */ | * \{ */ | ||||
| static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event) | static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); | const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); | ||||
| const bool plane_axis_auto = RNA_boolean_get(op->ptr, "plane_axis_auto"); | const bool plane_axis_auto = RNA_boolean_get(op->ptr, "plane_axis_auto"); | ||||
| Show All 9 Lines | static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| }; | }; | ||||
| const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation"); | const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation"); | ||||
| const float mval_fl[2] = {UNPACK2(event->mval)}; | const float mval_fl[2] = {UNPACK2(event->mval)}; | ||||
| struct InteractivePlaceData *ipd = op->customdata; | struct InteractivePlaceData *ipd = op->customdata; | ||||
| /* Assign snap gizmo which is may be used as part of the tool. */ | /* Assign snap gizmo which is may be used as part of the tool. */ | ||||
| { | ipd->snap_gizmo = idp_snap_gizmo_from_region(ipd->region); | ||||
| wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region); | idp_paintcursor_from_gizmo_visible_set(ipd->snap_gizmo, false); | ||||
| if (gzgroup != NULL) { | |||||
| if (gzgroup->gizmos.first) { | |||||
| ipd->snap_gizmo = gzgroup->gizmos.first; | |||||
| } | |||||
| /* Can be NULL when gizmos are disabled. */ | |||||
| if (gzgroup->customdata != NULL) { | |||||
| preview_plane_cursor_visible_set(gzgroup, false); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* For tweak events the snap target may have changed since dragging, | /* For tweak events the snap target may have changed since dragging, | ||||
| * update the snap target at the cursor location where tweak began. | * update the snap target at the cursor location where tweak began. | ||||
| * | * | ||||
| * NOTE: we could investigating solving this in a more generic way, | * NOTE: we could investigating solving this in a more generic way, | ||||
| * so each operator doesn't have to account for it. */ | * so each operator doesn't have to account for it. */ | ||||
| if (ISTWEAK(event->type)) { | if (ISTWEAK(event->type)) { | ||||
| if (ipd->snap_gizmo != NULL) { | if (ipd->snap_gizmo != NULL) { | ||||
| ▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | static void view3d_interactive_add_exit(bContext *C, wmOperator *op) | ||||
| struct InteractivePlaceData *ipd = op->customdata; | struct InteractivePlaceData *ipd = op->customdata; | ||||
| ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); | ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); | ||||
| ED_region_tag_redraw(ipd->region); | ED_region_tag_redraw(ipd->region); | ||||
| { | { | ||||
| wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region); | wmGizmo *snap_gz = idp_snap_gizmo_from_region(ipd->region); | ||||
| if (gzgroup != NULL) { | idp_paintcursor_from_gizmo_visible_set(snap_gz, true); | ||||
| if (gzgroup->customdata != NULL) { | |||||
| preview_plane_cursor_visible_set(gzgroup, true); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| MEM_freeN(ipd); | MEM_freeN(ipd); | ||||
| } | } | ||||
| static void view3d_interactive_add_cancel(bContext *C, wmOperator *op) | static void view3d_interactive_add_cancel(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| view3d_interactive_add_exit(C, op); | view3d_interactive_add_exit(C, op); | ||||
| ▲ Show 20 Lines • Show All 497 Lines • ▼ Show 20 Lines | wmGizmo *gizmo; | ||||
| gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); | gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); | ||||
| WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); | WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); | ||||
| /* Don't handle any events, this is for display only. */ | /* Don't handle any events, this is for display only. */ | ||||
| gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; | gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; | ||||
| } | } | ||||
| /* Sets the gizmos custom-data which has its own free callback. */ | { | ||||
| preview_plane_cursor_setup(gzgroup); | const wmGizmoType *gzt_plane = WM_gizmotype_find("GIZMO_GT_placement_plane_3d", true); | ||||
| gizmo = WM_gizmo_new_ptr(gzt_plane, gzgroup, NULL); | |||||
| WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); | |||||
| /* Don't handle any events, this is for display only. */ | |||||
| gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; | |||||
| } | |||||
| } | |||||
| static void WIDGETGROUP_placement_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) | |||||
| { | |||||
| /* TODO only set for drag & drop. */ | |||||
| if (!gzgroup->ptr) { | |||||
| return; | |||||
| } | |||||
| wmGizmo *gizmo_plane = ((wmGizmo *)gzgroup->gizmos.first)->next; | |||||
| PropertyRNA *boundbox_prop = RNA_struct_find_property(gzgroup->ptr, "bound_box"); | |||||
| if (boundbox_prop && RNA_property_is_set(gzgroup->ptr, boundbox_prop)) { | |||||
| float array[8][3]; | |||||
| RNA_property_float_get_array(gzgroup->ptr, boundbox_prop, (float *)array); | |||||
| RNA_float_set_array(gizmo_plane->ptr, "bound_box", (float *)array); | |||||
| } | |||||
| PropertyRNA *matrix_basis_prop = RNA_struct_find_property(gzgroup->ptr, "matrix_basis"); | |||||
| if (matrix_basis_prop && RNA_property_is_set(gzgroup->ptr, matrix_basis_prop)) { | |||||
| float array[4][4]; | |||||
| RNA_property_float_get_array(gzgroup->ptr, matrix_basis_prop, (float *)array); | |||||
| RNA_float_set_array(gizmo_plane->ptr, "matrix_basis", (float *)array); | |||||
| } | |||||
| } | |||||
| static bool WIDGETGROUP_placement_poll(const bContext *C, wmGizmoGroupType *gzgt) | |||||
| { | |||||
| return ED_gizmo_poll_from_dropbox(C, gzgt) || ED_gizmo_poll_from_tool(C, gzgt); | |||||
SeverinAuthorUnsubmitted Done Inline ActionsThis kind of polling isn't great, since it means the group needs to know what it will be used for. Think a better design would be letting external code register itself as "gizmo-group user" with its own poll function. E.g. the tool or dropbox code could then poll if they apply in current context, and the gizmo code checks the polls of all its potential users. Severin: This kind of polling isn't great, since it means the group needs to know what it will be used… | |||||
| } | } | ||||
| void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt) | void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt) | ||||
SeverinAuthorUnsubmitted Done Inline ActionsMaybe we should have a separate gizmo for the snap dragging. No strong opinion. Severin: Maybe we should have a separate gizmo for the snap dragging. No strong opinion. | |||||
| { | { | ||||
| PropertyRNA *prop; | |||||
| gzgt->name = "Placement Widget"; | gzgt->name = "Placement Widget"; | ||||
| gzgt->idname = view3d_gzgt_placement_id; | gzgt->idname = view3d_gzgt_placement_id; | ||||
| gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; | gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL | | ||||
| WM_GIZMOGROUPTYPE_ATTACHED_TO_CURSOR; | |||||
| gzgt->gzmap_params.spaceid = SPACE_VIEW3D; | gzgt->gzmap_params.spaceid = SPACE_VIEW3D; | ||||
| gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; | gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; | ||||
| gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; | gzgt->poll = WIDGETGROUP_placement_poll; | ||||
| gzgt->setup = WIDGETGROUP_placement_setup; | gzgt->setup = WIDGETGROUP_placement_setup; | ||||
| gzgt->draw_prepare = WIDGETGROUP_placement_draw_prepare; | |||||
| const int boundbox_dimsize[] = {8, 3}; | |||||
| prop = RNA_def_property(gzgt->srna, "bound_box", PROP_FLOAT, PROP_NONE); | |||||
| RNA_def_property_multi_array(prop, 2, boundbox_dimsize); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| const int matrix_dimsize[] = {4, 4}; | |||||
| prop = RNA_def_property(gzgt->srna, "matrix_basis", PROP_FLOAT, PROP_NONE); | |||||
| RNA_def_property_multi_array(prop, 2, matrix_dimsize); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Placement Preview Plane | /** \name Placement Preview Plane | ||||
| * | * | ||||
| * Preview the plane that will be used for placement. | * Preview the plane that will be used for placement. | ||||
| Show All 25 Lines | static void gizmo_plane_update_cursor(const bContext *C, | ||||
| const enum ePlace_Orient plane_orient = RNA_enum_get(&ptr, "plane_orientation"); | const enum ePlace_Orient plane_orient = RNA_enum_get(&ptr, "plane_orientation"); | ||||
| const float mval_fl[2] = {UNPACK2(mval)}; | const float mval_fl[2] = {UNPACK2(mval)}; | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| View3D *v3d = CTX_wm_view3d(C); | View3D *v3d = CTX_wm_view3d(C); | ||||
| /* Assign snap gizmo which is may be used as part of the tool. */ | /* Assign snap gizmo which is may be used as part of the tool. */ | ||||
| wmGizmo *snap_gizmo = NULL; | wmGizmo *snap_gizmo = idp_snap_gizmo_from_region(region); | ||||
| { | |||||
| wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region); | |||||
| if ((gzgroup != NULL) && gzgroup->gizmos.first) { | |||||
| snap_gizmo = gzgroup->gizmos.first; | |||||
| } | |||||
| } | |||||
| /* This ensures the snap gizmo has settings from this tool. | /* This ensures the snap gizmo has settings from this tool. | ||||
| * This function call could be moved a more appropriate place, | * This function call could be moved a more appropriate place, | ||||
| * responding to the setting being changed for example, | * responding to the setting being changed for example, | ||||
| * however setting the value isn't expensive, so do it here. */ | * however setting the value isn't expensive, so do it here. */ | ||||
| idp_snap_gizmo_update_snap_elements(scene, snap_to, snap_gizmo); | idp_snap_gizmo_update_snap_elements(scene, snap_to, snap_gizmo); | ||||
| view3d_interactive_add_calc_plane((bContext *)C, | view3d_interactive_add_calc_plane((bContext *)C, | ||||
| ▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | struct PlacementCursor { | ||||
| * Enable this while the modal operator is running, | * Enable this while the modal operator is running, | ||||
| * so the preview-plane doesn't show at the same time as add-object preview shape | * so the preview-plane doesn't show at the same time as add-object preview shape | ||||
| * since it's distracting & not helpful. | * since it's distracting & not helpful. | ||||
| */ | */ | ||||
| bool do_draw; | bool do_draw; | ||||
| void *paintcursor; | void *paintcursor; | ||||
| float boundbox[8][3]; | |||||
| bool draw_boundbox; | |||||
| float scale[3]; | |||||
| int plane_axis; | int plane_axis; | ||||
| float matrix[4][4]; | float matrix[4][4]; | ||||
| /* Check if we need to re-calculate the plane matrix. */ | /* Check if we need to re-calculate the plane matrix. */ | ||||
| int mval_prev[2]; | int mval_prev[2]; | ||||
| float persmat_prev[4][4]; | float persmat_prev[4][4]; | ||||
| }; | }; | ||||
| static void cursor_plane_draw(bContext *C, int x, int y, void *customdata) | static void cursor_plane_draw_ex(const bContext *C, const int mval[2], struct PlacementCursor *plc) | ||||
| { | { | ||||
| struct PlacementCursor *plc = (struct PlacementCursor *)customdata; | |||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| const RegionView3D *rv3d = region->regiondata; | const RegionView3D *rv3d = region->regiondata; | ||||
| /* Early exit. | /* Early exit. | ||||
| * Note that we can't do most of these checks in the poll function (besides global checks) | * Note that we can't do most of these checks in the poll function (besides global checks) | ||||
| * so test them here instead. | * so test them here instead. | ||||
| * | * | ||||
| * This cursor is only active while the gizmo is being used | * This cursor is only active while the gizmo is being used | ||||
| * so it's not so important to have a poll function. */ | * so it's not so important to have a poll function. */ | ||||
| if (plc->do_draw == false) { | if (plc->do_draw == false) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) { | if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (rv3d->rflag & RV3D_NAVIGATING) { | if (rv3d->rflag & RV3D_NAVIGATING) { | ||||
| return; | return; | ||||
| } | } | ||||
| GPU_line_smooth(false); | |||||
| GPU_line_width(1.0f); | |||||
| /* Check this gizmo group is in the region. */ | /* Check this gizmo group is in the region. */ | ||||
| { | { | ||||
| wmGizmoMap *gzmap = region->gizmo_map; | wmGizmoMap *gzmap = region->gizmo_map; | ||||
| wmGizmoGroup *gzgroup_test = WM_gizmomap_group_find_ptr(gzmap, plc->gzgroup->type); | wmGizmoGroup *gzgroup_test = WM_gizmomap_group_find_ptr(gzmap, plc->gzgroup->type); | ||||
| if (gzgroup_test != plc->gzgroup) { | if (gzgroup_test != plc->gzgroup) { | ||||
| /* Wrong viewport. */ | /* Wrong viewport. */ | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin}; | |||||
| /* Update matrix? */ | /* Update matrix? */ | ||||
| if ((plc->mval_prev[0] != mval[0]) || (plc->mval_prev[1] != mval[1]) || | if ((plc->mval_prev[0] != mval[0]) || (plc->mval_prev[1] != mval[1]) || | ||||
| !equals_m4m4(plc->persmat_prev, rv3d->persmat)) { | !equals_m4m4(plc->persmat_prev, rv3d->persmat)) { | ||||
| plc->mval_prev[0] = mval[0]; | plc->mval_prev[0] = mval[0]; | ||||
| plc->mval_prev[1] = mval[1]; | plc->mval_prev[1] = mval[1]; | ||||
| float orient_matrix[3][3]; | float orient_matrix[3][3]; | ||||
| float co[3]; | float co[3]; | ||||
| Show All 33 Lines | if (rv3d->is_persp) { | ||||
| /* Extra adjustment when it's near view-aligned as it seems overly bright. */ | /* Extra adjustment when it's near view-aligned as it seems overly bright. */ | ||||
| float view_vector[3]; | float view_vector[3]; | ||||
| ED_view3d_global_to_vector(rv3d, plc->matrix[3], view_vector); | ED_view3d_global_to_vector(rv3d, plc->matrix[3], view_vector); | ||||
| float view_dot = fabsf(dot_v3v3(plc->matrix[plc->plane_axis], view_vector)); | float view_dot = fabsf(dot_v3v3(plc->matrix[plc->plane_axis], view_vector)); | ||||
| color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot))); | color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot))); | ||||
| } | } | ||||
| /* Setup viewport & matrix. */ | /* Setup viewport & matrix. */ | ||||
| if (plc->paintcursor) { | |||||
| /* Paint cursors are on window level, need to set the viewport. */ | |||||
| wmViewport(®ion->winrct); | wmViewport(®ion->winrct); | ||||
| } | |||||
| GPU_matrix_push_projection(); | GPU_matrix_push_projection(); | ||||
| GPU_matrix_push(); | GPU_matrix_push(); | ||||
| GPU_matrix_projection_set(rv3d->winmat); | GPU_matrix_projection_set(rv3d->winmat); | ||||
| GPU_matrix_set(rv3d->viewmat); | GPU_matrix_set(rv3d->viewmat); | ||||
| float final_scale; | |||||
| if (plc->draw_boundbox) { | |||||
| /* Take diagonal of lower face to make the size based on the boundbox. */ | |||||
| float lower_min[3], lower_max[3]; | |||||
| mul_v3_v3v3(lower_min, plc->boundbox[0], plc->scale); | |||||
| mul_v3_v3v3(lower_max, plc->boundbox[6], plc->scale); | |||||
| final_scale = len_v3v3(lower_min, lower_max); | |||||
| } | |||||
| else { | |||||
| const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize; | const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize; | ||||
| final_scale = (scale_mod * pixel_size); | |||||
| } | |||||
| float final_scale = (scale_mod * pixel_size); | const int lines_subdiv = 10.0f; | ||||
| const int lines_subdiv = 10; | |||||
| int lines = lines_subdiv; | int lines = lines_subdiv; | ||||
| float final_scale_fade = final_scale; | float final_scale_fade = final_scale; | ||||
| final_scale = ceil_power_of_10(final_scale); | final_scale = ceil_power_of_10(final_scale); | ||||
| float fac = final_scale_fade / final_scale; | float fac = final_scale_fade / final_scale; | ||||
| float color[4] = {1, 1, 1, color_alpha}; | float color[4] = {1, 1, 1, color_alpha}; | ||||
| Show All 11 Lines | if (pixel_size > FLT_EPSILON) { | ||||
| /* When the grid is large, we only need the 2x lines in the middle. */ | /* When the grid is large, we only need the 2x lines in the middle. */ | ||||
| if (fac < 0.2f) { | if (fac < 0.2f) { | ||||
| lines = 1; | lines = 1; | ||||
| final_scale = final_scale_fade; | final_scale = final_scale_fade; | ||||
| } | } | ||||
| gizmo_plane_draw_grid( | gizmo_plane_draw_grid( | ||||
| lines, final_scale, final_scale_fade, plc->matrix, plc->plane_axis, color); | lines, final_scale, final_scale_fade, plc->matrix, plc->plane_axis, color); | ||||
| /* TODO support different plane axis (assumes Z right now). */ | |||||
SeverinAuthorUnsubmitted Done Inline ActionsDon't think we need to support that now, so I'm fine with just leaving this TODO in. Could also add gizmo properties without actually using them. Severin: Don't think we need to support that now, so I'm fine with just leaving this TODO in. Could also… | |||||
| if (plc->draw_boundbox) { | |||||
| float box_col[4] = {0.4f, 0.8f, 1.0f, 0.75f}; | |||||
| BoundBox bounds; | |||||
| memcpy(bounds.vec, plc->boundbox, sizeof(bounds.vec)); | |||||
| float size[3]; | |||||
| BKE_boundbox_calc_size_aabb(&bounds, size); | |||||
| float min[3] = {-size[0], -size[1], 0.0f}; | |||||
| float max[3] = {size[0], size[1], size[2] * 2}; | |||||
| mul_v3_v3(min, plc->scale); | |||||
| mul_v3_v3(max, plc->scale); | |||||
| BKE_boundbox_init_from_minmax(&bounds, min, max); | |||||
| GPU_matrix_mul(plc->matrix); | |||||
| /* Ensure the bounding-box points up. Matches how it will be placed eventualy. */ | |||||
| const bool negative_up = bounds.vec[1][2] < 0; | |||||
| if (negative_up) { | |||||
| GPU_matrix_scale_1f(-1.0f); | |||||
| } | |||||
| GPU_line_width(2.0f); | |||||
| draw_line_bounds(&bounds, box_col); | |||||
| } | |||||
| /* Restore matrix. */ | /* Restore matrix. */ | ||||
| GPU_matrix_pop(); | GPU_matrix_pop(); | ||||
| GPU_matrix_pop_projection(); | GPU_matrix_pop_projection(); | ||||
| } | } | ||||
| } | } | ||||
| static void cursor_plane_draw_cursor_fn(bContext *C, int x, int y, void *customdata) | |||||
| { | |||||
| struct PlacementCursor *plc = (struct PlacementCursor *)customdata; | |||||
| const ARegion *region = CTX_wm_region(C); | |||||
| const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin}; | |||||
| cursor_plane_draw_ex(C, mval, plc); | |||||
| } | |||||
| static void preview_plane_cursor_free(void *customdata) | static void preview_plane_cursor_free(void *customdata) | ||||
| { | { | ||||
| struct PlacementCursor *plc = customdata; | struct PlacementCursor *plc = customdata; | ||||
| /* The window manager is freed first on exit. */ | /* The window manager is freed first on exit. */ | ||||
| wmWindowManager *wm = G_MAIN->wm.first; | wmWindowManager *wm = G_MAIN->wm.first; | ||||
| if (UNLIKELY(wm != NULL)) { | if (UNLIKELY(wm != NULL)) { | ||||
| WM_paint_cursor_end(plc->paintcursor); | WM_paint_cursor_end(plc->paintcursor); | ||||
| } | } | ||||
| MEM_freeN(plc); | MEM_freeN(plc); | ||||
| } | } | ||||
| static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup) | static void UNUSED_FUNCTION(preview_plane_cursor_setup)(wmGizmoGroup *gzgroup) | ||||
| { | { | ||||
| BLI_assert(gzgroup->customdata == NULL); | BLI_assert(gzgroup->customdata == NULL); | ||||
| struct PlacementCursor *plc = MEM_callocN(sizeof(*plc), __func__); | struct PlacementCursor *plc = MEM_callocN(sizeof(*plc), __func__); | ||||
| plc->gzgroup = gzgroup; | plc->gzgroup = gzgroup; | ||||
| plc->paintcursor = WM_paint_cursor_activate( | plc->paintcursor = WM_paint_cursor_activate( | ||||
| SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw, plc); | SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw_cursor_fn, plc); | ||||
| gzgroup->customdata = plc; | gzgroup->customdata = plc; | ||||
| gzgroup->customdata_free = preview_plane_cursor_free; | gzgroup->customdata_free = preview_plane_cursor_free; | ||||
| preview_plane_cursor_visible_set(gzgroup, true); | preview_plane_cursor_visible_set(gzgroup, true); | ||||
| } | } | ||||
| static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw) | static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw) | ||||
| { | { | ||||
| struct PlacementCursor *plc = gzgroup->customdata; | struct PlacementCursor *plc = gzgroup->customdata; | ||||
| plc->do_draw = do_draw; | plc->do_draw = do_draw; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Placement Plane Gizmo | |||||
| * \{ */ | |||||
| struct PlacementPlaneGizmo { | |||||
| wmGizmo gizmo; | |||||
| struct PlacementCursor *plc; | |||||
| }; | |||||
| static void gizmo_placement_plane_setup(wmGizmo *gz) | |||||
| { | |||||
| struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz; | |||||
| plane_gz->plc = MEM_callocN(sizeof(*plane_gz->plc), __func__); | |||||
| plane_gz->plc->gzgroup = gz->parent_gzgroup; | |||||
| } | |||||
| static void gizmo_placement_plane_free(wmGizmo *gz) | |||||
| { | |||||
| struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz; | |||||
| MEM_SAFE_FREE(plane_gz->plc); | |||||
| } | |||||
| static void gizmo_placement_plane_draw(const bContext *C, wmGizmo *gz) | |||||
| { | |||||
| struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz; | |||||
| struct PlacementCursor *plc = plane_gz->plc; | |||||
| const wmWindow *win = CTX_wm_window(C); | |||||
| plc->do_draw = true; | |||||
| PropertyRNA *boundbox_prop = RNA_struct_find_property(gz->ptr, "bound_box"); | |||||
| if (RNA_property_is_set(gz->ptr, boundbox_prop)) { | |||||
| RNA_property_float_get_array(gz->ptr, boundbox_prop, (float *)plc->boundbox); | |||||
| plc->draw_boundbox = true; | |||||
| } | |||||
| else { | |||||
| plc->draw_boundbox = false; | |||||
| } | |||||
| PropertyRNA *matrix_basis_prop = RNA_struct_find_property(gz->ptr, "matrix_basis"); | |||||
| if (RNA_property_is_set(gz->ptr, matrix_basis_prop)) { | |||||
| float mat[4][4]; | |||||
| RNA_property_float_get_array(gz->ptr, matrix_basis_prop, (float *)mat); | |||||
| mat4_to_size(plc->scale, mat); | |||||
| } | |||||
| else { | |||||
| copy_v3_fl(plc->scale, 1.0f); | |||||
| } | |||||
| const wmEvent *eventstate = win->eventstate; | |||||
| const ARegion *region = CTX_wm_region(C); | |||||
| const int mval[2] = {eventstate->x - region->winrct.xmin, eventstate->y - region->winrct.ymin}; | |||||
| cursor_plane_draw_ex(C, mval, plc); | |||||
| } | |||||
| static void GIZMO_GT_placement_plane_3d(wmGizmoType *gzt) | |||||
SeverinAuthorUnsubmitted Done Inline ActionsInstantiated by the placement gizmo group, see WIDGETGROUP_placement_setup(). Severin: Instantiated by the placement gizmo group, see `WIDGETGROUP_placement_setup()`. | |||||
| { | |||||
| PropertyRNA *prop; | |||||
| /* identifiers */ | |||||
| gzt->idname = "GIZMO_GT_placement_plane_3d"; | |||||
| /* api callbacks */ | |||||
| gzt->setup = gizmo_placement_plane_setup; | |||||
| gzt->draw = gizmo_placement_plane_draw; | |||||
| gzt->free = gizmo_placement_plane_free; | |||||
| gzt->struct_size = sizeof(struct PlacementPlaneGizmo); | |||||
| const int boundbox_dimsize[] = {8, 3}; | |||||
| prop = RNA_def_property(gzt->srna, "bound_box", PROP_FLOAT, PROP_NONE); | |||||
| RNA_def_property_multi_array(prop, 2, boundbox_dimsize); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| const int matrix_dimsize[] = {4, 4}; | |||||
| prop = RNA_def_property(gzt->srna, "matrix_basis", PROP_FLOAT, PROP_NONE); | |||||
| RNA_def_property_multi_array(prop, 2, matrix_dimsize); | |||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | |||||
| } | |||||
| void ED_gizmotypes_placement_3d(void) | |||||
| { | |||||
| WM_gizmotype_append(GIZMO_GT_placement_plane_3d); | |||||
| } | |||||
| /** \} */ | |||||
This wasn't respecting the line width set with GPU_line_width().