Fix #141017: Rotation snapping increment is wrong after changing mode
After changing the transform mode, `initSnapping` was called, resetting the increment values. The solution is to create the `transform_snap_reset_from_mode` function with only the changes needed when changing modes. This commit also makes the properties set in the operator take priority over the scene properties.
This commit is contained in:
@@ -1102,7 +1102,7 @@ wmOperatorStatus transformEvent(TransInfo *t, wmOperator *op, const wmEvent *eve
|
||||
}
|
||||
|
||||
/* Need to reinitialize after mode change. */
|
||||
initSnapping(t, nullptr);
|
||||
transform_snap_reset_from_mode(t, op);
|
||||
applyMouseInput(t, &t->mouse, t->mval, t->values);
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
break;
|
||||
|
||||
@@ -750,60 +750,72 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
|
||||
return SCE_SNAP_TO_INCREMENT;
|
||||
}
|
||||
|
||||
static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t)
|
||||
static eSnapTargetOP snap_target_select_from_spacetype_and_tool_settings(TransInfo *t)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
|
||||
Base *base_act = BKE_view_layer_active_base_get(t->view_layer);
|
||||
|
||||
eSnapTargetOP ret = SCE_SNAP_TARGET_ALL;
|
||||
|
||||
/* `t->tsnap.target_operation` not initialized yet. */
|
||||
BLI_assert(t->tsnap.target_operation == SCE_SNAP_TARGET_ALL);
|
||||
|
||||
eSnapTargetOP r_target_operation = SCE_SNAP_TARGET_ALL;
|
||||
|
||||
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
|
||||
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
|
||||
Base *base_act = BKE_view_layer_active_base_get(t->view_layer);
|
||||
const int obedit_type = t->obedit_type;
|
||||
if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
|
||||
/* Particles edit mode. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
|
||||
else if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) {
|
||||
/* In "Edit Strokes" mode,
|
||||
* snap tool can perform snap to selected or active objects (see #49632)
|
||||
* TODO: perform self snap in gpencil_strokes.
|
||||
*
|
||||
* When we're moving the origins, allow snapping onto our own geometry (see #69132). */
|
||||
return ret;
|
||||
}
|
||||
|
||||
const int obedit_type = t->obedit_type;
|
||||
if (obedit_type != -1) {
|
||||
else if (obedit_type != -1) {
|
||||
/* Edit mode. */
|
||||
if (obedit_type == OB_MESH) {
|
||||
/* Editing a mesh. */
|
||||
if ((t->flag & T_PROP_EDIT) != 0) {
|
||||
/* Exclude editmesh when using proportional edit. */
|
||||
ret |= SCE_SNAP_TARGET_NOT_EDITED;
|
||||
r_target_operation |= SCE_SNAP_TARGET_NOT_EDITED;
|
||||
}
|
||||
/* UV editing must never snap to the selection as this is what is transformed. */
|
||||
if (t->spacetype == SPACE_IMAGE) {
|
||||
ret |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
r_target_operation |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
}
|
||||
}
|
||||
else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
|
||||
/* Temporary limited to edit mode armature, curves, surfaces, lattices, and meta-balls. */
|
||||
ret |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
/* Temporary limited to edit mode armature, curves, surfaces, lattices, and meta-balls.
|
||||
*/
|
||||
r_target_operation |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Object or pose mode. */
|
||||
ret |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE;
|
||||
r_target_operation |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE;
|
||||
}
|
||||
}
|
||||
else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
|
||||
ret |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
r_target_operation |= SCE_SNAP_TARGET_NOT_SELECTED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* Use scene defaults only when transform is modal. */
|
||||
if (t->flag & T_MODAL) {
|
||||
ToolSettings *ts = t->settings;
|
||||
SET_FLAG_FROM_TEST(
|
||||
r_target_operation, (ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE), SCE_SNAP_TARGET_NOT_ACTIVE);
|
||||
SET_FLAG_FROM_TEST(r_target_operation,
|
||||
!(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED),
|
||||
SCE_SNAP_TARGET_NOT_EDITED);
|
||||
SET_FLAG_FROM_TEST(r_target_operation,
|
||||
!(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED),
|
||||
SCE_SNAP_TARGET_NOT_NONEDITED);
|
||||
SET_FLAG_FROM_TEST(r_target_operation,
|
||||
(ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE),
|
||||
SCE_SNAP_TARGET_ONLY_SELECTABLE);
|
||||
}
|
||||
|
||||
return r_target_operation;
|
||||
}
|
||||
|
||||
static void snap_object_context_init(TransInfo *t)
|
||||
@@ -834,6 +846,12 @@ static void initSnappingMode(TransInfo *t)
|
||||
/* In this case, snapping is always disabled by default. */
|
||||
t->modifiers &= ~MOD_SNAP;
|
||||
}
|
||||
else if (t->flag & T_MODAL) {
|
||||
/* Use scene defaults only when transform is modal. */
|
||||
if (t->tsnap.flag & SCE_SNAP) {
|
||||
t->modifiers |= MOD_SNAP;
|
||||
}
|
||||
}
|
||||
|
||||
if (doForceIncrementSnap(t)) {
|
||||
t->tsnap.mode = SCE_SNAP_TO_INCREMENT;
|
||||
@@ -847,21 +865,6 @@ static void initSnappingMode(TransInfo *t)
|
||||
if (t->tsnap.mode & SCE_SNAP_TO_EDGE_PERPENDICULAR) {
|
||||
t->flag |= T_DRAW_SNAP_SOURCE;
|
||||
}
|
||||
|
||||
setSnappingCallback(t);
|
||||
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
if (t->tsnap.object_context == nullptr) {
|
||||
SET_FLAG_FROM_TEST(t->tsnap.flag, snap_use_backface_culling(t), SCE_SNAP_BACKFACE_CULLING);
|
||||
t->tsnap.object_context = snap_object_context_create(t->scene, 0);
|
||||
snap_object_context_init(t);
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_SEQ) {
|
||||
if (t->tsnap.seq_context == nullptr) {
|
||||
t->tsnap.seq_context = snap_sequencer_data_alloc(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transform_snap_grid_init(const TransInfo *t, float r_snap[3], float *r_snap_precision)
|
||||
@@ -902,125 +905,123 @@ void transform_snap_grid_init(const TransInfo *t, float r_snap[3], float *r_snap
|
||||
}
|
||||
}
|
||||
|
||||
void initSnapping(TransInfo *t, wmOperator *op)
|
||||
void transform_snap_reset_from_mode(TransInfo *t, wmOperator *op)
|
||||
{
|
||||
ToolSettings *ts = t->settings;
|
||||
eSnapSourceOP snap_source = eSnapSourceOP(ts->snap_target);
|
||||
|
||||
resetSnapping(t);
|
||||
|
||||
t->tsnap.mode = snap_mode_from_spacetype(t);
|
||||
t->tsnap.flag = snap_flag_from_spacetype(t);
|
||||
t->tsnap.target_operation = snap_target_select_from_spacetype(t);
|
||||
t->tsnap.target_operation = snap_target_select_from_spacetype_and_tool_settings(t);
|
||||
t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1);
|
||||
|
||||
/* If snap property exists. */
|
||||
initSnappingMode(t);
|
||||
|
||||
/* Overwrite defaults with values in properties. */
|
||||
PropertyRNA *prop;
|
||||
if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
if (RNA_property_boolean_get(op->ptr, prop)) {
|
||||
t->modifiers |= MOD_SNAP;
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
t->tsnap.mode = eSnapMode(RNA_property_enum_get(op->ptr, prop));
|
||||
}
|
||||
|
||||
/* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
|
||||
* "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
|
||||
* geometry is snapped). */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
snap_source = eSnapSourceOP(RNA_property_enum_get(op->ptr, prop));
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
RNA_property_float_get_array(op->ptr, prop, t->tsnap.snap_target);
|
||||
t->modifiers |= MOD_SNAP_FORCED;
|
||||
t->tsnap.status |= SNAP_TARGET_FOUND;
|
||||
}
|
||||
|
||||
/* Snap align only defined in specific cases. */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(
|
||||
t->tsnap.flag, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_ROTATE);
|
||||
|
||||
RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
|
||||
normalize_v3(t->tsnap.snapNormal);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(
|
||||
t->tsnap.mode, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_INDIVIDUAL_PROJECT);
|
||||
}
|
||||
|
||||
/* Use_snap_self is misnamed and should be use_snap_active. */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_ACTIVE);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_EDITED);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_NONEDITED);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_ONLY_SELECTABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Use scene defaults only when transform is modal. */
|
||||
else if (t->flag & T_MODAL) {
|
||||
if (t->tsnap.flag & SCE_SNAP) {
|
||||
t->modifiers |= MOD_SNAP;
|
||||
if (op && (prop = RNA_struct_find_property(op->ptr, "snap"))) {
|
||||
if (RNA_property_is_set(op->ptr, prop)) {
|
||||
SET_FLAG_FROM_TEST(t->modifiers, RNA_property_boolean_get(op->ptr, prop), MOD_SNAP);
|
||||
}
|
||||
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
(ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE),
|
||||
SCE_SNAP_TARGET_NOT_ACTIVE);
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED),
|
||||
SCE_SNAP_TARGET_NOT_EDITED);
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED),
|
||||
SCE_SNAP_TARGET_NOT_NONEDITED);
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
(ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE),
|
||||
SCE_SNAP_TARGET_ONLY_SELECTABLE);
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
t->tsnap.mode = eSnapMode(RNA_property_enum_get(op->ptr, prop));
|
||||
}
|
||||
|
||||
/* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
|
||||
* "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
|
||||
* geometry is snapped). */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
snap_source = eSnapSourceOP(RNA_property_enum_get(op->ptr, prop));
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
RNA_property_float_get_array(op->ptr, prop, t->tsnap.snap_target);
|
||||
t->modifiers |= MOD_SNAP_FORCED;
|
||||
t->tsnap.status |= SNAP_TARGET_FOUND;
|
||||
}
|
||||
|
||||
/* Snap align only defined in specific cases. */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.flag, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_ROTATE);
|
||||
|
||||
RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
|
||||
normalize_v3(t->tsnap.snapNormal);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(
|
||||
t->tsnap.mode, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_INDIVIDUAL_PROJECT);
|
||||
}
|
||||
|
||||
/* Use_snap_self is misnamed and should be use_snap_active. */
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_ACTIVE);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_EDITED);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
!RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_NOT_NONEDITED);
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) &&
|
||||
RNA_property_is_set(op->ptr, prop))
|
||||
{
|
||||
SET_FLAG_FROM_TEST(t->tsnap.target_operation,
|
||||
RNA_property_boolean_get(op->ptr, prop),
|
||||
SCE_SNAP_TARGET_ONLY_SELECTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
t->tsnap.source_operation = snap_source;
|
||||
|
||||
initSnappingMode(t);
|
||||
transform_snap_grid_init(t, t->snap_spatial, &t->snap_spatial_precision);
|
||||
transform_snap_flag_from_modifiers_set(t);
|
||||
}
|
||||
|
||||
void initSnapping(TransInfo *t, wmOperator *op)
|
||||
{
|
||||
transform_snap_reset_from_mode(t, op);
|
||||
transform_snap_grid_init(t, t->snap_spatial, &t->snap_spatial_precision);
|
||||
setSnappingCallback(t);
|
||||
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
if (t->tsnap.object_context == nullptr) {
|
||||
SET_FLAG_FROM_TEST(t->tsnap.flag, snap_use_backface_culling(t), SCE_SNAP_BACKFACE_CULLING);
|
||||
t->tsnap.object_context = snap_object_context_create(t->scene, 0);
|
||||
snap_object_context_init(t);
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_SEQ) {
|
||||
if (t->tsnap.seq_context == nullptr) {
|
||||
t->tsnap.seq_context = snap_sequencer_data_alloc(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default increment values. */
|
||||
t->increment = float3(1.0f);
|
||||
@@ -1046,15 +1047,23 @@ void initSnapAngleIncrements(TransInfo *t)
|
||||
/* The final value of increment with precision is `t->increment[0] * t->increment_precision`.
|
||||
* Therefore, we divide `snap_angle_increment_*_precision` by `snap_angle_increment_*`
|
||||
* to compute `increment_precision`. */
|
||||
float increment;
|
||||
float increment_precision;
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
t->increment[0] = t->settings->snap_angle_increment_3d;
|
||||
t->increment_precision = t->settings->snap_angle_increment_3d_precision /
|
||||
t->settings->snap_angle_increment_3d;
|
||||
increment = t->settings->snap_angle_increment_3d;
|
||||
increment_precision = t->settings->snap_angle_increment_3d_precision;
|
||||
}
|
||||
else {
|
||||
t->increment[0] = t->settings->snap_angle_increment_2d;
|
||||
t->increment_precision = t->settings->snap_angle_increment_2d_precision /
|
||||
t->settings->snap_angle_increment_2d;
|
||||
increment = t->settings->snap_angle_increment_2d;
|
||||
increment_precision = t->settings->snap_angle_increment_2d_precision;
|
||||
}
|
||||
|
||||
t->increment[0] = increment;
|
||||
if (increment != 0.0f) {
|
||||
t->increment_precision = float(double(increment_precision) / double(increment));
|
||||
}
|
||||
else {
|
||||
t->increment_precision = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1469,7 +1478,7 @@ static void snap_source_closest_fn(TransInfo *t)
|
||||
/* Object mode. */
|
||||
if (t->options & CTX_OBJECT) {
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
BLI_assert(tc->sorted_index_map);
|
||||
BLI_assert(tc->sorted_index_map || !(t->flag & T_PROP_EDIT_ALL));
|
||||
tc->foreach_index_selected([&](const int i) {
|
||||
TransData *td = &tc->data[i];
|
||||
|
||||
@@ -1524,7 +1533,7 @@ static void snap_source_closest_fn(TransInfo *t)
|
||||
}
|
||||
else {
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
BLI_assert(tc->sorted_index_map);
|
||||
BLI_assert(tc->sorted_index_map || !(t->flag & T_PROP_EDIT_ALL));
|
||||
tc->foreach_index_selected([&](const int i) {
|
||||
TransData *td = &tc->data[i];
|
||||
|
||||
@@ -1696,7 +1705,9 @@ static void snap_increment_apply(const TransInfo *t, const float loc[3], float r
|
||||
for (int i = 0; i <= t->idx_max; i++) {
|
||||
const float iter_fac = use_precision ? t->increment[i] * t->increment_precision :
|
||||
t->increment[i];
|
||||
r_out[i] = iter_fac * roundf(loc[i] / iter_fac);
|
||||
if (iter_fac != 0.0f) {
|
||||
r_out[i] = iter_fac * roundf(loc[i] / iter_fac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ bool transform_snap_is_active(const TransInfo *t);
|
||||
bool validSnap(const TransInfo *t);
|
||||
|
||||
void transform_snap_grid_init(const TransInfo *t, float r_snap[3], float *r_snap_precision);
|
||||
void transform_snap_reset_from_mode(TransInfo *t, wmOperator *op);
|
||||
void initSnapping(TransInfo *t, wmOperator *op);
|
||||
void freeSnapping(TransInfo *t);
|
||||
void initSnapAngleIncrements(TransInfo *t);
|
||||
|
||||
Reference in New Issue
Block a user