Object: new add object tool, currently for primitive types
- Interactively adding primitives with two clicks. - Scene orientation used for new objects. - Depth [view-plane, axis-plane, surface] - Origin [base, center] - Primitive types [cube, cylinder, cone, uv-sphere, ico-sphere ] - Settings for object types in the top-bar. Shortcuts: - Snapping (Ctrl). - Constrain 1:1 aspect (Shift). - Toggle center (Alt). Part of T57210 design task.
This commit is contained in:
@@ -4945,6 +4945,32 @@ def km_transform_modal_map(_params):
|
||||
return keymap
|
||||
|
||||
|
||||
def km_view3d_interactive_add_tool_modal_map(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"View3D Placement Modal Map",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("FIXED_ASPECT_ON", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
|
||||
("FIXED_ASPECT_OFF", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
|
||||
("FIXED_ASPECT_ON", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
|
||||
("FIXED_ASPECT_OFF", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
|
||||
("PIVOT_CENTER_ON", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
|
||||
("PIVOT_CENTER_OFF", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
|
||||
("PIVOT_CENTER_ON", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
|
||||
("PIVOT_CENTER_OFF", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None),
|
||||
("SNAP_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
|
||||
("SNAP_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
|
||||
("SNAP_ON", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
|
||||
("SNAP_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_view3d_gesture_circle(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
@@ -5855,13 +5881,14 @@ def km_3d_view_tool_edit_armature_extrude_to_cursor(params):
|
||||
)
|
||||
|
||||
|
||||
def km_3d_view_tool_edit_mesh_add_cube(params):
|
||||
def km_3d_view_tool_interactive_add(params):
|
||||
return (
|
||||
"3D View Tool: Edit Mesh, Add Cube",
|
||||
"3D View Tool: Object, Add Primitive",
|
||||
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("view3d.cursor3d", {"type": params.tool_mouse, "value": 'CLICK'}, None),
|
||||
("mesh.primitive_cube_add_gizmo", {"type": params.tool_tweak, "value": 'ANY'}, None),
|
||||
("view3d.interactive_add", {"type": params.tool_tweak, "value": 'ANY', "any": True},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
]},
|
||||
)
|
||||
|
||||
@@ -6674,6 +6701,7 @@ def generate_keymaps(params=None):
|
||||
km_eyedropper_modal_map(params),
|
||||
km_eyedropper_colorramp_pointsampling_map(params),
|
||||
km_transform_modal_map(params),
|
||||
km_view3d_interactive_add_tool_modal_map(params),
|
||||
km_view3d_gesture_circle(params),
|
||||
km_gesture_border(params),
|
||||
km_gesture_zoom_border(params),
|
||||
@@ -6733,6 +6761,7 @@ def generate_keymaps(params=None):
|
||||
km_3d_view_tool_scale(params),
|
||||
km_3d_view_tool_shear(params),
|
||||
km_3d_view_tool_measure(params),
|
||||
km_3d_view_tool_interactive_add(params),
|
||||
km_3d_view_tool_pose_breakdowner(params),
|
||||
km_3d_view_tool_pose_push(params),
|
||||
km_3d_view_tool_pose_relax(params),
|
||||
@@ -6741,7 +6770,6 @@ def generate_keymaps(params=None):
|
||||
km_3d_view_tool_edit_armature_bone_envelope(params),
|
||||
km_3d_view_tool_edit_armature_extrude(params),
|
||||
km_3d_view_tool_edit_armature_extrude_to_cursor(params),
|
||||
km_3d_view_tool_edit_mesh_add_cube(params),
|
||||
km_3d_view_tool_edit_mesh_extrude_region(params),
|
||||
km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params),
|
||||
km_3d_view_tool_edit_mesh_extrude_along_normals(params),
|
||||
|
||||
@@ -436,10 +436,124 @@ class _defs_view3d_select:
|
||||
)
|
||||
|
||||
|
||||
class _defs_view3d_add:
|
||||
|
||||
# Layout tweaks here would be good to avoid,
|
||||
# this shows limits in layout engine, as buttons are using a lot of space.
|
||||
@staticmethod
|
||||
def draw_settings_interactive_add(layout, tool):
|
||||
props = tool.operator_properties("view3d.interactive_add")
|
||||
row = layout.row()
|
||||
row.scale_x = 0.8
|
||||
row.label(text="Depth:")
|
||||
row = layout.row()
|
||||
row.scale_x = 0.9
|
||||
row.prop(props, "plane_depth", text="")
|
||||
row = layout.row()
|
||||
row.prop(props, "plane_axis", text="")
|
||||
row = layout.row()
|
||||
row.scale_x = 0.7
|
||||
row.prop(props, "plane_origin")
|
||||
|
||||
@ToolDef.from_fn
|
||||
def cube_add():
|
||||
def draw_settings(_context, layout, tool):
|
||||
_defs_view3d_add.draw_settings_interactive_add(layout, tool)
|
||||
return dict(
|
||||
idname="builtin.primitive_cube_add",
|
||||
label="Add Cube",
|
||||
icon="ops.mesh.primitive_cube_add_gizmo",
|
||||
description=(
|
||||
"Add cube to mesh interactively"
|
||||
),
|
||||
widget="VIEW3D_GGT_placement",
|
||||
keymap="3D View Tool: Object, Add Primitive",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def cone_add():
|
||||
def draw_settings(_context, layout, tool):
|
||||
_defs_view3d_add.draw_settings_interactive_add(layout, tool)
|
||||
|
||||
props = tool.operator_properties("mesh.primitive_cone_add")
|
||||
layout.prop(props, "vertices")
|
||||
layout.prop(props, "end_fill_type")
|
||||
return dict(
|
||||
idname="builtin.primitive_cone_add",
|
||||
label="Add Cone",
|
||||
icon="ops.mesh.primitive_cube_add_gizmo",
|
||||
description=(
|
||||
"Add cone to mesh interactively"
|
||||
),
|
||||
widget="VIEW3D_GGT_placement",
|
||||
keymap="3D View Tool: Object, Add Primitive",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def cylinder_add():
|
||||
def draw_settings(_context, layout, tool):
|
||||
_defs_view3d_add.draw_settings_interactive_add(layout, tool)
|
||||
|
||||
props = tool.operator_properties("mesh.primitive_cylinder_add")
|
||||
layout.prop(props, "vertices")
|
||||
layout.prop(props, "end_fill_type")
|
||||
return dict(
|
||||
idname="builtin.primitive_cylinder_add",
|
||||
label="Add Cylinder",
|
||||
icon="ops.mesh.primitive_cylinder_add_gizmo",
|
||||
description=(
|
||||
"Add cylinder to mesh interactively"
|
||||
),
|
||||
widget="VIEW3D_GGT_placement",
|
||||
keymap="3D View Tool: Object, Add Primitive",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def uv_sphere_add():
|
||||
def draw_settings(_context, layout, tool):
|
||||
_defs_view3d_add.draw_settings_interactive_add(layout, tool)
|
||||
|
||||
props = tool.operator_properties("mesh.primitive_uv_sphere_add")
|
||||
layout.prop(props, "segments")
|
||||
layout.prop(props, "ring_count")
|
||||
return dict(
|
||||
idname="builtin.primitive_uv_sphere_add",
|
||||
label="Add UV Sphere",
|
||||
icon="ops.mesh.primitive_sphere_add_gizmo",
|
||||
description=(
|
||||
"Add cylinder to mesh interactively"
|
||||
),
|
||||
widget="VIEW3D_GGT_placement",
|
||||
keymap="3D View Tool: Object, Add Primitive",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def ico_sphere_add():
|
||||
def draw_settings(_context, layout, tool):
|
||||
_defs_view3d_add.draw_settings_interactive_add(layout, tool)
|
||||
|
||||
props = tool.operator_properties("mesh.primitive_ico_sphere_add")
|
||||
layout.prop(props, "subdivisions")
|
||||
return dict(
|
||||
idname="builtin.primitive_ico_sphere_add",
|
||||
label="Add Ico Sphere",
|
||||
icon="ops.mesh.primitive_sphere_add_gizmo",
|
||||
description=(
|
||||
"Add cylinder to mesh interactively"
|
||||
),
|
||||
widget="VIEW3D_GGT_placement",
|
||||
keymap="3D View Tool: Object, Add Primitive",
|
||||
draw_settings=draw_settings,
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Object Modes (named based on context.mode)
|
||||
|
||||
|
||||
class _defs_edit_armature:
|
||||
|
||||
@ToolDef.from_fn
|
||||
@@ -497,19 +611,6 @@ class _defs_edit_armature:
|
||||
|
||||
class _defs_edit_mesh:
|
||||
|
||||
@ToolDef.from_fn
|
||||
def cube_add():
|
||||
return dict(
|
||||
idname="builtin.add_cube",
|
||||
label="Add Cube",
|
||||
icon="ops.mesh.primitive_cube_add_gizmo",
|
||||
description=(
|
||||
"Add cube to mesh interactively"
|
||||
),
|
||||
widget=None,
|
||||
keymap=(),
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def rip_region():
|
||||
def draw_settings(_context, layout, tool):
|
||||
@@ -2147,6 +2248,14 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
),
|
||||
)
|
||||
|
||||
_tools_view3d_add = (
|
||||
_defs_view3d_add.cube_add,
|
||||
_defs_view3d_add.cone_add,
|
||||
_defs_view3d_add.cylinder_add,
|
||||
_defs_view3d_add.uv_sphere_add,
|
||||
_defs_view3d_add.ico_sphere_add,
|
||||
)
|
||||
|
||||
_tools_default = (
|
||||
*_tools_select,
|
||||
_defs_view3d_generic.cursor,
|
||||
@@ -2165,6 +2274,9 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
],
|
||||
'OBJECT': [
|
||||
*_tools_default,
|
||||
|
||||
None,
|
||||
_tools_view3d_add,
|
||||
],
|
||||
'POSE': [
|
||||
*_tools_default,
|
||||
@@ -2193,6 +2305,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
'EDIT_MESH': [
|
||||
*_tools_default,
|
||||
None,
|
||||
_tools_view3d_add,
|
||||
None,
|
||||
(
|
||||
_defs_edit_mesh.extrude,
|
||||
_defs_edit_mesh.extrude_dissolve_and_intersect,
|
||||
|
||||
@@ -74,6 +74,7 @@ typedef struct SnapGizmo3D {
|
||||
int snap_on;
|
||||
bool invert_snap;
|
||||
#endif
|
||||
int use_snap_override;
|
||||
} SnapGizmo3D;
|
||||
|
||||
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
|
||||
@@ -211,6 +212,23 @@ SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene,
|
||||
return gizmo_snap->snap_context_v3d;
|
||||
}
|
||||
|
||||
bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz)
|
||||
{
|
||||
SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
|
||||
return gizmo_snap->invert_snap;
|
||||
}
|
||||
void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable)
|
||||
{
|
||||
SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
|
||||
gizmo_snap->use_snap_override = (int)enable;
|
||||
}
|
||||
|
||||
void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz)
|
||||
{
|
||||
SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
|
||||
gizmo_snap->use_snap_override = -1;
|
||||
}
|
||||
|
||||
short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
|
||||
struct Depsgraph *depsgraph,
|
||||
const ARegion *region,
|
||||
@@ -221,21 +239,30 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
|
||||
float r_nor[3])
|
||||
{
|
||||
SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
float co[3], no[3];
|
||||
short snap_elem = 0;
|
||||
int snap_elem_index[3] = {-1, -1, -1};
|
||||
int index = -1;
|
||||
|
||||
if (gizmo_snap->use_snap_override != -1) {
|
||||
if (gizmo_snap->use_snap_override == false) {
|
||||
gizmo_snap->snap_elem = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
|
||||
if (wm) {
|
||||
gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate);
|
||||
}
|
||||
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
const ToolSettings *ts = scene->toolsettings;
|
||||
if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
|
||||
gizmo_snap->snap_elem = 0;
|
||||
return 0;
|
||||
if (gizmo_snap->use_snap_override == -1) {
|
||||
const ToolSettings *ts = scene->toolsettings;
|
||||
if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
|
||||
gizmo_snap->snap_elem = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(wm);
|
||||
@@ -328,6 +355,8 @@ static void gizmo_snap_setup(wmGizmo *gz)
|
||||
gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index");
|
||||
gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force");
|
||||
|
||||
gizmo_snap->use_snap_override = -1;
|
||||
|
||||
/* Prop fallback. */
|
||||
WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1);
|
||||
|
||||
@@ -381,7 +410,7 @@ static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2])
|
||||
SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
|
||||
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
bool invert = invert_snap(gz, wm, wm->winactive->eventstate);
|
||||
const bool invert = invert_snap(gz, wm, wm->winactive->eventstate);
|
||||
if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] &&
|
||||
gizmo_snap->mval[1] == mval[1]) {
|
||||
/* Performance, do not update. */
|
||||
|
||||
@@ -261,6 +261,11 @@ struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *sce
|
||||
const struct ARegion *region,
|
||||
const struct View3D *v3d,
|
||||
struct wmGizmo *gz);
|
||||
|
||||
bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz);
|
||||
void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable);
|
||||
void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz);
|
||||
|
||||
short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz,
|
||||
struct Depsgraph *depsgraph,
|
||||
const struct ARegion *region,
|
||||
|
||||
@@ -64,6 +64,7 @@ set(SRC
|
||||
view3d_header.c
|
||||
view3d_iterators.c
|
||||
view3d_ops.c
|
||||
view3d_placement.c
|
||||
view3d_project.c
|
||||
view3d_select.c
|
||||
view3d_snap.c
|
||||
|
||||
@@ -675,6 +675,8 @@ static void view3d_widgets(void)
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
|
||||
WM_gizmotype_append(VIEW3D_GT_ruler_item);
|
||||
|
||||
WM_gizmogrouptype_append(VIEW3D_GGT_placement);
|
||||
|
||||
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
|
||||
WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
|
||||
}
|
||||
|
||||
@@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
|
||||
/* view3d_buttons.c */
|
||||
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
|
||||
@@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
|
||||
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
|
||||
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
|
||||
|
||||
/* view3d_placement.c */
|
||||
void VIEW3D_OT_interactive_add(struct wmOperatorType *ot);
|
||||
|
||||
/* space_view3d.c */
|
||||
extern const char *view3d_context_dir[]; /* doc access */
|
||||
|
||||
@@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot);
|
||||
|
||||
void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt);
|
||||
|
||||
void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt);
|
||||
|
||||
/* workaround for trivial but noticeable camera bug caused by imprecision
|
||||
* between view border calculation in 2D/3D space, workaround for bug [#28037].
|
||||
* without this define we get the old behavior which is to try and align them
|
||||
|
||||
@@ -211,6 +211,8 @@ void view3d_operatortypes(void)
|
||||
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
|
||||
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
|
||||
|
||||
WM_operatortype_append(VIEW3D_OT_interactive_add);
|
||||
|
||||
WM_operatortype_append(VIEW3D_OT_toggle_shading);
|
||||
WM_operatortype_append(VIEW3D_OT_toggle_xray);
|
||||
WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
|
||||
@@ -234,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf)
|
||||
viewmove_modal_keymap(keyconf);
|
||||
viewzoom_modal_keymap(keyconf);
|
||||
viewdolly_modal_keymap(keyconf);
|
||||
viewplace_modal_keymap(keyconf);
|
||||
}
|
||||
|
||||
1153
source/blender/editors/space_view3d/view3d_placement.c
Normal file
1153
source/blender/editors/space_view3d/view3d_placement.c
Normal file
@@ -0,0 +1,1153 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup spview3d
|
||||
*
|
||||
* Operator to interactively place data.
|
||||
*
|
||||
* Currently only adds meshes, but could add other kinds of data
|
||||
* including library assets & non-mesh types.
|
||||
*/
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_vfont_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_toolsystem.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "ED_gizmo_library.h"
|
||||
#include "ED_gizmo_utils.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_transform.h"
|
||||
#include "ED_transform_snap_object_context.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_state.h"
|
||||
|
||||
#include "view3d_intern.h"
|
||||
|
||||
static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Local Types
|
||||
* \{ */
|
||||
|
||||
enum ePlace_PrimType {
|
||||
PLACE_PRIMITIVE_TYPE_CUBE = 1,
|
||||
PLACE_PRIMITIVE_TYPE_CYLINDER = 2,
|
||||
PLACE_PRIMITIVE_TYPE_CONE = 3,
|
||||
PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4,
|
||||
PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5,
|
||||
};
|
||||
|
||||
enum ePlace_Origin {
|
||||
PLACE_ORIGIN_BASE = 1,
|
||||
PLACE_ORIGIN_CENTER = 2,
|
||||
};
|
||||
|
||||
enum ePlace_Depth {
|
||||
PLACE_DEPTH_SURFACE = 1,
|
||||
PLACE_DEPTH_CURSOR_PLANE = 2,
|
||||
PLACE_DEPTH_CURSOR_VIEW = 3,
|
||||
};
|
||||
|
||||
struct InteractivePlaceData {
|
||||
/* Window manager variables (set these even when waiting for input). */
|
||||
Scene *scene;
|
||||
ScrArea *area;
|
||||
View3D *v3d;
|
||||
ARegion *region;
|
||||
|
||||
/** Draw object preview region draw callback. */
|
||||
void *draw_handle_view;
|
||||
|
||||
float co_src[3];
|
||||
|
||||
/** Primary & secondary steps. */
|
||||
struct {
|
||||
bool is_centered;
|
||||
bool is_fixed_aspect;
|
||||
float plane[4];
|
||||
float co_dst[3];
|
||||
} step[2];
|
||||
|
||||
float matrix_orient[3][3];
|
||||
int orient_axis;
|
||||
|
||||
/** The tool option, if we start centered, invert toggling behavior. */
|
||||
bool is_centered_init;
|
||||
|
||||
bool use_snap, is_snap_found, is_snap_invert;
|
||||
float snap_co[3];
|
||||
|
||||
/** Can index into #InteractivePlaceData.step. */
|
||||
enum {
|
||||
STEP_BASE = 0,
|
||||
STEP_DEPTH = 1,
|
||||
} step_index;
|
||||
|
||||
enum ePlace_PrimType primitive_type;
|
||||
|
||||
/** Activated from the tool-system. */
|
||||
bool use_tool;
|
||||
|
||||
/** Event used to start the operator. */
|
||||
short launch_event;
|
||||
|
||||
/** When activated without a tool. */
|
||||
bool wait_for_input;
|
||||
|
||||
/** Optional snap gizmo, needed for snapping. */
|
||||
wmGizmo *snap_gizmo;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Utilities
|
||||
* \{ */
|
||||
|
||||
/* On-screen snap distance. */
|
||||
#define MVAL_MAX_PX_DIST 12.0f
|
||||
|
||||
static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
|
||||
{
|
||||
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
|
||||
PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location");
|
||||
RNA_property_float_get_array(gz->ptr, prop_location, r_location);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Primitive Drawing (Cube, Cone, Cylinder...)
|
||||
* \{ */
|
||||
|
||||
static void draw_line_loop(float coords[][3], int coords_len, const float color[4])
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
|
||||
GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(vert, coords_len);
|
||||
|
||||
for (int i = 0; i < coords_len; i++) {
|
||||
GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
|
||||
}
|
||||
|
||||
GPU_blend(true);
|
||||
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_bind(batch);
|
||||
|
||||
GPU_batch_uniform_4fv(batch, "color", color);
|
||||
|
||||
float viewport[4];
|
||||
GPU_viewport_size_get_f(viewport);
|
||||
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
|
||||
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_program_use_end(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
static void draw_line_pairs(float coords_a[][3],
|
||||
float coords_b[][3],
|
||||
int coords_len,
|
||||
const float color[4])
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
|
||||
GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(vert, coords_len * 2);
|
||||
|
||||
for (int i = 0; i < coords_len; i++) {
|
||||
GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
|
||||
GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
|
||||
}
|
||||
|
||||
GPU_blend(true);
|
||||
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_bind(batch);
|
||||
|
||||
GPU_batch_uniform_4fv(batch, "color", color);
|
||||
|
||||
float viewport[4];
|
||||
GPU_viewport_size_get_f(viewport);
|
||||
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
|
||||
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_program_use_end(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
static void draw_line_bounds(const BoundBox *bounds, const float color[4])
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
|
||||
int edges[12][2] = {
|
||||
/* First side. */
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 3},
|
||||
{3, 0},
|
||||
/* Second side. */
|
||||
{4, 5},
|
||||
{5, 6},
|
||||
{6, 7},
|
||||
{7, 4},
|
||||
/* Edges between. */
|
||||
{0, 4},
|
||||
{1, 5},
|
||||
{2, 6},
|
||||
{3, 7},
|
||||
};
|
||||
|
||||
GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2);
|
||||
|
||||
for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
|
||||
GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
|
||||
GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
|
||||
}
|
||||
|
||||
GPU_blend(true);
|
||||
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_bind(batch);
|
||||
|
||||
GPU_batch_uniform_4fv(batch, "color", color);
|
||||
|
||||
float viewport[4];
|
||||
GPU_viewport_size_get_f(viewport);
|
||||
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
|
||||
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_program_use_end(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds)
|
||||
{
|
||||
memset(bounds, 0x0, sizeof(*bounds));
|
||||
|
||||
if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float matrix_orient_inv[3][3];
|
||||
invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
|
||||
|
||||
const int x_axis = (ipd->orient_axis + 1) % 3;
|
||||
const int y_axis = (ipd->orient_axis + 2) % 3;
|
||||
|
||||
float quad_base[4][3];
|
||||
float quad_secondary[4][3];
|
||||
|
||||
copy_v3_v3(quad_base[0], ipd->co_src);
|
||||
copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
|
||||
|
||||
/* Only set when we have a fixed aspect. */
|
||||
float fixed_aspect_dimension;
|
||||
|
||||
/* *** Primary *** */
|
||||
|
||||
{
|
||||
float delta_local[3];
|
||||
float delta_a[3];
|
||||
float delta_b[3];
|
||||
|
||||
sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
|
||||
mul_m3_v3(matrix_orient_inv, delta_local);
|
||||
|
||||
copy_v3_v3(delta_a, delta_local);
|
||||
copy_v3_v3(delta_b, delta_local);
|
||||
delta_a[ipd->orient_axis] = 0.0f;
|
||||
delta_b[ipd->orient_axis] = 0.0f;
|
||||
|
||||
delta_a[x_axis] = 0.0f;
|
||||
delta_b[y_axis] = 0.0f;
|
||||
|
||||
/* Assign here in case secondary */
|
||||
fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
|
||||
|
||||
if (ipd->step[0].is_fixed_aspect) {
|
||||
delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
|
||||
delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
|
||||
}
|
||||
|
||||
mul_m3_v3(ipd->matrix_orient, delta_a);
|
||||
mul_m3_v3(ipd->matrix_orient, delta_b);
|
||||
|
||||
if (ipd->step[0].is_fixed_aspect) {
|
||||
/* Recalculate the destination point. */
|
||||
copy_v3_v3(quad_base[2], ipd->co_src);
|
||||
add_v3_v3(quad_base[2], delta_a);
|
||||
add_v3_v3(quad_base[2], delta_b);
|
||||
}
|
||||
|
||||
add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
|
||||
add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
|
||||
}
|
||||
|
||||
if (ipd->step[0].is_centered) {
|
||||
/* Use a copy in case aspect was applied to the quad. */
|
||||
float base_co_dst[3];
|
||||
copy_v3_v3(base_co_dst, quad_base[2]);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sub_v3_v3(quad_base[i], base_co_dst);
|
||||
mul_v3_fl(quad_base[i], 2.0f);
|
||||
add_v3_v3(quad_base[i], base_co_dst);
|
||||
}
|
||||
}
|
||||
|
||||
/* *** Secondary *** */
|
||||
|
||||
float delta_local[3];
|
||||
if (ipd->step_index == STEP_DEPTH) {
|
||||
sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
|
||||
}
|
||||
else {
|
||||
zero_v3(delta_local);
|
||||
}
|
||||
|
||||
if (ipd->step[1].is_fixed_aspect) {
|
||||
if (!is_zero_v3(delta_local)) {
|
||||
normalize_v3_length(delta_local, fixed_aspect_dimension);
|
||||
}
|
||||
}
|
||||
|
||||
if (ipd->step[1].is_centered) {
|
||||
for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
|
||||
sub_v3_v3(quad_base[i], delta_local);
|
||||
}
|
||||
mul_v3_fl(delta_local, 2.0f);
|
||||
}
|
||||
|
||||
if ((ipd->step_index == STEP_DEPTH) &&
|
||||
(compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) {
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
|
||||
add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(quad_secondary[0], quad_base[0]);
|
||||
copy_v3_v3(quad_secondary[1], quad_base[1]);
|
||||
copy_v3_v3(quad_secondary[2], quad_base[2]);
|
||||
copy_v3_v3(quad_secondary[3], quad_base[3]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
copy_v3_v3(bounds->vec[i], quad_base[i]);
|
||||
copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void draw_circle_in_quad(const float v1[2],
|
||||
const float v2[2],
|
||||
const float v3[2],
|
||||
const float v4[2],
|
||||
const int resolution,
|
||||
const float color[4])
|
||||
{
|
||||
/* This isn't so efficient. */
|
||||
const float quad[4][2] = {
|
||||
{-1, -1},
|
||||
{+1, -1},
|
||||
{+1, +1},
|
||||
{-1, +1},
|
||||
};
|
||||
|
||||
float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__);
|
||||
for (int i = 0; i <= resolution; i++) {
|
||||
float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f;
|
||||
float x = cosf(theta);
|
||||
float y = sinf(theta);
|
||||
float pt[2] = {x, y};
|
||||
float w[4];
|
||||
barycentric_weights_v2_quad(UNPACK4(quad), pt, w);
|
||||
|
||||
float *co = coords[i];
|
||||
zero_v3(co);
|
||||
madd_v3_v3fl(co, v1, w[0]);
|
||||
madd_v3_v3fl(co, v2, w[1]);
|
||||
madd_v3_v3fl(co, v3, w[2]);
|
||||
madd_v3_v3fl(co, v4, w[3]);
|
||||
}
|
||||
draw_line_loop(coords, resolution + 1, color);
|
||||
MEM_freeN(coords);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Drawing Callbacks
|
||||
* \{ */
|
||||
|
||||
static void draw_primitive_view_impl(const struct bContext *C,
|
||||
struct InteractivePlaceData *ipd,
|
||||
const float color[4])
|
||||
{
|
||||
UNUSED_VARS(C);
|
||||
|
||||
BoundBox bounds;
|
||||
calc_bbox(ipd, &bounds);
|
||||
draw_line_bounds(&bounds, color);
|
||||
|
||||
if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
|
||||
/* pass */
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
|
||||
draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
|
||||
draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color);
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
|
||||
draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
|
||||
|
||||
float center[3];
|
||||
mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4])));
|
||||
|
||||
float coords_a[4][3];
|
||||
float coords_b[4][3];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
copy_v3_v3(coords_a[i], center);
|
||||
mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
|
||||
}
|
||||
|
||||
draw_line_pairs(coords_a, coords_b, 4, color);
|
||||
}
|
||||
else if (ELEM(ipd->primitive_type,
|
||||
PLACE_PRIMITIVE_TYPE_SPHERE_UV,
|
||||
PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) {
|
||||
/* See bound-box diagram for reference. */
|
||||
|
||||
/* Primary Side. */
|
||||
float v01[3], v12[3], v23[3], v30[3];
|
||||
mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
|
||||
mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
|
||||
mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
|
||||
mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
|
||||
/* Secondary Side. */
|
||||
float v45[3], v56[3], v67[3], v74[3];
|
||||
mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
|
||||
mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
|
||||
mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
|
||||
mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
|
||||
/* Edges between. */
|
||||
float v04[3], v15[3], v26[3], v37[3];
|
||||
mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
|
||||
mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
|
||||
mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
|
||||
mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
|
||||
|
||||
draw_circle_in_quad(v01, v45, v67, v23, 32, color);
|
||||
draw_circle_in_quad(v30, v12, v56, v74, 32, color);
|
||||
draw_circle_in_quad(v04, v15, v26, v37, 32, color);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg)
|
||||
{
|
||||
struct InteractivePlaceData *ipd = arg;
|
||||
float color[4];
|
||||
UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color);
|
||||
|
||||
const bool use_depth = !XRAY_ENABLED(ipd->v3d);
|
||||
const bool depth_test_enabled = GPU_depth_test_enabled();
|
||||
|
||||
if (use_depth) {
|
||||
GPU_depth_test(false);
|
||||
color[3] = 0.15f;
|
||||
draw_primitive_view_impl(C, ipd, color);
|
||||
}
|
||||
|
||||
if (use_depth) {
|
||||
GPU_depth_test(true);
|
||||
}
|
||||
color[3] = 1.0f;
|
||||
draw_primitive_view_impl(C, ipd, color);
|
||||
|
||||
if (use_depth) {
|
||||
if (depth_test_enabled == false) {
|
||||
GPU_depth_test(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Add Object Modal Operator
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
*
|
||||
* */
|
||||
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 enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
|
||||
const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin");
|
||||
|
||||
struct InteractivePlaceData *ipd = op->customdata;
|
||||
|
||||
RegionView3D *rv3d = ipd->region->regiondata;
|
||||
|
||||
ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
|
||||
|
||||
ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
|
||||
|
||||
ipd->orient_axis = plane_axis;
|
||||
ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
|
||||
ipd->step[0].is_centered = ipd->is_centered_init;
|
||||
ipd->step[1].is_centered = ipd->is_centered_init;
|
||||
ipd->step_index = STEP_BASE;
|
||||
|
||||
/* Assign snap gizmo which is may be used as part of the tool. */
|
||||
{
|
||||
wmGizmoMap *gzmap = ipd->region->gizmo_map;
|
||||
wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
|
||||
if ((gzgroup != NULL) && gzgroup->gizmos.first) {
|
||||
ipd->snap_gizmo = gzgroup->gizmos.first;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
|
||||
if (RNA_property_is_set(op->ptr, prop)) {
|
||||
ipd->primitive_type = RNA_property_enum_get(op->ptr, prop);
|
||||
ipd->use_tool = false;
|
||||
}
|
||||
else {
|
||||
ipd->use_tool = true;
|
||||
|
||||
/* Get from the tool, a bit of a non-standard way of operating. */
|
||||
const bToolRef *tref = ipd->area->runtime.tool;
|
||||
if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
|
||||
}
|
||||
else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER;
|
||||
}
|
||||
else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE;
|
||||
}
|
||||
else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV;
|
||||
}
|
||||
else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO;
|
||||
}
|
||||
else {
|
||||
/* If the user runs this as an operator they should set the 'primitive_type',
|
||||
* however running from operator search will end up at this point. */
|
||||
ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
|
||||
ipd->use_tool = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED_VARS(C, event);
|
||||
|
||||
ipd->draw_handle_view = ED_region_draw_cb_activate(
|
||||
ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW);
|
||||
|
||||
ED_region_tag_redraw(ipd->region);
|
||||
|
||||
plane_from_point_normal_v3(
|
||||
ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
|
||||
|
||||
const float mval_fl[2] = {UNPACK2(event->mval)};
|
||||
|
||||
const bool is_snap_found = ipd->snap_gizmo ?
|
||||
idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) :
|
||||
false;
|
||||
ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) :
|
||||
false;
|
||||
{
|
||||
const ToolSettings *ts = ipd->scene->toolsettings;
|
||||
ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
|
||||
}
|
||||
|
||||
if (is_snap_found) {
|
||||
/* pass */
|
||||
}
|
||||
else {
|
||||
bool use_depth_fallback = true;
|
||||
if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) {
|
||||
/* View plane. */
|
||||
ED_view3d_win_to_3d(
|
||||
ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src);
|
||||
use_depth_fallback = false;
|
||||
}
|
||||
else if (plane_depth == PLACE_DEPTH_SURFACE) {
|
||||
SnapObjectContext *snap_context =
|
||||
(ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(
|
||||
ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) :
|
||||
NULL);
|
||||
if ((snap_context != NULL) &&
|
||||
ED_transform_snap_object_project_view3d(snap_context,
|
||||
CTX_data_ensure_evaluated_depsgraph(C),
|
||||
SCE_SNAP_MODE_FACE,
|
||||
&(const struct SnapObjectParams){
|
||||
.snap_select = SNAP_ALL,
|
||||
.use_object_edit_cage = true,
|
||||
},
|
||||
mval_fl,
|
||||
NULL,
|
||||
NULL,
|
||||
ipd->co_src,
|
||||
NULL)) {
|
||||
use_depth_fallback = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use as fallback to surface. */
|
||||
if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) {
|
||||
/* Cursor plane. */
|
||||
float plane[4];
|
||||
plane_from_point_normal_v3(
|
||||
plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
|
||||
if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) {
|
||||
use_depth_fallback = false;
|
||||
}
|
||||
/* Even if the calculation works, it's possible the point found is behind the view. */
|
||||
if (rv3d->is_persp) {
|
||||
float dir[3];
|
||||
sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src);
|
||||
if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) {
|
||||
use_depth_fallback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_depth_fallback) {
|
||||
float co_depth[3];
|
||||
/* Fallback to view center. */
|
||||
negate_v3_v3(co_depth, rv3d->ofs);
|
||||
ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src);
|
||||
}
|
||||
}
|
||||
|
||||
plane_from_point_normal_v3(
|
||||
ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]);
|
||||
|
||||
copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
|
||||
}
|
||||
|
||||
static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
|
||||
|
||||
struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__);
|
||||
op->customdata = ipd;
|
||||
|
||||
ipd->scene = CTX_data_scene(C);
|
||||
ipd->area = CTX_wm_area(C);
|
||||
ipd->region = CTX_wm_region(C);
|
||||
ipd->v3d = CTX_wm_view3d(C);
|
||||
|
||||
if (wait_for_input) {
|
||||
ipd->wait_for_input = true;
|
||||
/* TODO: support snapping when not using with tool. */
|
||||
#if 0
|
||||
WM_gizmo_group_type_ensure(view3d_gzgt_placement_id);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
view3d_interactive_add_begin(C, op, event);
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
|
||||
{
|
||||
UNUSED_VARS(C);
|
||||
|
||||
struct InteractivePlaceData *ipd = op->customdata;
|
||||
|
||||
ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
|
||||
|
||||
ED_region_tag_redraw(ipd->region);
|
||||
|
||||
MEM_freeN(ipd);
|
||||
}
|
||||
|
||||
static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
view3d_interactive_add_exit(C, op);
|
||||
}
|
||||
|
||||
enum {
|
||||
PLACE_MODAL_SNAP_ON,
|
||||
PLACE_MODAL_SNAP_OFF,
|
||||
PLACE_MODAL_FIXED_ASPECT_ON,
|
||||
PLACE_MODAL_FIXED_ASPECT_OFF,
|
||||
PLACE_MODAL_PIVOT_CENTER_ON,
|
||||
PLACE_MODAL_PIVOT_CENTER_OFF,
|
||||
};
|
||||
|
||||
void viewplace_modal_keymap(wmKeyConfig *keyconf)
|
||||
{
|
||||
static const EnumPropertyItem modal_items[] = {
|
||||
{PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
|
||||
{PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
|
||||
{PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
|
||||
{PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
|
||||
{PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
|
||||
{PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
const char *keymap_name = "View3D Placement Modal Map";
|
||||
wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
|
||||
|
||||
/* This function is called for each space-type, only needs to add map once. */
|
||||
if (keymap && keymap->modal_items) {
|
||||
return;
|
||||
}
|
||||
|
||||
keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
|
||||
|
||||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
|
||||
}
|
||||
|
||||
static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
UNUSED_VARS(C, op);
|
||||
|
||||
struct InteractivePlaceData *ipd = op->customdata;
|
||||
|
||||
ARegion *region = ipd->region;
|
||||
bool do_redraw = false;
|
||||
bool do_cursor_update = false;
|
||||
|
||||
/* Handle modal key-map. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
bool is_fallthrough = false;
|
||||
switch (event->val) {
|
||||
case PLACE_MODAL_FIXED_ASPECT_ON: {
|
||||
is_fallthrough = true;
|
||||
ATTR_FALLTHROUGH;
|
||||
}
|
||||
case PLACE_MODAL_FIXED_ASPECT_OFF: {
|
||||
ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough;
|
||||
do_redraw = true;
|
||||
break;
|
||||
}
|
||||
case PLACE_MODAL_PIVOT_CENTER_ON: {
|
||||
is_fallthrough = true;
|
||||
ATTR_FALLTHROUGH;
|
||||
}
|
||||
case PLACE_MODAL_PIVOT_CENTER_OFF: {
|
||||
ipd->step[ipd->step_index].is_centered = is_fallthrough;
|
||||
do_redraw = true;
|
||||
break;
|
||||
}
|
||||
case PLACE_MODAL_SNAP_ON: {
|
||||
is_fallthrough = true;
|
||||
ATTR_FALLTHROUGH;
|
||||
}
|
||||
case PLACE_MODAL_SNAP_OFF: {
|
||||
const ToolSettings *ts = ipd->scene->toolsettings;
|
||||
ipd->is_snap_invert = is_fallthrough;
|
||||
ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
|
||||
do_cursor_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
|
||||
view3d_interactive_add_exit(C, op);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
else if (event->type == MOUSEMOVE) {
|
||||
do_cursor_update = true;
|
||||
}
|
||||
|
||||
if (ipd->wait_for_input) {
|
||||
if (ELEM(event->type, LEFTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
view3d_interactive_add_begin(C, op, event);
|
||||
ipd->wait_for_input = false;
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
}
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
if (ipd->step_index == STEP_BASE) {
|
||||
if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
/* Set secondary plane. */
|
||||
|
||||
/* Create normal. */
|
||||
{
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
float no_temp[3];
|
||||
float no[3];
|
||||
cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
|
||||
cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
|
||||
normalize_v3(no);
|
||||
|
||||
plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
|
||||
}
|
||||
|
||||
copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
|
||||
ipd->step_index = STEP_DEPTH;
|
||||
|
||||
/* Keep these values from the previous step. */
|
||||
ipd->step[1].is_centered = ipd->step[0].is_centered;
|
||||
ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ipd->step_index == STEP_DEPTH) {
|
||||
if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
|
||||
if (event->val == KM_PRESS) {
|
||||
|
||||
BoundBox bounds;
|
||||
calc_bbox(ipd, &bounds);
|
||||
|
||||
float location[3];
|
||||
float rotation[3];
|
||||
float scale[3];
|
||||
|
||||
float matrix_orient_axis[3][3];
|
||||
copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
|
||||
if (ipd->orient_axis != 2) {
|
||||
swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
|
||||
swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
|
||||
}
|
||||
/* Needed for shapes where the sign matters (cone for eg). */
|
||||
{
|
||||
float delta[3];
|
||||
sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
|
||||
if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
|
||||
negate_v3(matrix_orient_axis[2]);
|
||||
|
||||
/* Only flip Y so we don't flip a single axis which causes problems. */
|
||||
negate_v3(matrix_orient_axis[1]);
|
||||
}
|
||||
}
|
||||
|
||||
mat3_to_eul(rotation, matrix_orient_axis);
|
||||
|
||||
mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
|
||||
const int cube_verts[3] = {3, 1, 4};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
|
||||
}
|
||||
|
||||
wmOperatorType *ot = NULL;
|
||||
PointerRNA op_props;
|
||||
if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
|
||||
ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
|
||||
ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
|
||||
ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) {
|
||||
ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
|
||||
}
|
||||
else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) {
|
||||
ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
|
||||
}
|
||||
|
||||
if (ot != NULL) {
|
||||
WM_operator_properties_create_ptr(&op_props, ot);
|
||||
|
||||
if (ipd->use_tool) {
|
||||
bToolRef *tref = ipd->area->runtime.tool;
|
||||
PointerRNA temp_props;
|
||||
WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
|
||||
SWAP(PointerRNA, temp_props, op_props);
|
||||
WM_operator_properties_free(&temp_props);
|
||||
}
|
||||
|
||||
RNA_float_set_array(&op_props, "rotation", rotation);
|
||||
RNA_float_set_array(&op_props, "location", location);
|
||||
RNA_float_set_array(&op_props, "scale", scale);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
|
||||
WM_operator_properties_free(&op_props);
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
view3d_interactive_add_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
if (do_cursor_update) {
|
||||
const float mval_fl[2] = {UNPACK2(event->mval)};
|
||||
|
||||
/* Calculate the snap location on mouse-move or when toggling snap. */
|
||||
bool is_snap_found_prev = ipd->is_snap_found;
|
||||
ipd->is_snap_found = false;
|
||||
if (ipd->use_snap) {
|
||||
if (ipd->snap_gizmo != NULL) {
|
||||
ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap);
|
||||
if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
|
||||
CTX_data_ensure_evaluated_depsgraph(C),
|
||||
ipd->region,
|
||||
ipd->v3d,
|
||||
NULL,
|
||||
mval_fl,
|
||||
ipd->snap_co,
|
||||
NULL)) {
|
||||
ipd->is_snap_found = true;
|
||||
}
|
||||
ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo);
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround because test_select doesn't run at the same time as the modal operator. */
|
||||
if (is_snap_found_prev != ipd->is_snap_found) {
|
||||
wmGizmoMap *gzmap = ipd->region->gizmo_map;
|
||||
WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL);
|
||||
}
|
||||
|
||||
if (ipd->step_index == STEP_BASE) {
|
||||
if (ipd->is_snap_found) {
|
||||
closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co);
|
||||
}
|
||||
else {
|
||||
if (ED_view3d_win_to_3d_on_plane(
|
||||
region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ipd->step_index == STEP_DEPTH) {
|
||||
if (ipd->is_snap_found) {
|
||||
closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co);
|
||||
}
|
||||
else {
|
||||
if (ED_view3d_win_to_3d_on_plane(
|
||||
region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
|
||||
/* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
|
||||
float close[3], delta[3];
|
||||
closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst);
|
||||
sub_v3_v3v3(delta, close, ipd->step[0].co_dst);
|
||||
sub_v3_v3(ipd->step[1].co_dst, delta);
|
||||
}
|
||||
do_redraw = true;
|
||||
}
|
||||
|
||||
if (do_redraw) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static bool view3d_interactive_add_poll(bContext *C)
|
||||
{
|
||||
const enum eContextObjectMode mode = CTX_data_mode_enum(C);
|
||||
return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH);
|
||||
}
|
||||
|
||||
void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Primitive Object";
|
||||
ot->description = "Interactively add an object";
|
||||
ot->idname = "VIEW3D_OT_interactive_add";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = view3d_interactive_add_invoke;
|
||||
ot->modal = view3d_interactive_add_modal;
|
||||
ot->cancel = view3d_interactive_add_cancel;
|
||||
ot->poll = view3d_interactive_add_poll;
|
||||
|
||||
/* Note, let the operator we call handle undo and registering it's self. */
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* Normally not accessed directly, leave unset and check the active tool. */
|
||||
static const EnumPropertyItem primitive_type[] = {
|
||||
{PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
|
||||
{PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
|
||||
{PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
|
||||
{PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
|
||||
{PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Primitive", "");
|
||||
RNA_def_property_enum_items(prop, primitive_type);
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region");
|
||||
RNA_def_property_enum_default(prop, 2);
|
||||
RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
static const EnumPropertyItem plane_depth_items[] = {
|
||||
{PLACE_DEPTH_SURFACE,
|
||||
"SURFACE",
|
||||
0,
|
||||
"Surface",
|
||||
"Start placing on the surface, using the 3D cursor position as a fallback"},
|
||||
{PLACE_DEPTH_CURSOR_PLANE,
|
||||
"CURSOR_PLANE",
|
||||
0,
|
||||
"3D Cursor Plane",
|
||||
"Start placement using a point projected onto the selected axis at the 3D cursor position"},
|
||||
{PLACE_DEPTH_CURSOR_VIEW,
|
||||
"CURSOR_VIEW",
|
||||
0,
|
||||
"3D Cursor View",
|
||||
"Start placement using the mouse cursor projected onto the view plane"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor");
|
||||
RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE);
|
||||
RNA_def_property_enum_items(prop, plane_depth_items);
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
static const EnumPropertyItem origin_items[] = {
|
||||
{PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"},
|
||||
{PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
|
||||
RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE);
|
||||
RNA_def_property_enum_items(prop, origin_items);
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
/* When not accessed via a tool. */
|
||||
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Placement Gizmo Group
|
||||
*
|
||||
* This is currently only used for snapping before the tool is initialized,
|
||||
* we could show a placement plane here.
|
||||
* \{ */
|
||||
|
||||
static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
|
||||
{
|
||||
wmGizmo *gizmo;
|
||||
|
||||
{
|
||||
/* The gizmo snap has to be the first gizmo. */
|
||||
const wmGizmoType *gzt_snap;
|
||||
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
|
||||
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
|
||||
RNA_enum_set(gizmo->ptr,
|
||||
"snap_elements_force",
|
||||
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
|
||||
/* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
|
||||
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
|
||||
{
|
||||
gzgt->name = "Placement Widget";
|
||||
gzgt->idname = view3d_gzgt_placement_id;
|
||||
|
||||
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
|
||||
|
||||
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
|
||||
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
|
||||
|
||||
gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
|
||||
gzgt->setup = WIDGETGROUP_placement_setup;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
Reference in New Issue
Block a user