Manipulator: experimental lamp positioning tool
- New manipulator tracks lamps to position under cursor. - Works with multiple lamps, keeping relative offsets. - Holding Ctrl moves the lamp. - Access via manipulator or Shift-T. Code could be improved, but like to get feedback from users.
This commit is contained in:
parent
48adef4444
commit
459365443f
Notes:
blender-bot
2023-02-14 07:30:31 +01:00
Referenced by issue #52591, Eevee ERROR: 0:14: Invalid call of undeclared identifier 'texture3D' on MacPro
|
@ -300,6 +300,12 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
|
|||
layout.operator("object.randomize_transform")
|
||||
layout.operator("object.align")
|
||||
|
||||
# TODO: there is a strange context bug here.
|
||||
"""
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("object.transform_axis_target")
|
||||
"""
|
||||
|
||||
|
||||
# Armature EditMode extensions to Transform menu
|
||||
class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
|
||||
|
|
|
@ -55,6 +55,7 @@ void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
|
|||
void OBJECT_OT_origin_clear(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_visual_transform_apply(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_transform_apply(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
|
||||
|
||||
/* object_relations.c */
|
||||
|
|
|
@ -61,6 +61,7 @@ void ED_operatortypes_object(void)
|
|||
WM_operatortype_append(OBJECT_OT_origin_clear);
|
||||
WM_operatortype_append(OBJECT_OT_visual_transform_apply);
|
||||
WM_operatortype_append(OBJECT_OT_transform_apply);
|
||||
WM_operatortype_append(OBJECT_OT_transform_axis_target);
|
||||
WM_operatortype_append(OBJECT_OT_origin_set);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_mode_set);
|
||||
|
|
|
@ -39,10 +39,12 @@
|
|||
#include "DNA_scene_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_array.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
|
@ -72,6 +74,8 @@
|
|||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "object_intern.h"
|
||||
|
||||
/*************************** Clear Transformation ****************************/
|
||||
|
@ -1124,3 +1128,385 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
|
|||
ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
|
||||
RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEAN, "Center", "");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Transform Axis Target
|
||||
*
|
||||
* Note this is an experemental operator to point lamps/cameras at objects.
|
||||
* We may re-work how this behaves based on user feedback.
|
||||
* - campbell.
|
||||
* \{ */
|
||||
|
||||
/* When using multiple objects, apply their relative rotational offset to the active object. */
|
||||
#define USE_RELATIVE_ROTATION
|
||||
|
||||
struct XFormAxisItem {
|
||||
Object *ob;
|
||||
float rot_mat[3][3];
|
||||
void *obtfm;
|
||||
float xform_dist;
|
||||
|
||||
#ifdef USE_RELATIVE_ROTATION
|
||||
/* use when translating multiple */
|
||||
float xform_rot_offset[3][3];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct XFormAxisData {
|
||||
ViewContext vc;
|
||||
struct {
|
||||
float depth;
|
||||
float normal[3];
|
||||
bool is_depth_valid;
|
||||
bool is_normal_valid;
|
||||
} prev;
|
||||
|
||||
struct XFormAxisItem *object_data;
|
||||
uint object_data_len;
|
||||
bool is_translate;
|
||||
|
||||
int init_event;
|
||||
};
|
||||
|
||||
static bool object_is_target_compat(const Object *ob)
|
||||
{
|
||||
if (ob->type == OB_LAMP) {
|
||||
const Lamp *la = ob->data;
|
||||
if (ELEM(la->type, LA_SUN, LA_SPOT, LA_HEMI, LA_AREA)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* We might want to enable this later, for now just lamps */
|
||||
#if 0
|
||||
else if (ob->type == OB_CAMERA) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static void object_transform_axis_target_free_data(wmOperator *op)
|
||||
{
|
||||
struct XFormAxisData *xfd = op->customdata;
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
MEM_freeN(item->obtfm);
|
||||
}
|
||||
MEM_freeN(xfd->object_data);
|
||||
MEM_freeN(xfd);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
/* We may want to expose as alternative to: BKE_object_apply_rotation */
|
||||
static void object_apply_rotation(Object *ob, const float rmat[3][3])
|
||||
{
|
||||
float size[3];
|
||||
float loc[3];
|
||||
float rmat4[4][4];
|
||||
copy_m4_m3(rmat4, rmat);
|
||||
|
||||
copy_v3_v3(size, ob->size);
|
||||
copy_v3_v3(loc, ob->loc);
|
||||
BKE_object_apply_mat4(ob, rmat4, true, true);
|
||||
copy_v3_v3(ob->size, size);
|
||||
copy_v3_v3(ob->loc, loc);
|
||||
}
|
||||
/* We may want to extract this to: BKE_object_apply_location */
|
||||
static void object_apply_location(Object *ob, const float loc[3])
|
||||
{
|
||||
/* quick but weak */
|
||||
Object ob_prev = *ob;
|
||||
float mat[4][4];
|
||||
copy_m4_m4(mat, ob->obmat);
|
||||
copy_v3_v3(mat[3], loc);
|
||||
BKE_object_apply_mat4(ob, mat, true, true);
|
||||
copy_v3_v3(mat[3], ob->loc);
|
||||
*ob = ob_prev;
|
||||
copy_v3_v3(ob->loc, mat[3]);
|
||||
}
|
||||
|
||||
static void object_orient_to_location(
|
||||
Object *ob, float rot_orig[3][3], const float axis[3], const float location[3])
|
||||
{
|
||||
float delta[3];
|
||||
sub_v3_v3v3(delta, ob->obmat[3], location);
|
||||
if (normalize_v3(delta) != 0.0f) {
|
||||
if (len_squared_v3v3(delta, axis) > FLT_EPSILON) {
|
||||
float delta_rot[3][3];
|
||||
float final_rot[3][3];
|
||||
rotation_between_vecs_to_mat3(delta_rot, axis, delta);
|
||||
|
||||
mul_m3_m3m3(final_rot, delta_rot, rot_orig);
|
||||
|
||||
object_apply_rotation(ob, final_rot);
|
||||
|
||||
DEG_id_tag_update(&ob->id, OB_RECALC_OB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
struct XFormAxisData *xfd = op->customdata;
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
BKE_object_tfm_restore(item->ob, item->obtfm);
|
||||
DEG_id_tag_update(&item->ob->id, OB_RECALC_OB);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
|
||||
}
|
||||
|
||||
object_transform_axis_target_free_data(op);
|
||||
}
|
||||
|
||||
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ViewContext vc;
|
||||
view3d_set_viewcontext(C, &vc);
|
||||
|
||||
if (!object_is_target_compat(vc.obact)) {
|
||||
/* Falls back to texture space transform. */
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
ED_view3d_autodist_init(C, vc.depsgraph, vc.ar, vc.v3d, 0);
|
||||
|
||||
if (vc.rv3d->depths != NULL) {
|
||||
vc.rv3d->depths->damaged = true;
|
||||
}
|
||||
ED_view3d_depth_update(vc.ar);
|
||||
|
||||
if (vc.rv3d->depths == NULL) {
|
||||
BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(vc.ar);
|
||||
|
||||
struct XFormAxisData *xfd;
|
||||
xfd = op->customdata = MEM_callocN(sizeof(struct XFormAxisData), __func__);
|
||||
|
||||
/* Don't change this at runtime. */
|
||||
xfd->vc = vc;
|
||||
xfd->vc.mval[0] = event->mval[0];
|
||||
xfd->vc.mval[1] = event->mval[1];
|
||||
|
||||
xfd->prev.depth = 1.0f;
|
||||
xfd->prev.is_depth_valid = false;
|
||||
xfd->prev.is_normal_valid = false;
|
||||
xfd->is_translate = false;
|
||||
|
||||
xfd->init_event = WM_userdef_event_type_from_keymap_type(event->type);
|
||||
|
||||
{
|
||||
struct XFormAxisItem *object_data = NULL;
|
||||
BLI_array_declare(object_data);
|
||||
|
||||
struct XFormAxisItem *item = BLI_array_append_ret(object_data);
|
||||
item->ob = xfd->vc.obact;
|
||||
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
|
||||
{
|
||||
if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) {
|
||||
item = BLI_array_append_ret(object_data);
|
||||
item->ob = ob;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
xfd->object_data = object_data;
|
||||
xfd->object_data_len = BLI_array_count(object_data);
|
||||
|
||||
if (xfd->object_data_len != BLI_array_count(object_data)) {
|
||||
xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
item->obtfm = BKE_object_tfm_backup(item->ob);
|
||||
BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
|
||||
}
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
struct XFormAxisData *xfd = op->customdata;
|
||||
ARegion *ar = xfd->vc.ar;
|
||||
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
const bool is_translate = (event->ctrl != 0);
|
||||
const bool is_translate_init = is_translate && (xfd->is_translate != is_translate);
|
||||
|
||||
if (event->type == MOUSEMOVE || is_translate_init) {
|
||||
const ViewDepths *depths = xfd->vc.rv3d->depths;
|
||||
if (depths &&
|
||||
((unsigned int)event->mval[0] < depths->w) &&
|
||||
((unsigned int)event->mval[1] < depths->h))
|
||||
{
|
||||
double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval);
|
||||
float location_world[3];
|
||||
if (depth == 1.0f) {
|
||||
if (xfd->prev.is_depth_valid) {
|
||||
depth = (double)xfd->prev.depth;
|
||||
}
|
||||
}
|
||||
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
|
||||
xfd->prev.depth = depth;
|
||||
xfd->prev.is_depth_valid = true;
|
||||
if (ED_view3d_depth_unproject(ar, event->mval, depth, location_world)) {
|
||||
if (is_translate) {
|
||||
|
||||
float normal[3];
|
||||
bool normal_found = false;
|
||||
if (ED_view3d_depth_read_cached_normal(&xfd->vc, event->mval, normal)) {
|
||||
normal_found = true;
|
||||
|
||||
/* cheap attempt to smooth normals out a bit! */
|
||||
const uint ofs = 2;
|
||||
for (uint x = -ofs; x <= ofs; x += ofs / 2) {
|
||||
for (uint y = -ofs; y <= ofs; y += ofs / 2) {
|
||||
if (x != 0 && y != 0) {
|
||||
int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y};
|
||||
float n[3];
|
||||
if (ED_view3d_depth_read_cached_normal(
|
||||
&xfd->vc, mval_ofs, n))
|
||||
{
|
||||
add_v3_v3(normal, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
normalize_v3(normal);
|
||||
}
|
||||
else if (xfd->prev.is_normal_valid) {
|
||||
copy_v3_v3(normal, xfd->prev.normal);
|
||||
normal_found = true;
|
||||
}
|
||||
|
||||
if (normal_found) {
|
||||
#ifdef USE_RELATIVE_ROTATION
|
||||
if (is_translate_init && xfd->object_data_len > 1) {
|
||||
float xform_rot_offset_inv_first[3][3];
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
copy_m3_m4(item->xform_rot_offset, item->ob->obmat);
|
||||
normalize_m3(item->xform_rot_offset);
|
||||
|
||||
if (i == 0) {
|
||||
invert_m3_m3(xform_rot_offset_inv_first, xfd->object_data[0].xform_rot_offset);
|
||||
}
|
||||
else {
|
||||
mul_m3_m3m3(item->xform_rot_offset,
|
||||
item->xform_rot_offset,
|
||||
xform_rot_offset_inv_first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
if (is_translate_init) {
|
||||
float ob_axis[3];
|
||||
item->xform_dist = len_v3v3(item->ob->obmat[3], location_world);
|
||||
normalize_v3_v3(ob_axis, item->ob->obmat[2]);
|
||||
/* Scale to avoid adding distance when moving between surfaces. */
|
||||
float scale = fabsf(dot_v3v3(ob_axis, normal));
|
||||
item->xform_dist *= scale;
|
||||
}
|
||||
|
||||
float target_normal[3];
|
||||
copy_v3_v3(target_normal, normal);
|
||||
|
||||
#ifdef USE_RELATIVE_ROTATION
|
||||
if (i != 0) {
|
||||
mul_m3_v3(item->xform_rot_offset, target_normal);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
float loc[3];
|
||||
|
||||
copy_v3_v3(loc, location_world);
|
||||
madd_v3_v3fl(loc, target_normal, item->xform_dist);
|
||||
object_apply_location(item->ob, loc);
|
||||
copy_v3_v3(item->ob->obmat[3], loc); /* so orient behaves as expected */
|
||||
}
|
||||
|
||||
object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
|
||||
}
|
||||
copy_v3_v3(xfd->prev.normal, normal);
|
||||
xfd->prev.is_normal_valid = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct XFormAxisItem *item = xfd->object_data;
|
||||
for (int i = 0; i < xfd->object_data_len; i++, item++) {
|
||||
object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
|
||||
}
|
||||
xfd->prev.is_normal_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xfd->is_translate = is_translate;
|
||||
|
||||
ED_region_tag_redraw(xfd->vc.ar);
|
||||
}
|
||||
|
||||
bool is_finished = false;
|
||||
|
||||
if (ISMOUSE(xfd->init_event)) {
|
||||
if ((event->type == xfd->init_event) && (event->val == KM_RELEASE)) {
|
||||
is_finished = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ELEM(event->type, LEFTMOUSE, RETKEY, PADENTER)) {
|
||||
is_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_finished) {
|
||||
object_transform_axis_target_free_data(op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
|
||||
object_transform_axis_target_cancel(C, op);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void OBJECT_OT_transform_axis_target(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Interactive Lamp Track to Cursor";
|
||||
ot->description = "Interactively point cameras and lamps to a location (Ctrl translates)";
|
||||
ot->idname = "OBJECT_OT_transform_axis_target";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = object_transform_axis_target_invoke;
|
||||
ot->cancel = object_transform_axis_target_cancel;
|
||||
ot->modal = object_transform_axis_target_modal;
|
||||
ot->poll = ED_operator_region_view3d_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
||||
}
|
||||
|
||||
#undef USE_RELATIVE_ROTATION
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -737,6 +737,7 @@ static void view3d_widgets(void)
|
|||
WM_manipulatorgrouptype_append_and_link(mmap_type, TRANSFORM_WGT_manipulator);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_lamp_spot);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_lamp_area);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_lamp_target);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_force_field);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_camera);
|
||||
WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_camera_view);
|
||||
|
|
|
@ -321,6 +321,7 @@ extern const char *view3d_context_dir[]; /* doc access */
|
|||
/* view3d_widgets.c */
|
||||
void VIEW3D_WGT_lamp_spot (struct wmManipulatorGroupType *wgt);
|
||||
void VIEW3D_WGT_lamp_area (struct wmManipulatorGroupType *wgt);
|
||||
void VIEW3D_WGT_lamp_target (struct wmManipulatorGroupType *wgt);
|
||||
void VIEW3D_WGT_camera (struct wmManipulatorGroupType *wgt);
|
||||
void VIEW3D_WGT_camera_view (struct wmManipulatorGroupType *wgt);
|
||||
void VIEW3D_WGT_force_field (struct wmManipulatorGroupType *wgt);
|
||||
|
|
|
@ -50,8 +50,6 @@
|
|||
/** \name Spot Lamp Manipulators
|
||||
* \{ */
|
||||
|
||||
/* Spot Lamp */
|
||||
|
||||
static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
@ -122,8 +120,6 @@ void VIEW3D_WGT_lamp_spot(wmManipulatorGroupType *wgt)
|
|||
/** \name Area Lamp Manipulators
|
||||
* \{ */
|
||||
|
||||
/* Area Lamp */
|
||||
|
||||
/* translate callbacks */
|
||||
static void manipulator_area_lamp_prop_size_get(
|
||||
const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
|
||||
|
@ -231,3 +227,71 @@ void VIEW3D_WGT_lamp_area(wmManipulatorGroupType *wgt)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Lamp Target Manipulator
|
||||
* \{ */
|
||||
|
||||
static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
if (ob != NULL) {
|
||||
if (ob->type == OB_LAMP) {
|
||||
Lamp *la = ob->data;
|
||||
return (ELEM(la->type, LA_SUN, LA_SPOT, LA_HEMI, LA_AREA));
|
||||
}
|
||||
else if (ob->type == OB_CAMERA) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_lamp_target_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
|
||||
{
|
||||
const float color[4] = {1.0f, 1.0f, 0.5f, 1.0f};
|
||||
const float color_hi[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__);
|
||||
wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL);
|
||||
wmManipulator *mpr = wwrapper->manipulator;
|
||||
|
||||
mgroup->customdata = wwrapper;
|
||||
|
||||
WM_manipulator_set_color(mpr, color);
|
||||
WM_manipulator_set_color_highlight(mpr, color_hi);
|
||||
|
||||
mpr->scale_basis = 0.05f;
|
||||
|
||||
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_transform_axis_target", true);
|
||||
WM_manipulator_set_operator(mpr, ot, NULL);
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_lamp_target_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
|
||||
{
|
||||
wmManipulatorWrapper *wwrapper = mgroup->customdata;
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
wmManipulator *mpr = wwrapper->manipulator;
|
||||
|
||||
copy_m4_m4(mpr->matrix_basis, ob->obmat);
|
||||
unit_m4(mpr->matrix_offset);
|
||||
mpr->matrix_offset[3][2] = -2.4f / mpr->scale_basis;
|
||||
}
|
||||
|
||||
void VIEW3D_WGT_lamp_target(wmManipulatorGroupType *wgt)
|
||||
{
|
||||
wgt->name = "Target Lamp Widgets";
|
||||
wgt->idname = "VIEW3D_WGT_lamp_target";
|
||||
|
||||
wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
|
||||
WM_MANIPULATORGROUPTYPE_3D);
|
||||
|
||||
wgt->poll = WIDGETGROUP_lamp_target_poll;
|
||||
wgt->setup = WIDGETGROUP_lamp_target_setup;
|
||||
wgt->draw_prepare = WIDGETGROUP_lamp_target_draw_prepare;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -1050,6 +1050,8 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
|
|||
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
|
||||
RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element");
|
||||
|
||||
/* Will fall-through to texture-space transform. */
|
||||
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_transform_axis_target", TKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, OP_TRANSLATION, TKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "texture_space", true);
|
||||
|
|
Loading…
Reference in New Issue