Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.c
| Show First 20 Lines • Show All 438 Lines • ▼ Show 20 Lines | |||||
| bool SCULPT_vertex_any_face_visible_get(SculptSession *ss, PBVHVertRef vertex) | bool SCULPT_vertex_any_face_visible_get(SculptSession *ss, PBVHVertRef vertex) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| case PBVH_FACES: { | case PBVH_FACES: { | ||||
| if (!ss->hide_poly) { | if (!ss->hide_poly) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| for (int j = 0; j < ss->pmap[vertex.i].count; j++) { | for (int j = 0; j < ss->pmap[vertex.i].count; j++) { | ||||
| if (!ss->hide_poly[vert_map->indices[j]]) { | if (!ss->hide_poly[vert_map->indices[j]]) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| case PBVH_BMESH: | case PBVH_BMESH: | ||||
| return true; | return true; | ||||
| case PBVH_GRIDS: | case PBVH_GRIDS: | ||||
| return true; | return true; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool SCULPT_vertex_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex) | bool SCULPT_vertex_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| case PBVH_FACES: { | case PBVH_FACES: { | ||||
| if (!ss->hide_poly) { | if (!ss->hide_poly) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| for (int j = 0; j < ss->pmap[vertex.i].count; j++) { | for (int j = 0; j < vert_map->count; j++) { | ||||
| if (ss->hide_poly[vert_map->indices[j]]) { | if (ss->hide_poly[vert_map->indices[j]]) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| case PBVH_BMESH: | case PBVH_BMESH: | ||||
| return true; | return true; | ||||
| Show All 10 Lines | bool SCULPT_vertex_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex) | ||||
| return true; | return true; | ||||
| } | } | ||||
| void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set) | void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| case PBVH_FACES: { | case PBVH_FACES: { | ||||
| BLI_assert(ss->face_sets != NULL); | BLI_assert(ss->face_sets != NULL); | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| for (int j = 0; j < ss->pmap[vertex.i].count; j++) { | for (int j = 0; j < vert_map->count; j++) { | ||||
| const int poly_index = vert_map->indices[j]; | const int poly_index = vert_map->indices[j]; | ||||
| if (ss->hide_poly && ss->hide_poly[poly_index]) { | if (ss->hide_poly && ss->hide_poly[poly_index]) { | ||||
| /* Skip hidden faces connected to the vertex. */ | /* Skip hidden faces connected to the vertex. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| ss->face_sets[poly_index] = face_set; | ss->face_sets[poly_index] = face_set; | ||||
| } | } | ||||
| break; | break; | ||||
| Show All 17 Lines | |||||
| int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) | int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| case PBVH_FACES: { | case PBVH_FACES: { | ||||
| if (!ss->face_sets) { | if (!ss->face_sets) { | ||||
| return SCULPT_FACE_SET_NONE; | return SCULPT_FACE_SET_NONE; | ||||
| } | } | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| int face_set = 0; | int face_set = 0; | ||||
| for (int i = 0; i < ss->pmap[vertex.i].count; i++) { | for (int i = 0; i < vert_map->count; i++) { | ||||
| if (ss->face_sets[vert_map->indices[i]] > face_set) { | if (ss->face_sets[vert_map->indices[i]] > face_set) { | ||||
| face_set = abs(ss->face_sets[vert_map->indices[i]]); | face_set = abs(ss->face_sets[vert_map->indices[i]]); | ||||
| } | } | ||||
| } | } | ||||
| return face_set; | return face_set; | ||||
| } | } | ||||
| case PBVH_BMESH: | case PBVH_BMESH: | ||||
| return 0; | return 0; | ||||
| Show All 12 Lines | |||||
| bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set) | bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| case PBVH_FACES: { | case PBVH_FACES: { | ||||
| if (!ss->face_sets) { | if (!ss->face_sets) { | ||||
| return face_set == SCULPT_FACE_SET_NONE; | return face_set == SCULPT_FACE_SET_NONE; | ||||
| } | } | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| for (int i = 0; i < ss->pmap[vertex.i].count; i++) { | for (int i = 0; i < vert_map->count; i++) { | ||||
| if (ss->face_sets[vert_map->indices[i]] == face_set) { | if (ss->face_sets[vert_map->indices[i]] == face_set) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| case PBVH_BMESH: | case PBVH_BMESH: | ||||
| return true; | return true; | ||||
| Show All 34 Lines | void SCULPT_visibility_sync_all_from_faces(Object *ob) | ||||
| } | } | ||||
| } | } | ||||
| static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index) | static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index) | ||||
| { | { | ||||
| if (!ss->face_sets) { | if (!ss->face_sets) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| MeshElemMap *vert_map = &ss->pmap[index]; | const MeshElemMap *vert_map = &ss->pmap[index]; | ||||
| int face_set = -1; | int face_set = -1; | ||||
| for (int i = 0; i < ss->pmap[index].count; i++) { | for (int i = 0; i < vert_map->count; i++) { | ||||
| if (face_set == -1) { | if (face_set == -1) { | ||||
| face_set = ss->face_sets[vert_map->indices[i]]; | face_set = ss->face_sets[vert_map->indices[i]]; | ||||
| } | } | ||||
| else { | else { | ||||
| if (ss->face_sets[vert_map->indices[i]] != face_set) { | if (ss->face_sets[vert_map->indices[i]] != face_set) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /** | /** | ||||
| * Checks if the face sets of the adjacent faces to the edge between \a v1 and \a v2 | * Checks if the face sets of the adjacent faces to the edge between \a v1 and \a v2 | ||||
| * in the base mesh are equal. | * in the base mesh are equal. | ||||
| */ | */ | ||||
| static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2) | static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2) | ||||
| { | { | ||||
| MeshElemMap *vert_map = &ss->pmap[v1]; | const MeshElemMap *vert_map = &ss->pmap[v1]; | ||||
| int p1 = -1, p2 = -1; | int p1 = -1, p2 = -1; | ||||
| for (int i = 0; i < ss->pmap[v1].count; i++) { | for (int i = 0; i < vert_map->count; i++) { | ||||
| const MPoly *p = &ss->mpoly[vert_map->indices[i]]; | const MPoly *p = &ss->mpoly[vert_map->indices[i]]; | ||||
| for (int l = 0; l < p->totloop; l++) { | for (int l = 0; l < p->totloop; l++) { | ||||
| const MLoop *loop = &ss->mloop[p->loopstart + l]; | const MLoop *loop = &ss->mloop[p->loopstart + l]; | ||||
| if (loop->v == v2) { | if (loop->v == v2) { | ||||
| if (p1 == -1) { | if (p1 == -1) { | ||||
| p1 = vert_map->indices[i]; | p1 = vert_map->indices[i]; | ||||
| break; | break; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, | static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, | ||||
| PBVHVertRef vertex, | PBVHVertRef vertex, | ||||
| SculptVertexNeighborIter *iter) | SculptVertexNeighborIter *iter) | ||||
| { | { | ||||
| MeshElemMap *vert_map = &ss->pmap[vertex.i]; | const MeshElemMap *vert_map = &ss->pmap[vertex.i]; | ||||
| iter->size = 0; | iter->size = 0; | ||||
| iter->num_duplicates = 0; | iter->num_duplicates = 0; | ||||
| iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; | iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; | ||||
| iter->neighbors = iter->neighbors_fixed; | iter->neighbors = iter->neighbors_fixed; | ||||
| iter->neighbor_indices = iter->neighbor_indices_fixed; | iter->neighbor_indices = iter->neighbor_indices_fixed; | ||||
| const bool *hide_poly = BKE_pbvh_get_vert_hide(ss->pbvh); | |||||
| for (int i = 0; i < ss->pmap[vertex.i].count; i++) { | for (int i = 0; i < vert_map->count; i++) { | ||||
| if (hide_poly && hide_poly[vert_map->indices[i]]) { | if (ss->hide_poly && ss->hide_poly[vert_map->indices[i]]) { | ||||
| /* Skip connectivity from hidden faces. */ | /* Skip connectivity from hidden faces. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| const MPoly *p = &ss->mpoly[vert_map->indices[i]]; | const MPoly *p = &ss->mpoly[vert_map->indices[i]]; | ||||
| uint f_adj_v[2]; | int f_adj_v[2]; | ||||
| if (poly_get_adj_loops_from_vert(p, ss->mloop, vertex.i, f_adj_v) != -1) { | if (poly_get_adj_loops_from_vert(p, ss->mloop, vertex.i, f_adj_v) != -1) { | ||||
| for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { | for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { | ||||
| if (f_adj_v[j] != vertex.i) { | if (f_adj_v[j] != vertex.i) { | ||||
| sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]); | sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 453 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) && | return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) && | ||||
| (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL); | (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL); | ||||
| } | } | ||||
| /** | /** | ||||
| * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action | * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action | ||||
| */ | */ | ||||
| static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush) | static int sculpt_brush_needs_normal(const SculptSession *ss, Sculpt *sd, const Brush *brush) | ||||
| { | { | ||||
| return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) && | return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) && | ||||
| (ss->cache->normal_weight > 0.0f)) || | (ss->cache->normal_weight > 0.0f)) || | ||||
| SCULPT_automasking_needs_normal(ss, sd, brush) || | |||||
| ELEM(brush->sculpt_tool, | ELEM(brush->sculpt_tool, | ||||
| SCULPT_TOOL_BLOB, | SCULPT_TOOL_BLOB, | ||||
| SCULPT_TOOL_CREASE, | SCULPT_TOOL_CREASE, | ||||
| SCULPT_TOOL_DRAW, | SCULPT_TOOL_DRAW, | ||||
| SCULPT_TOOL_DRAW_SHARP, | SCULPT_TOOL_DRAW_SHARP, | ||||
| SCULPT_TOOL_CLOTH, | SCULPT_TOOL_CLOTH, | ||||
| SCULPT_TOOL_LAYER, | SCULPT_TOOL_LAYER, | ||||
| SCULPT_TOOL_NUDGE, | SCULPT_TOOL_NUDGE, | ||||
| ▲ Show 20 Lines • Show All 1,124 Lines • ▼ Show 20 Lines | |||||
| float SCULPT_brush_strength_factor(SculptSession *ss, | float SCULPT_brush_strength_factor(SculptSession *ss, | ||||
| const Brush *br, | const Brush *br, | ||||
| const float brush_point[3], | const float brush_point[3], | ||||
| float len, | float len, | ||||
| const float vno[3], | const float vno[3], | ||||
| const float fno[3], | const float fno[3], | ||||
| float mask, | float mask, | ||||
| const PBVHVertRef vertex, | const PBVHVertRef vertex, | ||||
| int thread_id) | const int thread_id, | ||||
| AutomaskingNodeData *automask_data) | |||||
| { | { | ||||
| StrokeCache *cache = ss->cache; | StrokeCache *cache = ss->cache; | ||||
| const Scene *scene = cache->vc->scene; | const Scene *scene = cache->vc->scene; | ||||
| const MTex *mtex = &br->mtex; | const MTex *mtex = &br->mtex; | ||||
| float avg = 1.0f; | float avg = 1.0f; | ||||
| float rgba[4]; | float rgba[4]; | ||||
| float point[3]; | float point[3]; | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | float SCULPT_brush_strength_factor(SculptSession *ss, | ||||
| /* Falloff curve. */ | /* Falloff curve. */ | ||||
| avg *= BKE_brush_curve_strength(br, final_len, cache->radius); | avg *= BKE_brush_curve_strength(br, final_len, cache->radius); | ||||
| avg *= frontface(br, cache->view_normal, vno, fno); | avg *= frontface(br, cache->view_normal, vno, fno); | ||||
| /* Paint mask. */ | /* Paint mask. */ | ||||
| avg *= 1.0f - mask; | avg *= 1.0f - mask; | ||||
| /* Auto-masking. */ | /* Auto-masking. */ | ||||
| avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex); | avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex, automask_data); | ||||
| return avg; | return avg; | ||||
| } | } | ||||
| bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v) | bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v) | ||||
| { | { | ||||
| SculptSearchSphereData *data = data_v; | SculptSearchSphereData *data = data_v; | ||||
| const float *center; | const float *center; | ||||
| ▲ Show 20 Lines • Show All 573 Lines • ▼ Show 20 Lines | BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { | ||||
| const float fade = SCULPT_brush_strength_factor(ss, | const float fade = SCULPT_brush_strength_factor(ss, | ||||
| brush, | brush, | ||||
| vd.co, | vd.co, | ||||
| sqrtf(test.dist), | sqrtf(test.dist), | ||||
| vd.no, | vd.no, | ||||
| vd.fno, | vd.fno, | ||||
| vd.mask ? *vd.mask : 0.0f, | vd.mask ? *vd.mask : 0.0f, | ||||
| vd.vertex, | vd.vertex, | ||||
| thread_id); | thread_id, | ||||
| NULL); | |||||
| mul_v3_v3fl(proxy[vd.i], offset, fade); | mul_v3_v3fl(proxy[vd.i], offset, fade); | ||||
| if (vd.mvert) { | if (vd.mvert) { | ||||
| BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); | BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); | ||||
| } | } | ||||
| } | } | ||||
| BKE_pbvh_vertex_iter_end; | BKE_pbvh_vertex_iter_end; | ||||
| ▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | static void do_brush_action(Sculpt *sd, | ||||
| /* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no | /* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no | ||||
| * PBVH nodes on the first brush step. */ | * PBVH nodes on the first brush step. */ | ||||
| if (totnode || | if (totnode || | ||||
| ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { | ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { | ||||
| if (SCULPT_stroke_is_first_brush_step(ss->cache)) { | if (SCULPT_stroke_is_first_brush_step(ss->cache)) { | ||||
| /* Initialize auto-masking cache. */ | /* Initialize auto-masking cache. */ | ||||
| if (SCULPT_is_automasking_enabled(sd, ss, brush)) { | if (SCULPT_is_automasking_enabled(sd, ss, brush)) { | ||||
| ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); | ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); | ||||
| ss->last_automasking_settings_hash = SCULPT_automasking_settings_hash( | |||||
| ob, ss->cache->automasking); | |||||
| } | } | ||||
| /* Initialize surface smooth cache. */ | /* Initialize surface smooth cache. */ | ||||
| if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) && | if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) && | ||||
| (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) { | (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) { | ||||
| BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL); | BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL); | ||||
| ss->cache->surface_smooth_laplacian_disp = MEM_callocN( | ss->cache->surface_smooth_laplacian_disp = MEM_callocN( | ||||
| sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"); | sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"); | ||||
| } | } | ||||
| Show All 14 Lines | SculptThreadedTaskData task_data = { | ||||
| .nodes = nodes, | .nodes = nodes, | ||||
| }; | }; | ||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BKE_pbvh_parallel_range_settings(&settings, true, totnode); | BKE_pbvh_parallel_range_settings(&settings, true, totnode); | ||||
| BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); | BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); | ||||
| } | } | ||||
| if (sculpt_brush_needs_normal(ss, brush)) { | if (sculpt_brush_needs_normal(ss, sd, brush)) { | ||||
| update_sculpt_normal(sd, ob, nodes, totnode); | update_sculpt_normal(sd, ob, nodes, totnode); | ||||
| } | } | ||||
| if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) { | if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) { | ||||
| update_brush_local_mat(sd, ob); | update_brush_local_mat(sd, ob); | ||||
| } | } | ||||
| if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) { | if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) { | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | else { | ||||
| SCULPT_smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false); | SCULPT_smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false); | ||||
| } | } | ||||
| } | } | ||||
| if (sculpt_brush_use_topology_rake(ss, brush)) { | if (sculpt_brush_use_topology_rake(ss, brush)) { | ||||
| SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); | SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); | ||||
| } | } | ||||
| if (!SCULPT_tool_can_reuse_automask(brush->sculpt_tool) || | |||||
| (ss->cache->supports_gravity && sd->gravity_factor > 0.0f)) { | |||||
| /* Clear cavity mask cache. */ | |||||
| ss->last_automasking_settings_hash = 0; | |||||
| } | |||||
| /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ | /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ | ||||
| if (ss->cache->supports_gravity && !ELEM(brush->sculpt_tool, | if (ss->cache->supports_gravity && !ELEM(brush->sculpt_tool, | ||||
| SCULPT_TOOL_CLOTH, | SCULPT_TOOL_CLOTH, | ||||
| SCULPT_TOOL_DRAW_FACE_SETS, | SCULPT_TOOL_DRAW_FACE_SETS, | ||||
| SCULPT_TOOL_BOUNDARY)) { | SCULPT_TOOL_BOUNDARY)) { | ||||
| do_gravity(sd, ob, nodes, totnode, sd->gravity_factor); | do_gravity(sd, ob, nodes, totnode, sd->gravity_factor); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 777 Lines • ▼ Show 20 Lines | if (cache->supports_gravity) { | ||||
| normalize_v3(cache->true_gravity_direction); | normalize_v3(cache->true_gravity_direction); | ||||
| } | } | ||||
| /* Make copies of the mesh vertex locations and normals for some tools. */ | /* Make copies of the mesh vertex locations and normals for some tools. */ | ||||
| if (brush->flag & BRUSH_ANCHORED) { | if (brush->flag & BRUSH_ANCHORED) { | ||||
| cache->original = true; | cache->original = true; | ||||
| } | } | ||||
| if (SCULPT_automasking_needs_original(sd, brush)) { | |||||
| cache->original = true; | |||||
| } | |||||
| /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it | /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it | ||||
| * should work the opposite way. */ | * should work the opposite way. */ | ||||
| if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { | if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { | ||||
| cache->original = true; | cache->original = true; | ||||
| } | } | ||||
| if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) { | if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) { | ||||
| if (!(brush->flag & BRUSH_ACCUMULATE)) { | if (!(brush->flag & BRUSH_ACCUMULATE)) { | ||||
| ▲ Show 20 Lines • Show All 1,043 Lines • ▼ Show 20 Lines | if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) { | ||||
| if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT && | if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT && | ||||
| SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { | SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { | ||||
| ED_image_undo_push_begin(op->type->name, PAINT_MODE_SCULPT); | ED_image_undo_push_begin(op->type->name, PAINT_MODE_SCULPT); | ||||
| } | } | ||||
| else { | else { | ||||
| SCULPT_undo_push_begin_ex(ob, sculpt_tool_name(sd)); | SCULPT_undo_push_begin_ex(ob, sculpt_tool_name(sd)); | ||||
| } | } | ||||
| SCULPT_stroke_id_next(ob); | |||||
| ss->cache->stroke_id = ss->stroke_id; | |||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static void sculpt_stroke_update_step(bContext *C, | static void sculpt_stroke_update_step(bContext *C, | ||||
| wmOperator *UNUSED(op), | wmOperator *UNUSED(op), | ||||
| struct PaintStroke *stroke, | struct PaintStroke *stroke, | ||||
| ▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | static void sculpt_brush_exit_tex(Sculpt *sd) | ||||
| Brush *brush = BKE_paint_brush(&sd->paint); | Brush *brush = BKE_paint_brush(&sd->paint); | ||||
| MTex *mtex = &brush->mtex; | MTex *mtex = &brush->mtex; | ||||
| if (mtex->tex && mtex->tex->nodetree) { | if (mtex->tex && mtex->tex->nodetree) { | ||||
| ntreeTexEndExecTree(mtex->tex->nodetree->execdata); | ntreeTexEndExecTree(mtex->tex->nodetree->execdata); | ||||
| } | } | ||||
| } | } | ||||
| static void sculpt_flush_batches(Sculpt *sd, | |||||
| Object *ob, | |||||
| Brush *brush, | |||||
| PaintModeSettings *paint_mode_settings) | |||||
| { | |||||
| if (!sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) { | |||||
| return; | |||||
| } | |||||
| if (brush->sculpt_tool == SCULPT_TOOL_PAINT) { | |||||
| SCULPT_paint_batches_flush(paint_mode_settings, sd, ob); | |||||
| } | |||||
| } | |||||
| static void sculpt_stroke_redraw(const bContext *C, | |||||
| struct PaintStroke *UNUSED(stroke), | |||||
| bool is_final) | |||||
| { | |||||
| /* TODO(jbakker): this callback should not be named redraw as in this case it doesn't do | |||||
| * redrawing, but triggers batched step drawing and downloading of results and update undo steps | |||||
| * for the paint brush with a canvas target.*/ | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| SculptSession *ss = ob->sculpt; | |||||
| Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | |||||
| Brush *brush = BKE_paint_brush(&sd->paint); | |||||
| ToolSettings *tool_settings = CTX_data_tool_settings(C); | |||||
| sculpt_flush_batches(sd, ob, brush, &tool_settings->paint_mode); | |||||
| if (!ss->cache) { | |||||
| return; | |||||
| } | |||||
| if (is_final) { | |||||
| } | |||||
| } | |||||
| static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) | static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | ||||
| ToolSettings *tool_settings = CTX_data_tool_settings(C); | ToolSettings *tool_settings = CTX_data_tool_settings(C); | ||||
| /* Finished. */ | /* Finished. */ | ||||
| Show All 33 Lines | static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) | ||||
| if (brush->sculpt_tool == SCULPT_TOOL_MASK) { | if (brush->sculpt_tool == SCULPT_TOOL_MASK) { | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | ||||
| } | } | ||||
| else if (brush->sculpt_tool == SCULPT_TOOL_PAINT) { | else if (brush->sculpt_tool == SCULPT_TOOL_PAINT) { | ||||
| if (SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { | if (SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_IMAGE); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_IMAGE); | ||||
| } | } | ||||
| else { | |||||
| BKE_sculpt_attributes_destroy_temporary_stroke(ob); | |||||
| } | |||||
| } | } | ||||
| else { | else { | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); | ||||
| } | } | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); | ||||
| sculpt_brush_exit_tex(sd); | sculpt_brush_exit_tex(sd); | ||||
| } | } | ||||
| Show All 37 Lines | if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) { | ||||
| ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); | ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); | ||||
| } | } | ||||
| stroke = paint_stroke_new(C, | stroke = paint_stroke_new(C, | ||||
| op, | op, | ||||
| SCULPT_stroke_get_location, | SCULPT_stroke_get_location, | ||||
| sculpt_stroke_test_start, | sculpt_stroke_test_start, | ||||
| sculpt_stroke_update_step, | sculpt_stroke_update_step, | ||||
| NULL, | sculpt_stroke_redraw, | ||||
| sculpt_stroke_done, | sculpt_stroke_done, | ||||
| event->type); | event->type); | ||||
| op->customdata = stroke; | op->customdata = stroke; | ||||
| /* For tablet rotation. */ | /* For tablet rotation. */ | ||||
| ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); | ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); | ||||
| ▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| void SCULPT_fake_neighbors_free(Object *ob) | void SCULPT_fake_neighbors_free(Object *ob) | ||||
| { | { | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| sculpt_pose_fake_neighbors_free(ss); | sculpt_pose_fake_neighbors_free(ss); | ||||
| } | } | ||||
| void SCULPT_automasking_node_begin(Object *ob, | |||||
| const SculptSession *UNUSED(ss), | |||||
| AutomaskingCache *automasking, | |||||
| AutomaskingNodeData *node_data, | |||||
| PBVHNode *node) | |||||
| { | |||||
| if (!automasking) { | |||||
| memset(node_data, 0, sizeof(*node_data)); | |||||
| return; | |||||
| } | |||||
| node_data->node = node; | |||||
| node_data->have_orig_data = automasking->settings.flags & | |||||
| (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL); | |||||
| if (node_data->have_orig_data) { | |||||
| SCULPT_orig_vert_data_init(&node_data->orig_data, ob, node, SCULPT_UNDO_COORDS); | |||||
| } | |||||
| else { | |||||
| memset(&node_data->orig_data, 0, sizeof(node_data->orig_data)); | |||||
| } | |||||
| } | |||||
| void SCULPT_automasking_node_update(SculptSession *UNUSED(ss), | |||||
| AutomaskingNodeData *automask_data, | |||||
| PBVHVertexIter *vd) | |||||
| { | |||||
| if (automask_data->have_orig_data) { | |||||
| SCULPT_orig_vert_data_update(&automask_data->orig_data, vd); | |||||
| } | |||||
| } | |||||
| bool SCULPT_vertex_is_occluded(SculptSession *ss, PBVHVertRef vertex, bool original) | |||||
| { | |||||
| float ray_start[3], ray_end[3], ray_normal[3], face_normal[3]; | |||||
| float co[3]; | |||||
| copy_v3_v3(co, SCULPT_vertex_co_get(ss, vertex)); | |||||
| float mouse[2]; | |||||
| ED_view3d_project_float_v2_m4(ss->cache->vc->region, co, mouse, ss->cache->projection_mat); | |||||
| int depth = SCULPT_raycast_init(ss->cache->vc, mouse, ray_end, ray_start, ray_normal, original); | |||||
| negate_v3(ray_normal); | |||||
| copy_v3_v3(ray_start, SCULPT_vertex_co_get(ss, vertex)); | |||||
| madd_v3_v3fl(ray_start, ray_normal, 0.002); | |||||
| SculptRaycastData srd = {0}; | |||||
| srd.original = original; | |||||
| srd.ss = ss; | |||||
| srd.hit = false; | |||||
| srd.ray_start = ray_start; | |||||
| srd.ray_normal = ray_normal; | |||||
| srd.depth = depth; | |||||
| srd.face_normal = face_normal; | |||||
| isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal); | |||||
| BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); | |||||
| return srd.hit; | |||||
| } | |||||
| void SCULPT_stroke_id_next(Object *ob) | |||||
| { | |||||
| /* Manually wrap in int32 space to avoid tripping up undefined behavior | |||||
| * sanitizers. | |||||
| */ | |||||
| ob->sculpt->stroke_id = (uchar)(((int)ob->sculpt->stroke_id + 1) & 255); | |||||
| } | |||||
| void SCULPT_stroke_id_ensure(Object *ob) | |||||
| { | |||||
| SculptSession *ss = ob->sculpt; | |||||
| if (!ss->attrs.automasking_stroke_id) { | |||||
| SculptAttributeParams params = {0}; | |||||
| ss->attrs.automasking_stroke_id = BKE_sculpt_attribute_ensure( | |||||
| ob, | |||||
| ATTR_DOMAIN_POINT, | |||||
| CD_PROP_INT8, | |||||
| SCULPT_ATTRIBUTE_NAME(automasking_stroke_id), | |||||
| ¶ms); | |||||
| } | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||