Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py5
-rw-r--r--source/blender/blenkernel/BKE_paint.h11
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_transform.h1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c365
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h15
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c7
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.c14
-rw-r--r--source/blender/editors/transform/transform_convert.c7
-rw-r--r--source/blender/editors/transform/transform_convert.h2
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c101
-rw-r--r--source/blender/editors/transform/transform_generics.c9
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c13
14 files changed, 548 insertions, 8 deletions
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 8ec2733ff34..de05a357211 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1986,6 +1986,11 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_sculpt.mesh_filter,
None,
+ _defs_transform.translate,
+ _defs_transform.rotate,
+ _defs_transform.scale,
+ _defs_transform.transform,
+ None,
*_tools_annotate,
],
'PAINT_TEXTURE': [
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index ed4bcee3541..5ce16e8b906 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -267,12 +267,19 @@ typedef struct SculptSession {
float cursor_view_normal[3];
struct RegionView3D *rv3d;
- float pivot_pos[3];
-
/* Dynamic mesh preview */
int *preview_vert_index_list;
int preview_vert_index_count;
+ /* Transform operator */
+ float pivot_pos[3];
+ float pivot_rot[4];
+ float pivot_scale[3];
+
+ float init_pivot_pos[3];
+ float init_pivot_rot[4];
+ float init_pivot_scale[3];
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index d907ba4e581..0273c8c73ab 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -39,6 +39,11 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
+/* transform */
+void ED_sculpt_update_modal_transform(struct bContext *C);
+void ED_sculpt_init_transform(struct bContext *C);
+void ED_sculpt_end_transform(struct bContext *C);
+
/* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index d8b65aa5975..8c70fc9a157 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -94,6 +94,7 @@ enum TfmMode {
#define CTX_OBMODE_XFORM_OBDATA (1 << 11)
/** Transform object parents without moving their children. */
#define CTX_OBMODE_XFORM_SKIP_CHILDREN (1 << 12)
+#define CTX_SCULPT (1 << 13)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 44927a3052b..6235b60ea74 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -8737,7 +8737,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
for (int i = 0; i < vertex_count; i++) {
if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
- check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
+ check_vertex_pivot_symmetry(
+ sculpt_vertex_co_get(ss, i), ss->filter_cache->mask_expand_initial_co, symm)) {
total++;
add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
}
@@ -8859,6 +8860,9 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache->mask_update_current_it = 1;
ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)] = 1;
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co,
+ sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+
char *visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), original_normal);
@@ -9074,6 +9078,364 @@ void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
ss->preview_vert_index_count = totpoints;
}
+void ED_sculpt_init_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
+
+ ss->init_pivot_scale[0] = 1.0f;
+ ss->init_pivot_scale[1] = 1.0f;
+ ss->init_pivot_scale[2] = 1.0f;
+
+ ss->pivot_scale[0] = 1.0f;
+ ss->pivot_scale[1] = 1.0f;
+ ss->pivot_scale[2] = 1.0f;
+
+ sculpt_undo_push_begin("Transform");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ ss->pivot_rot[3] = 1.0f;
+
+ sculpt_vertex_random_access_init(ss);
+ sculpt_filter_cache_init(ob, sd);
+}
+
+typedef enum PaintSymmetryAreas {
+ AREA_SYMM_X = (1 << 0),
+ AREA_SYMM_Y = (1 << 1),
+ AREA_SYMM_Z = (1 << 2),
+} PaintSymmetryAreas;
+
+static char sculpt_get_vertex_symm_area(float co[3])
+{
+ float vco[3];
+ char symm_area = 0;
+ copy_v3_v3(vco, co);
+ if (vco[0] < 0) {
+ symm_area |= AREA_SYMM_X;
+ }
+ if (vco[1] < 0) {
+ symm_area |= AREA_SYMM_Y;
+ }
+ if (vco[2] < 0) {
+ symm_area |= AREA_SYMM_Z;
+ }
+ return symm_area;
+}
+
+static void flip_qt(float qt[4], char symm)
+{
+ float euler[3];
+ if (symm & PAINT_SYMM_X) {
+ quat_to_eul(euler, qt);
+ euler[1] = -euler[1];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Y) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[2] = -euler[2];
+ eul_to_quat(qt, euler);
+ }
+ if (symm & PAINT_SYMM_Z) {
+ quat_to_eul(euler, qt);
+ euler[0] = -euler[0];
+ euler[1] = -euler[1];
+ eul_to_quat(qt, euler);
+ }
+}
+
+static void sculpt_flip_transform_by_symm_area(
+ float disp[3], float rot[4], char symm, char symmarea, float pivot[3])
+{
+
+ for (char i = 0; i < 3; i++) {
+ char symm_it = 1 << i;
+ if (symm & symm_it) {
+ if (symmarea & symm_it) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ if (pivot[0] < 0) {
+ if (disp) {
+ flip_v3(disp, symm_it);
+ }
+ if (rot) {
+ flip_qt(rot, symm_it);
+ }
+ }
+ }
+ }
+}
+
+static void sculpt_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+ char symm_area = sculpt_get_vertex_symm_area(orig_co);
+
+ copy_v3_v3(transformed_co, orig_co);
+ mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
+ mul_v3_fl(disp, 1.0f - fade);
+
+ add_v3_v3v3(vd.co, orig_co, disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
+void ED_sculpt_update_modal_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ sculpt_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ float final_pivot_pos[3], d_t[3], d_r[4];
+ float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
+ transform_mat[4][4];
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+ for (int i = 0; i < 8; i++) {
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+
+ unit_m4(pivot_mat);
+
+ unit_m4(t_mat);
+ unit_m4(r_mat);
+ unit_m4(s_mat);
+
+ /* Translation matrix */
+ sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
+ sculpt_flip_transform_by_symm_area(d_t, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
+
+ /* Rotation matrix */
+ sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
+ normalize_qt(d_r);
+ sculpt_flip_transform_by_symm_area(NULL, d_r, symm, (char)i, ss->init_pivot_pos);
+ quat_to_mat4(r_mat, d_r);
+
+ /* Scale matrix */
+ size_to_mat4(s_mat, ss->pivot_scale);
+
+ /* Pivot matrix */
+ sculpt_flip_transform_by_symm_area(final_pivot_pos, NULL, symm, (char)i, ss->init_pivot_pos);
+ translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
+ invert_m4_m4(pivot_imat, pivot_mat);
+
+ /* Final transform matrix */
+ mul_m4_m4m4(transform_mat, r_mat, t_mat);
+ mul_m4_m4m4(transform_mat, transform_mat, s_mat);
+ mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
+ mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
+ }
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
+
+ if (ss->modifiers_active || ss->kb) {
+ sculpt_flush_stroke_deform(sd, ob, true);
+ }
+
+ sculpt_flush_update_step(C);
+}
+
+void ED_sculpt_end_transform(struct bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ if (ss->filter_cache) {
+ sculpt_filter_cache_free(ss);
+ }
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob);
+}
+
+typedef enum eSculptPivotPositionModes {
+ SCULPT_PIVOT_POSITION_ORIGIN = 0,
+ SCULPT_PIVOT_POSITION_UNMASKED = 1,
+ SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
+ SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
+ SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
+} eSculptPivotPositionModes;
+
+EnumPropertyItem prop_sculpt_pivot_position_types[] = {
+ {SCULPT_PIVOT_POSITION_ORIGIN,
+ "ORIGIN",
+ 0,
+ "Origin",
+ "Sets the pivot to the origin of the sculpt"},
+ {SCULPT_PIVOT_POSITION_UNMASKED,
+ "UNMASKED",
+ 0,
+ "Unmasked",
+ "Sets the pivot position to the average position of the unmasked vertices"},
+ {SCULPT_PIVOT_POSITION_MASK_BORDER,
+ "BORDER",
+ 0,
+ "Mask border",
+ "Sets the pivot position to the center of the border of the mask"},
+ {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
+ "ACTIVE",
+ 0,
+ "Active vertex",
+ "Sets the pivot position to the active vertex position"},
+ {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Sets the pivot position to the surface under the cursor"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+
+ int vert_count = sculpt_vertex_count_get(ss);
+
+ /* Pivot to center */
+ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
+ zero_v3(ss->pivot_pos);
+ }
+
+ /* Pivot to unmasked */
+ if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+ for (int i = 0; i < vert_count; i++) {
+ if (sculpt_vertex_mask_get(ss, i) < 1.0f &&
+ check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
+ total++;
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+ }
+ }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ }
+
+ /* Pivot to mask border */
+ if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ float avg[3];
+ int total = 0;
+ float threshold = 0.2f;
+ zero_v3(avg);
+ for (int i = 0; i < vert_count; i++) {
+ if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
+ sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
+ check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
+ total++;
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+ }
+ }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ }
+
+ /* Pivot to active vertex */
+ if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+ }
+
+ /* Pivot to raycast surface */
+ if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+
+ ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Pivot Position";
+ ot->idname = "SCULPT_OT_set_pivot_position";
+ ot->description = "Sets the sculpt transform pivot position";
+
+ /* api callbacks */
+ ot->invoke = sculpt_set_pivot_position_invoke;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_pivot_position_types,
+ SCULPT_PIVOT_POSITION_UNMASKED,
+ "Mode",
+ "");
+}
void ED_operatortypes_sculpt(void)
{
@@ -9090,4 +9452,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_mask_filter);
WM_operatortype_append(SCULPT_OT_dirty_mask);
WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 5995eadea59..b814e87fcb0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -122,6 +122,10 @@ typedef struct SculptUndoNode {
int geom_totloop;
int geom_totpoly;
+ /* pivot */
+ float pivot_pos[3];
+ float pivot_rot[4];
+
size_t undo_size;
} SculptUndoNode;
@@ -173,16 +177,16 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ int filter_type;
+ float filter_strength;
+ int *node_mask;
+
/* 0=towards view, 1=flipped */
float (*area_cos)[3];
float (*area_nos)[3];
int *count;
bool any_vertex_sampled;
- int filter_type;
- float filter_strength;
- int *node_mask;
-
float *prev_mask;
float *pose_origin;
@@ -198,6 +202,8 @@ typedef struct SculptThreadedTaskData {
bool mask_expand_use_normals;
bool mask_expand_keep_prev_mask;
+ float transform_mats[8][4][4];
+
ThreadMutex mutex;
} SculptThreadedTaskData;
@@ -387,6 +393,7 @@ typedef struct FilterCache {
int *mask_update_it;
float *normal_factor;
float *prev_mask;
+ float mask_expand_initial_co[3];
} FilterCache;
void sculpt_cache_calc_brushdata_symm(StrokeCache *cache,
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index cb8afd5d7fa..3783eb17562 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -494,6 +494,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
+ /* restore pivot */
+ copy_v3_v3(ss->pivot_pos, unode->pivot_pos);
+ copy_v3_v3(ss->pivot_rot, unode->pivot_rot);
if (STREQ(unode->idname, ob->id.name)) {
if (unode->type == SCULPT_UNDO_MASK) {
/* is possible that we can't do the mask undo (below)
@@ -1055,6 +1058,10 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
break;
}
+ /* store sculpt pivot */
+ copy_v3_v3(unode->pivot_pos, ss->pivot_pos);
+ copy_v3_v3(unode->pivot_rot, ss->pivot_rot);
+
/* store active shape key */
if (ss->kb) {
BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 210cc5cbca7..e3ff8b92081 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
transform_convert_object.c
transform_convert_paintcurve.c
transform_convert_particle.c
+ transform_convert_sculpt.c
transform_convert_sequencer.c
transform_convert_tracking.c
transform_generics.c
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 019db4f74fa..d3b331faca9 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -79,6 +79,7 @@
#include "ED_clip.h"
#include "ED_node.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -2299,6 +2300,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
+ if (t->options & CTX_SCULPT) {
+ ED_sculpt_end_transform(C);
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
RNA_property_boolean_set(
op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
@@ -2342,6 +2347,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
+ options |= CTX_SCULPT;
+ }
+
t->options = options;
t->mode = mode;
@@ -2404,6 +2414,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
createTransData(C, t); // make TransData structs from selection
+ if (t->options & CTX_SCULPT) {
+ ED_sculpt_init_transform(C);
+ }
+
if (t->data_len_all == 0) {
postTrans(C, t);
return 0;
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 6da03d917a6..dfdd7b71332 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -2264,6 +2264,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->options & CTX_PAINT_CURVE) {
/* pass */
}
+ else if (t->options & CTX_SCULPT) {
+ /* pass */
+ }
else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
(ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) {
/* do nothing */
@@ -2414,6 +2417,10 @@ void createTransData(bContext *C, TransInfo *t)
}
countAndCleanTransDataContainer(t);
}
+ else if (t->options & CTX_SCULPT) {
+ createTransSculpt(t);
+ countAndCleanTransDataContainer(t);
+ }
else if (t->options & CTX_TEXTURE) {
t->flag |= T_TEXTURE;
t->obedit_type = -1;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index ee6f181a133..02ad4688ab6 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -129,6 +129,8 @@ void createTransTexspace(TransInfo *t);
void createTransPaintCurveVerts(bContext *C, TransInfo *t);
/* transform_convert_particle.c */
void createTransParticleVerts(bContext *C, TransInfo *t);
+/* transform_convert_sculpt.c */
+void createTransSculpt(TransInfo *t);
/* transform_convert_sequence.c */
void createTransSeqData(bContext *C, TransInfo *t);
/* transform_convert_tracking.c */
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
new file mode 100644
index 00000000000..b02ad71da07
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_paint.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Transform Creation
+ *
+ * \{ */
+
+void createTransSculpt(TransInfo *t)
+{
+ TransData *td;
+
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
+ }
+
+ Object *ob = CTX_data_active_object(t->context);
+ SculptSession *ss = ob->sculpt;
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ tc->is_active = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
+
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ss->pivot_pos);
+ td->ob = NULL;
+
+ float tquat[4];
+ normalize_qt_qt(tquat, ss->pivot_rot);
+ quat_to_mat3(td->axismtx, tquat);
+
+ td->loc = ss->pivot_pos;
+ copy_v3_v3(td->iloc, ss->pivot_pos);
+
+ if (is_zero_v4(ss->pivot_rot)) {
+ ss->pivot_rot[3] = 1.0f;
+ }
+
+ td->ext->rot = NULL;
+ td->ext->rotAxis = NULL;
+ td->ext->rotAngle = NULL;
+ td->ext->quat = ss->pivot_rot;
+
+ copy_qt_qt(td->ext->iquat, ss->pivot_rot);
+ td->ext->rotOrder = ROT_MODE_QUAT;
+
+ ss->pivot_scale[0] = 1.0f;
+ ss->pivot_scale[1] = 1.0f;
+ ss->pivot_scale[2] = 1.0f;
+ td->ext->size = ss->pivot_scale;
+ copy_v3_v3(td->ext->isize, ss->pivot_scale);
+
+ float obmat_inv[3][3];
+ copy_m3_m4(obmat_inv, ob->obmat);
+ invert_m3(obmat_inv);
+ copy_m3_m3(td->smtx, obmat_inv);
+ copy_m3_m4(td->mtx, ob->obmat);
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index c4da7780a22..32d8c7381e7 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -99,6 +99,7 @@
#include "ED_clip.h"
#include "ED_screen.h"
#include "ED_gpencil.h"
+#include "ED_sculpt.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -1206,6 +1207,11 @@ static void recalcData_gpencil_strokes(TransInfo *t)
}
}
+static void recalcData_sculpt(TransInfo *t)
+{
+ ED_sculpt_update_modal_transform(t->context);
+}
+
/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
@@ -1226,6 +1232,9 @@ void recalcData(TransInfo *t)
/* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
+ if (t->options & CTX_SCULPT) {
+ recalcData_sculpt(t);
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 64fdbe5f8b1..bd8cf047db7 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -55,6 +55,7 @@
#include "BKE_scene.h"
#include "BKE_workspace.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "DEG_depsgraph.h"
@@ -1056,7 +1057,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- /* pass */
+ if (ob->mode & OB_MODE_SCULPT) {
+ totsel = 1;
+ calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat);
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
+ }
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
PTCacheEdit *edit = PE_get_current(scene, ob);
@@ -1168,6 +1175,10 @@ static void gizmo_prepare_mat(const bContext *C,
if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
/* pass */
}
+ else if (ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
+ }
else if (ob != NULL) {
ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
}