diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 11 | ||||
-rw-r--r-- | source/blender/editors/include/ED_sculpt.h | 5 | ||||
-rw-r--r-- | source/blender/editors/include/ED_transform.h | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 365 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 15 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 7 | ||||
-rw-r--r-- | source/blender/editors/transform/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.c | 14 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert.c | 7 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert.h | 2 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert_sculpt.c | 101 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 9 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_gizmo_3d.c | 13 |
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]); } |