2020-04-03 19:42:48 +02:00
|
|
|
/*
|
|
|
|
* 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
|
2020-05-09 17:14:35 +10:00
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2020-04-03 19:42:48 +02:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2020 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
* \ingroup edsculpt
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#include "BLI_task.h"
|
|
|
|
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
|
|
|
#include "BKE_brush.h"
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_mesh_mapping.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_paint.h"
|
|
|
|
#include "BKE_pbvh.h"
|
|
|
|
#include "BKE_scene.h"
|
|
|
|
|
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_message.h"
|
|
|
|
#include "WM_toolsystem.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "ED_object.h"
|
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_sculpt.h"
|
|
|
|
#include "paint_intern.h"
|
|
|
|
#include "sculpt_intern.h"
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "bmesh.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2021-02-11 12:34:41 +11:00
|
|
|
void ED_sculpt_init_transform(struct bContext *C, Object *ob)
|
2020-04-03 19:42:48 +02:00
|
|
|
{
|
|
|
|
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
|
|
|
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);
|
2020-11-26 00:37:56 +01:00
|
|
|
copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
|
|
|
|
|
|
|
|
copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
|
|
|
|
copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
|
|
|
|
copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
2020-11-12 10:41:33 +01:00
|
|
|
SCULPT_undo_push_begin(ob, "Transform");
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
ss->pivot_rot[3] = 1.0f;
|
|
|
|
|
2020-08-11 02:12:08 +02:00
|
|
|
SCULPT_vertex_random_access_ensure(ss);
|
2020-08-17 18:47:00 +02:00
|
|
|
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
|
2020-11-26 00:37:56 +01:00
|
|
|
|
|
|
|
ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sculpt_transform_matrices_init(SculptSession *ss,
|
|
|
|
const char symm,
|
|
|
|
const SculptTransformDisplacementMode t_mode,
|
|
|
|
float r_transform_mats[8][4][4])
|
|
|
|
{
|
|
|
|
|
|
|
|
float final_pivot_pos[3], d_t[3], d_r[4], d_s[3];
|
|
|
|
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];
|
|
|
|
|
|
|
|
float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3];
|
|
|
|
switch (t_mode) {
|
|
|
|
case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
|
|
|
|
copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
|
|
|
|
copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
|
|
|
|
copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
|
|
|
|
break;
|
|
|
|
case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
|
|
|
|
copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos);
|
|
|
|
copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot);
|
|
|
|
copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
|
|
|
|
ePaintSymmetryAreas v_symm = 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, start_pivot_pos);
|
|
|
|
SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, 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, start_pivot_rot);
|
|
|
|
normalize_qt(d_r);
|
|
|
|
SCULPT_flip_quat_by_symm_area(d_r, symm, v_symm, ss->init_pivot_pos);
|
|
|
|
quat_to_mat4(r_mat, d_r);
|
|
|
|
|
|
|
|
/* Scale matrix. */
|
|
|
|
sub_v3_v3v3(d_s, ss->pivot_scale, start_pivot_scale);
|
|
|
|
add_v3_fl(d_s, 1.0f);
|
|
|
|
size_to_mat4(s_mat, d_s);
|
|
|
|
|
|
|
|
/* Pivot matrix. */
|
|
|
|
SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, start_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(r_transform_mats[i], transform_mat, pivot_imat);
|
|
|
|
mul_m4_m4m4(r_transform_mats[i], pivot_mat, r_transform_mats[i]);
|
|
|
|
}
|
2020-04-03 19:42:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-03-12 22:20:51 +01:00
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
2020-04-03 19:42:48 +02:00
|
|
|
SCULPT_orig_vert_data_update(&orig_data, &vd);
|
|
|
|
float transformed_co[3], orig_co[3], disp[3];
|
2020-11-26 00:37:56 +01:00
|
|
|
float *start_co;
|
2020-04-03 19:42:48 +02:00
|
|
|
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);
|
|
|
|
|
2020-11-26 00:37:56 +01:00
|
|
|
switch (ss->filter_cache->transform_displacement_mode) {
|
|
|
|
case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
|
|
|
|
start_co = orig_co;
|
|
|
|
break;
|
|
|
|
case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
|
|
|
|
start_co = vd.co;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
copy_v3_v3(transformed_co, start_co);
|
2020-04-03 19:42:48 +02:00
|
|
|
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
|
2020-11-26 00:37:56 +01:00
|
|
|
sub_v3_v3v3(disp, transformed_co, start_co);
|
2020-04-03 19:42:48 +02:00
|
|
|
mul_v3_fl(disp, 1.0f - fade);
|
2020-11-26 00:37:56 +01:00
|
|
|
add_v3_v3v3(vd.co, start_co, disp);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
if (vd.mvert) {
|
|
|
|
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
|
|
|
|
BKE_pbvh_node_mark_update(node);
|
|
|
|
}
|
|
|
|
|
2020-11-26 00:37:56 +01:00
|
|
|
static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
|
2020-04-03 19:42:48 +02:00
|
|
|
{
|
|
|
|
SculptSession *ss = ob->sculpt;
|
2020-09-18 19:58:48 +02:00
|
|
|
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
SculptThreadedTaskData data = {
|
|
|
|
.sd = sd,
|
|
|
|
.ob = ob,
|
|
|
|
.nodes = ss->filter_cache->nodes,
|
|
|
|
};
|
|
|
|
|
2020-11-26 00:37:56 +01:00
|
|
|
sculpt_transform_matrices_init(
|
|
|
|
ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
2020-12-07 13:24:58 +11:00
|
|
|
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
|
|
|
|
* (each vertex can only be transformed once by the transform matrix of its area). */
|
2020-04-30 07:59:23 +02:00
|
|
|
TaskParallelSettings settings;
|
2020-06-29 18:16:15 +02:00
|
|
|
BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode);
|
2020-04-30 07:59:23 +02:00
|
|
|
BLI_task_parallel_range(
|
2020-04-03 19:42:48 +02:00
|
|
|
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
|
2020-11-26 00:37:56 +01:00
|
|
|
}
|
|
|
|
|
2021-02-11 12:34:41 +11:00
|
|
|
void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
|
2020-11-26 00:37:56 +01:00
|
|
|
{
|
|
|
|
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
|
|
|
SculptSession *ss = ob->sculpt;
|
|
|
|
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
|
|
|
|
|
|
|
SCULPT_vertex_random_access_ensure(ss);
|
|
|
|
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
|
|
|
|
|
|
|
|
sculpt_transform_all_vertices(sd, ob);
|
|
|
|
|
|
|
|
copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
|
|
|
|
copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
|
|
|
|
copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
if (ss->deform_modifiers_active || ss->shapekey_active) {
|
|
|
|
SCULPT_flush_stroke_deform(sd, ob, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
|
|
|
|
}
|
|
|
|
|
2021-02-11 12:34:41 +11:00
|
|
|
void ED_sculpt_end_transform(struct bContext *C, Object *ob)
|
2020-04-03 19:42:48 +02:00
|
|
|
{
|
|
|
|
SculptSession *ss = ob->sculpt;
|
|
|
|
if (ss->filter_cache) {
|
|
|
|
SCULPT_filter_cache_free(ss);
|
|
|
|
}
|
|
|
|
/* Force undo push to happen even inside transform operator, since the sculpt
|
|
|
|
* undo system works separate from regular undo and this is require to properly
|
2020-06-16 16:50:23 +10:00
|
|
|
* finish an undo step also when canceling. */
|
2020-04-03 19:42:48 +02:00
|
|
|
const bool use_nested_undo = true;
|
|
|
|
SCULPT_undo_push_end_ex(use_nested_undo);
|
|
|
|
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
static 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,
|
2020-12-24 11:07:32 -06:00
|
|
|
"Mask Border",
|
2020-04-03 19:42:48 +02:00
|
|
|
"Sets the pivot position to the center of the border of the mask"},
|
|
|
|
{SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
|
|
|
|
"ACTIVE",
|
|
|
|
0,
|
2020-12-24 11:07:32 -06:00
|
|
|
"Active Vertex",
|
2020-04-03 19:42:48 +02:00
|
|
|
"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_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
SculptSession *ss = ob->sculpt;
|
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2020-09-18 19:58:48 +02:00
|
|
|
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
int mode = RNA_enum_get(op->ptr, "mode");
|
|
|
|
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false);
|
2020-04-03 19:42:48 +02:00
|
|
|
|
|
|
|
/* Pivot to center. */
|
|
|
|
if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
|
|
|
|
zero_v3(ss->pivot_pos);
|
|
|
|
}
|
|
|
|
/* Pivot to active vertex. */
|
|
|
|
else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
|
|
|
|
copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
|
|
|
|
}
|
|
|
|
/* Pivot to raycast surface. */
|
|
|
|
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
|
|
|
|
float stroke_location[3];
|
|
|
|
float mouse[2];
|
|
|
|
mouse[0] = RNA_float_get(op->ptr, "mouse_x");
|
|
|
|
mouse[1] = RNA_float_get(op->ptr, "mouse_y");
|
|
|
|
if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
|
|
|
|
copy_v3_v3(ss->pivot_pos, stroke_location);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PBVHNode **nodes;
|
|
|
|
int totnode;
|
|
|
|
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
|
|
|
|
|
|
|
|
float avg[3];
|
|
|
|
int total = 0;
|
|
|
|
zero_v3(avg);
|
|
|
|
|
|
|
|
/* Pivot to unmasked. */
|
|
|
|
if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
|
|
|
|
for (int n = 0; n < totnode; n++) {
|
|
|
|
PBVHVertexIter vd;
|
2021-03-12 22:20:51 +01:00
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
2020-04-03 19:42:48 +02:00
|
|
|
const float mask = (vd.mask) ? *vd.mask : 0.0f;
|
|
|
|
if (mask < 1.0f) {
|
|
|
|
if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
|
|
|
|
add_v3_v3(avg, vd.co);
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Pivot to mask border. */
|
|
|
|
else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
|
|
|
|
const float threshold = 0.2f;
|
|
|
|
|
|
|
|
for (int n = 0; n < totnode; n++) {
|
|
|
|
PBVHVertexIter vd;
|
2021-03-12 22:20:51 +01:00
|
|
|
BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
|
2020-04-03 19:42:48 +02:00
|
|
|
const float mask = (vd.mask) ? *vd.mask : 0.0f;
|
|
|
|
if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
|
|
|
|
if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
|
|
|
|
add_v3_v3(avg, vd.co);
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BKE_pbvh_vertex_iter_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (total > 0) {
|
|
|
|
mul_v3_fl(avg, 1.0f / total);
|
|
|
|
copy_v3_v3(ss->pivot_pos, avg);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2020-08-20 16:01:35 +02:00
|
|
|
/* Update the viewport navigation rotation origin. */
|
|
|
|
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
|
|
|
|
copy_v3_v3(ups->average_stroke_accum, ss->pivot_pos);
|
|
|
|
ups->average_stroke_counter = 1;
|
|
|
|
ups->last_stroke_valid = true;
|
|
|
|
|
2020-04-03 19:42:48 +02:00
|
|
|
ED_region_tag_redraw(region);
|
|
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
|
|
|
|
RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
|
|
|
|
return sculpt_set_pivot_position_exec(C, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
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->exec = sculpt_set_pivot_position_exec;
|
|
|
|
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",
|
|
|
|
"");
|
|
|
|
|
|
|
|
RNA_def_float(ot->srna,
|
|
|
|
"mouse_x",
|
|
|
|
0.0f,
|
|
|
|
0.0f,
|
|
|
|
FLT_MAX,
|
|
|
|
"Mouse Position X",
|
|
|
|
"Position of the mouse used for \"Surface\" mode",
|
|
|
|
0.0f,
|
|
|
|
10000.0f);
|
|
|
|
RNA_def_float(ot->srna,
|
|
|
|
"mouse_y",
|
|
|
|
0.0f,
|
|
|
|
0.0f,
|
|
|
|
FLT_MAX,
|
|
|
|
"Mouse Position Y",
|
|
|
|
"Position of the mouse used for \"Surface\" mode",
|
|
|
|
0.0f,
|
|
|
|
10000.0f);
|
|
|
|
}
|