Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.c
| Show First 20 Lines • Show All 2,825 Lines • ▼ Show 20 Lines | SculptThreadedTaskData data = { | ||||
| .offset = offset, | .offset = offset, | ||||
| }; | }; | ||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | ||||
| BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); | BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); | ||||
| } | } | ||||
| void SCULPT_stroke_local_space_matrix_init(float r_mat[4][4], | |||||
| const float location[3], | |||||
| const float normal[3], | |||||
| const float delta[3]) | |||||
| { | |||||
| cross_v3_v3v3(r_mat[0], normal, delta); | |||||
| r_mat[0][3] = 0.0f; | |||||
| cross_v3_v3v3(r_mat[1], normal, r_mat[0]); | |||||
| r_mat[1][3] = 0.0f; | |||||
| copy_v3_v3(r_mat[2], normal); | |||||
| r_mat[2][3] = 0.0f; | |||||
| copy_v3_v3(r_mat[3], location); | |||||
| r_mat[3][3] = 1.0f; | |||||
| normalize_m4(r_mat); | |||||
| } | |||||
| static void do_draw_sharp_pinch_perpendicular_brush_task_cb_ex( | |||||
| void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) | |||||
| { | |||||
| SculptThreadedTaskData *data = userdata; | |||||
| SculptSession *ss = data->ob->sculpt; | |||||
| const Brush *brush = data->brush; | |||||
| const float *offset = data->offset; | |||||
| float(*stroke_xz)[3] = data->stroke_xz; | |||||
| PBVHVertexIter vd; | |||||
| SculptOrigVertData orig_data; | |||||
| float(*proxy)[3]; | |||||
| const float bstrength = ss->cache->bstrength; | |||||
| SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); | |||||
| proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; | |||||
| SculptBrushTest test; | |||||
| SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( | |||||
| ss, &test, data->brush->falloff_shape); | |||||
| const int thread_id = BLI_task_parallel_thread_id(tls); | |||||
| float x_object_space[3]; | |||||
| float z_object_space[3]; | |||||
| copy_v3_v3(x_object_space, stroke_xz[0]); | |||||
| copy_v3_v3(z_object_space, stroke_xz[1]); | |||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | |||||
| { | |||||
| SCULPT_orig_vert_data_update(&orig_data, &vd); | |||||
| if (sculpt_brush_test_sq_fn(&test, vd.co)) { | |||||
| const float fade = SCULPT_brush_strength_factor(ss, | |||||
| brush, | |||||
| vd.co, | |||||
| sqrtf(test.dist), | |||||
| vd.no, | |||||
| vd.fno, | |||||
| vd.mask ? *vd.mask : 0.0f, | |||||
| vd.index, | |||||
| thread_id); | |||||
| float disp_draw[3]; | |||||
| float disp_center[3]; | |||||
| float x_disp[3]; | |||||
| float z_disp[3]; | |||||
| mul_v3_v3fl(disp_draw, offset, fade); | |||||
| sub_v3_v3v3(disp_center, test.location, orig_data.co); | |||||
| mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space)); | |||||
| mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space)); | |||||
| add_v3_v3v3(disp_center, x_disp, z_disp); | |||||
| if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { | |||||
| project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal); | |||||
| } | |||||
| /* fabsf(fade) is used to always pinch towards the stroke whith the direction inverted. */ | |||||
| /* The pinch effect is also reduced to make the draw effect more visible. */ | |||||
| mul_v3_v3fl(proxy[vd.i], disp_center, fabsf(fade * brush->crease_pinch_factor * bstrength)); | |||||
| add_v3_v3(proxy[vd.i], disp_draw); | |||||
| if (vd.mvert) { | |||||
jbakker: Move this after the early breaks.
I didn't see that the first_time and grab_delta_symmetry is… | |||||
| vd.mvert->flag |= ME_VERT_PBVH_UPDATE; | |||||
| } | |||||
| } | |||||
| } | |||||
| BKE_pbvh_vertex_iter_end; | |||||
| } | |||||
| static void do_draw_sharp_pinch_perpendicular( | |||||
| SculptThreadedTaskData *data, Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode) | |||||
| { | |||||
| SculptSession *ss = ob->sculpt; | |||||
| float area_no[3]; | |||||
Done Inline ActionsThere are already 5 places using exactly the same code. Please add a function for this. jbakker: There are already 5 places using exactly the same code. Please add a function for this. | |||||
| float area_co[3]; | |||||
| /* Delay the first daub because grab delta is not setup. */ | |||||
| if (ss->cache->first_time) { | |||||
| return; | |||||
| } | |||||
| if (is_zero_v3(ss->cache->grab_delta_symmetry)) { | |||||
| return; | |||||
| } | |||||
| float mat[4][4]; | |||||
| SCULPT_calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); | |||||
| SCULPT_stroke_local_space_matrix_init( | |||||
| mat, ss->cache->location, area_no, ss->cache->grab_delta_symmetry); | |||||
| float stroke_xz[2][3]; | |||||
| normalize_v3_v3(stroke_xz[0], mat[0]); | |||||
| normalize_v3_v3(stroke_xz[1], mat[2]); | |||||
| data->stroke_xz = stroke_xz; | |||||
| TaskParallelSettings settings; | |||||
| BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | |||||
| BLI_task_parallel_range( | |||||
| 0, totnode, data, do_draw_sharp_pinch_perpendicular_brush_task_cb_ex, &settings); | |||||
| } | |||||
| static void do_draw_sharp_pinch_radial_brush_task_cb_ex(void *__restrict userdata, | |||||
| const int n, | |||||
| const TaskParallelTLS *__restrict tls) | |||||
| { | |||||
| SculptThreadedTaskData *data = userdata; | |||||
| SculptSession *ss = data->ob->sculpt; | |||||
| const Brush *brush = data->brush; | |||||
| const float *offset = data->offset; | |||||
| SculptProjectVector *spvc = data->spvc; | |||||
| const float flippedbstrength = data->flippedbstrength; | |||||
| PBVHVertexIter vd; | |||||
| SculptOrigVertData orig_data; | |||||
| float(*proxy)[3]; | |||||
| SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); | |||||
| proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; | |||||
| SculptBrushTest test; | |||||
| SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( | |||||
| ss, &test, data->brush->falloff_shape); | |||||
| const int thread_id = BLI_task_parallel_thread_id(tls); | |||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | |||||
| { | |||||
| SCULPT_orig_vert_data_update(&orig_data, &vd); | |||||
| if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { | |||||
| /* Offset vertex. */ | |||||
| const float fade = SCULPT_brush_strength_factor(ss, | |||||
| brush, | |||||
| orig_data.co, | |||||
| sqrtf(test.dist), | |||||
| orig_data.no, | |||||
| NULL, | |||||
| vd.mask ? *vd.mask : 0.0f, | |||||
| vd.index, | |||||
| thread_id); | |||||
| float pinch_disp[3]; | |||||
| float draw_disp[3]; | |||||
| /* First we pinch. */ | |||||
| sub_v3_v3v3(pinch_disp, test.location, orig_data.co); | |||||
| if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { | |||||
| project_plane_v3_v3v3(pinch_disp, pinch_disp, ss->cache->view_normal); | |||||
| } | |||||
| mul_v3_fl(pinch_disp, fade * flippedbstrength); | |||||
| sculpt_project_v3(spvc, pinch_disp, pinch_disp); | |||||
| mul_v3_v3fl(proxy[vd.i], offset, fade); | |||||
| /* Then we draw. */ | |||||
| mul_v3_v3fl(draw_disp, offset, fade); | |||||
| add_v3_v3v3(proxy[vd.i], pinch_disp, draw_disp); | |||||
| if (vd.mvert) { | |||||
| vd.mvert->flag |= ME_VERT_PBVH_UPDATE; | |||||
| } | |||||
| } | |||||
| } | |||||
| BKE_pbvh_vertex_iter_end; | |||||
| } | |||||
| static void do_draw_sharp_pinch_radial(SculptThreadedTaskData *data, | |||||
| Sculpt *sd, | |||||
| Object *ob, | |||||
| const int totnode) | |||||
| { | |||||
| SculptSession *ss = ob->sculpt; | |||||
| Brush *brush = BKE_paint_brush(&sd->paint); | |||||
| const float bstrength = ss->cache->bstrength; | |||||
| const Scene *scene = ss->cache->vc->scene; | |||||
| float flippedbstrength, crease_correction; | |||||
| float brush_alpha; | |||||
| SculptProjectVector spvc; | |||||
| /* We divide out the squared alpha and multiply by the squared crease | |||||
| * to give us the pinch strength. */ | |||||
| crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor; | |||||
| brush_alpha = BKE_brush_alpha_get(scene, brush); | |||||
| if (brush_alpha > 0.0f) { | |||||
| crease_correction /= brush_alpha * brush_alpha; | |||||
| } | |||||
| /* we always want crease to pinch or blob to relax even when draw is negative */ | |||||
| flippedbstrength = (bstrength < 0) ? -crease_correction * bstrength : | |||||
| crease_correction * bstrength; | |||||
| if (brush->sculpt_tool == SCULPT_TOOL_BLOB) { | |||||
| flippedbstrength *= -1.0f; | |||||
| } | |||||
| sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm); | |||||
| data->spvc = &spvc; | |||||
| data->flippedbstrength = flippedbstrength; | |||||
| TaskParallelSettings settings; | |||||
| BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | |||||
| BLI_task_parallel_range( | |||||
| 0, totnode, data, do_draw_sharp_pinch_radial_brush_task_cb_ex, &settings); | |||||
| } | |||||
| static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, | static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, | ||||
| const int n, | const int n, | ||||
| const TaskParallelTLS *__restrict tls) | const TaskParallelTLS *__restrict tls) | ||||
| { | { | ||||
| SculptThreadedTaskData *data = userdata; | SculptThreadedTaskData *data = userdata; | ||||
| SculptSession *ss = data->ob->sculpt; | SculptSession *ss = data->ob->sculpt; | ||||
| const Brush *brush = data->brush; | const Brush *brush = data->brush; | ||||
| const float *offset = data->offset; | const float *offset = data->offset; | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .sd = sd, | .sd = sd, | ||||
| .ob = ob, | .ob = ob, | ||||
| .brush = brush, | .brush = brush, | ||||
| .nodes = nodes, | .nodes = nodes, | ||||
| .offset = offset, | .offset = offset, | ||||
| }; | }; | ||||
| switch (brush->draw_sharp_deform_type) { | |||||
| case BRUSH_DRAW_SHARP_DEFORM_DRAW: { | |||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); | ||||
| BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); | BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); | ||||
| } break; | |||||
| case BRUSH_DRAW_SHARP_DEFORM_PINCH_RADIAL: | |||||
| do_draw_sharp_pinch_radial(&data, sd, ob, totnode); | |||||
| break; | |||||
| case BRUSH_DRAW_SHARP_DEFORM_PINCH_PERPENDICULAR: | |||||
| do_draw_sharp_pinch_perpendicular(&data, sd, ob, nodes, totnode); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Sculpt Topology Brush | /** \name Sculpt Topology Brush | ||||
| * \{ */ | * \{ */ | ||||
| static void do_topology_slide_task_cb_ex(void *__restrict userdata, | static void do_topology_slide_task_cb_ex(void *__restrict userdata, | ||||
| ▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Lines | for (int i = 0; i < 4; i++) { | ||||
| BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); | BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); | BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); | ||||
| } | } | ||||
| } | } | ||||
| static void calc_sculpt_plane( | void SCULPT_calc_sculpt_plane( | ||||
| Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) | Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) | ||||
| { | { | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| Brush *brush = BKE_paint_brush(&sd->paint); | Brush *brush = BKE_paint_brush(&sd->paint); | ||||
| if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 && | if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 && | ||||
| ss->cache->tile_pass == 0 && | ss->cache->tile_pass == 0 && | ||||
| (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) || | (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) || | ||||
| ▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | |||||
| static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) | static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) | ||||
| { | { | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| Brush *brush = BKE_paint_brush(&sd->paint); | Brush *brush = BKE_paint_brush(&sd->paint); | ||||
| float area_no[3]; | float area_no[3]; | ||||
| float area_co[3]; | float area_co[3]; | ||||
| float mat[4][4]; | |||||
| calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); | |||||
| /* delay the first daub because grab delta is not setup */ | /* delay the first daub because grab delta is not setup */ | ||||
| if (ss->cache->first_time) { | if (ss->cache->first_time) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (is_zero_v3(ss->cache->grab_delta_symmetry)) { | if (is_zero_v3(ss->cache->grab_delta_symmetry)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Init mat */ | float mat[4][4]; | ||||
| cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); | SCULPT_calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); | ||||
| mat[0][3] = 0.0f; | SCULPT_stroke_local_space_matrix_init( | ||||
| cross_v3_v3v3(mat[1], area_no, mat[0]); | mat, ss->cache->location, area_no, ss->cache->grab_delta_symmetry); | ||||
| mat[1][3] = 0.0f; | |||||
| copy_v3_v3(mat[2], area_no); | |||||
| mat[2][3] = 0.0f; | |||||
| copy_v3_v3(mat[3], ss->cache->location); | |||||
| mat[3][3] = 1.0f; | |||||
| normalize_m4(mat); | |||||
| float stroke_xz[2][3]; | float stroke_xz[2][3]; | ||||
| normalize_v3_v3(stroke_xz[0], mat[0]); | normalize_v3_v3(stroke_xz[0], mat[0]); | ||||
| normalize_v3_v3(stroke_xz[1], mat[2]); | normalize_v3_v3(stroke_xz[1], mat[2]); | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .sd = sd, | .sd = sd, | ||||
| .ob = ob, | .ob = ob, | ||||
| ▲ Show 20 Lines • Show All 1,254 Lines • ▼ Show 20 Lines | if (is_zero_v3(ss->cache->grab_delta_symmetry)) { | ||||
| return; | return; | ||||
| } | } | ||||
| mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); | mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); | ||||
| mul_v3_fl(temp, displace); | mul_v3_fl(temp, displace); | ||||
| add_v3_v3(area_co, temp); | add_v3_v3(area_co, temp); | ||||
| /* Init brush local space matrix. */ | /* Init brush local space matrix. */ | ||||
| cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); | SCULPT_stroke_local_space_matrix_init( | ||||
| mat[0][3] = 0.0f; | mat, ss->cache->location, area_no, ss->cache->grab_delta_symmetry); | ||||
| cross_v3_v3v3(mat[1], area_no, mat[0]); | |||||
| mat[1][3] = 0.0f; | |||||
| copy_v3_v3(mat[2], area_no); | |||||
| mat[2][3] = 0.0f; | |||||
| copy_v3_v3(mat[3], ss->cache->location); | |||||
| mat[3][3] = 1.0f; | |||||
| normalize_m4(mat); | |||||
| /* Scale brush local space matrix. */ | /* Scale brush local space matrix. */ | ||||
| scale_m4_fl(scale, ss->cache->radius); | scale_m4_fl(scale, ss->cache->radius); | ||||
| mul_m4_m4m4(tmat, mat, scale); | mul_m4_m4m4(tmat, mat, scale); | ||||
| invert_m4_m4(mat, tmat); | invert_m4_m4(mat, tmat); | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| .sd = sd, | .sd = sd, | ||||
| ▲ Show 20 Lines • Show All 331 Lines • ▼ Show 20 Lines | static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) | ||||
| /* Displace the brush planes. */ | /* Displace the brush planes. */ | ||||
| copy_v3_v3(area_co, ss->cache->location); | copy_v3_v3(area_co, ss->cache->location); | ||||
| mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); | mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); | ||||
| mul_v3_fl(temp, displace); | mul_v3_fl(temp, displace); | ||||
| add_v3_v3(area_co, temp); | add_v3_v3(area_co, temp); | ||||
| /* Init brush local space matrix. */ | /* Init brush local space matrix. */ | ||||
| cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); | SCULPT_stroke_local_space_matrix_init( | ||||
| mat[0][3] = 0.0f; | mat, ss->cache->location, area_no, ss->cache->grab_delta_symmetry); | ||||
| cross_v3_v3v3(mat[1], area_no, mat[0]); | |||||
| mat[1][3] = 0.0f; | |||||
| copy_v3_v3(mat[2], area_no); | |||||
| mat[2][3] = 0.0f; | |||||
| copy_v3_v3(mat[3], ss->cache->location); | |||||
| mat[3][3] = 1.0f; | |||||
| normalize_m4(mat); | |||||
| /* Scale brush local space matrix. */ | /* Scale brush local space matrix. */ | ||||
| scale_m4_fl(scale, ss->cache->radius); | scale_m4_fl(scale, ss->cache->radius); | ||||
| mul_m4_m4m4(tmat, mat, scale); | mul_m4_m4m4(tmat, mat, scale); | ||||
| invert_m4_m4(mat, tmat); | invert_m4_m4(mat, tmat); | ||||
| float clay_strength = ss->cache->bstrength * | float clay_strength = ss->cache->bstrength * | ||||
| sculpt_clay_thumb_get_stabilized_pressure(ss->cache); | sculpt_clay_thumb_get_stabilized_pressure(ss->cache); | ||||
| ▲ Show 20 Lines • Show All 1,212 Lines • ▼ Show 20 Lines | static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush) | ||||
| if (ELEM(tool, | if (ELEM(tool, | ||||
| SCULPT_TOOL_GRAB, | SCULPT_TOOL_GRAB, | ||||
| SCULPT_TOOL_ELASTIC_DEFORM, | SCULPT_TOOL_ELASTIC_DEFORM, | ||||
| SCULPT_TOOL_CLOTH, | SCULPT_TOOL_CLOTH, | ||||
| SCULPT_TOOL_NUDGE, | SCULPT_TOOL_NUDGE, | ||||
| SCULPT_TOOL_CLAY_STRIPS, | SCULPT_TOOL_CLAY_STRIPS, | ||||
| SCULPT_TOOL_PINCH, | SCULPT_TOOL_PINCH, | ||||
| SCULPT_TOOL_DRAW_SHARP, | |||||
| SCULPT_TOOL_MULTIPLANE_SCRAPE, | SCULPT_TOOL_MULTIPLANE_SCRAPE, | ||||
| SCULPT_TOOL_CLAY_THUMB, | SCULPT_TOOL_CLAY_THUMB, | ||||
| SCULPT_TOOL_SNAKE_HOOK, | SCULPT_TOOL_SNAKE_HOOK, | ||||
| SCULPT_TOOL_POSE, | SCULPT_TOOL_POSE, | ||||
| SCULPT_TOOL_THUMB) || | SCULPT_TOOL_THUMB) || | ||||
| sculpt_brush_use_topology_rake(ss, brush)) { | sculpt_brush_use_topology_rake(ss, brush)) { | ||||
| float grab_location[3], imat[4][4], delta[3], loc[3]; | float grab_location[3], imat[4][4], delta[3], loc[3]; | ||||
| ▲ Show 20 Lines • Show All 1,627 Lines • Show Last 20 Lines | |||||
Move this after the early breaks.
I didn't see that the first_time and grab_delta_symmetry is changed by this function.