Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.c
| Context not available. | |||||
| #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 | #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 | ||||
| typedef struct SculptVertexNeighborIter { | typedef struct SculptVertexNeighborIter { | ||||
| /* Storage */ | |||||
| int *neighbors; | int *neighbors; | ||||
| int size; | int size; | ||||
| int capacity; | int capacity; | ||||
| int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; | |||||
| /* Internal iterator. */ | int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; | ||||
| int num_duplicates; | |||||
| int i; | |||||
| /* Public */ | |||||
| int index; | int index; | ||||
| bool is_duplicate; | int i; | ||||
| } SculptVertexNeighborIter; | } SculptVertexNeighborIter; | ||||
| static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) | static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) | ||||
| Context not available. | |||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| iter->size = 0; | iter->size = 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; | ||||
| Context not available. | |||||
| int i; | int i; | ||||
| MeshElemMap *vert_map = &ss->pmap[(int)index]; | MeshElemMap *vert_map = &ss->pmap[(int)index]; | ||||
| iter->size = 0; | iter->size = 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; | ||||
| Context not available. | |||||
| } | } | ||||
| static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, | static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, | ||||
| const int index, | int index, | ||||
| const bool include_duplicates, | |||||
| SculptVertexNeighborIter *iter) | SculptVertexNeighborIter *iter) | ||||
| { | { | ||||
| /* TODO: optimize this. We could fill SculptVertexNeighborIter directly, | /* TODO: optimize this. We could fill SculptVertexNeighborIter directly, | ||||
| Context not available. | |||||
| .y = vertex_index / key->grid_size}; | .y = vertex_index / key->grid_size}; | ||||
| SubdivCCGNeighbors neighbors; | SubdivCCGNeighbors neighbors; | ||||
| BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors); | BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, &neighbors); | ||||
| iter->size = 0; | iter->size = 0; | ||||
| iter->num_duplicates = neighbors.num_duplicates; | |||||
| iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; | iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; | ||||
| iter->neighbors = iter->neighbors_fixed; | iter->neighbors = iter->neighbors_fixed; | ||||
| Context not available. | |||||
| } | } | ||||
| static void sculpt_vertex_neighbors_get(SculptSession *ss, | static void sculpt_vertex_neighbors_get(SculptSession *ss, | ||||
| const int index, | int index, | ||||
| const bool include_duplicates, | |||||
| SculptVertexNeighborIter *iter) | SculptVertexNeighborIter *iter) | ||||
| { | { | ||||
| switch (BKE_pbvh_type(ss->pbvh)) { | switch (BKE_pbvh_type(ss->pbvh)) { | ||||
| Context not available. | |||||
| sculpt_vertex_neighbors_get_bmesh(ss, index, iter); | sculpt_vertex_neighbors_get_bmesh(ss, index, iter); | ||||
| return; | return; | ||||
| case PBVH_GRIDS: | case PBVH_GRIDS: | ||||
| sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter); | sculpt_vertex_neighbors_get_grids(ss, index, iter); | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| /* Iterator over neighboring vertices. */ | |||||
| #define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ | #define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ | ||||
| sculpt_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ | sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \ | ||||
| for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ | for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ | ||||
| neighbor_iterator.i++) { \ | neighbor_iterator.i++) { \ | ||||
| neighbor_iterator.index = ni.neighbors[ni.i]; | neighbor_iterator.index = ni.neighbors[ni.i]; | ||||
| /* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come | |||||
| * first since they are nearest for floodfill. */ | |||||
| #define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ | |||||
| sculpt_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ | |||||
| for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ | |||||
| neighbor_iterator.i--) { \ | |||||
| neighbor_iterator.index = ni.neighbors[ni.i]; \ | |||||
| neighbor_iterator.is_duplicate = (ni.i >= \ | |||||
| neighbor_iterator.size - neighbor_iterator.num_duplicates); | |||||
| #define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \ | #define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \ | ||||
| } \ | } \ | ||||
| if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ | if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ | ||||
| Context not available. | |||||
| char *visited_vertices; | char *visited_vertices; | ||||
| } SculptFloodFill; | } SculptFloodFill; | ||||
| typedef struct SculptFloodFillIterator { | |||||
| int v; | |||||
| int it; | |||||
| float edge_factor; | |||||
| } SculptFloodFillIterator; | |||||
| static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood) | static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood) | ||||
| { | { | ||||
| int vertex_count = sculpt_vertex_count_get(ss); | int vertex_count = sculpt_vertex_count_get(ss); | ||||
| sculpt_vertex_random_access_init(ss); | sculpt_vertex_random_access_init(ss); | ||||
| flood->queue = BLI_gsqueue_new(sizeof(int)); | flood->queue = BLI_gsqueue_new(sizeof(SculptFloodFillIterator)); | ||||
| flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); | flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); | ||||
| } | } | ||||
| static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index) | static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index) | ||||
| { | { | ||||
| BLI_gsqueue_push(flood->queue, &index); | SculptFloodFillIterator mevit; | ||||
| mevit.v = index; | |||||
| mevit.it = 0; | |||||
| mevit.edge_factor = 1.0f; | |||||
| BLI_gsqueue_push(flood->queue, &mevit); | |||||
| } | } | ||||
| static void sculpt_floodfill_add_active( | static void sculpt_floodfill_add_active( | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| static void sculpt_floodfill_execute( | static void sculpt_floodfill_execute(SculptSession *ss, | ||||
| SculptSession *ss, | SculptFloodFill *flood, | ||||
| SculptFloodFill *flood, | bool (*func)(SculptSession *ss, | ||||
| bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), | const SculptFloodFillIterator *from, | ||||
| void *userdata) | SculptFloodFillIterator *to, | ||||
| void *userdata), | |||||
| void *userdata) | |||||
| { | { | ||||
| /* TODO: multires support, taking into account duplicate vertices and | |||||
| * correctly handling them in the pose, automask and mask expand callbacks. */ | |||||
| while (!BLI_gsqueue_is_empty(flood->queue)) { | while (!BLI_gsqueue_is_empty(flood->queue)) { | ||||
| int from_v; | SculptFloodFillIterator from; | ||||
| BLI_gsqueue_pop(flood->queue, &from_v); | BLI_gsqueue_pop(flood->queue, &from); | ||||
| SculptVertexNeighborIter ni; | SculptVertexNeighborIter ni; | ||||
| sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni) | sculpt_vertex_neighbors_iter_begin(ss, from.v, ni) | ||||
| { | { | ||||
| const int to_v = ni.index; | if (flood->visited_vertices[ni.index] == 0) { | ||||
| if (flood->visited_vertices[to_v] == 0) { | flood->visited_vertices[ni.index] = 1; | ||||
| flood->visited_vertices[to_v] = 1; | |||||
| SculptFloodFillIterator to; | |||||
| to.v = ni.index; | |||||
| to.it = from.it + 1; | |||||
| to.edge_factor = 0.0f; | |||||
| if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { | if (func(ss, &from, &to, userdata)) { | ||||
| BLI_gsqueue_push(flood->queue, &to_v); | BLI_gsqueue_push(flood->queue, &to); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br) | static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br) | ||||
| { | { | ||||
| // REMOVE WITH PBVH_GRIDS | |||||
| if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { | |||||
| return false; | |||||
| } | |||||
| if (sculpt_stroke_is_dynamic_topology(ss, br)) { | if (sculpt_stroke_is_dynamic_topology(ss, br)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| Context not available. | |||||
| char symm; | char symm; | ||||
| } AutomaskFloodFillData; | } AutomaskFloodFillData; | ||||
| static bool automask_floodfill_cb( | static bool automask_floodfill_cb(SculptSession *ss, | ||||
| SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) | const SculptFloodFillIterator *UNUSED(from), | ||||
| SculptFloodFillIterator *to, | |||||
| void *userdata) | |||||
| { | { | ||||
| AutomaskFloodFillData *data = userdata; | AutomaskFloodFillData *data = userdata; | ||||
| data->automask_factor[to_v] = 1.0f; | data->automask_factor[to->v] = 1.0f; | ||||
| return (!data->use_radius || | return (!data->use_radius || | ||||
| sculpt_is_vertex_inside_brush_radius_symm( | sculpt_is_vertex_inside_brush_radius_symm( | ||||
| sculpt_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); | sculpt_vertex_co_get(ss, to->v), data->location, data->radius, data->symm)); | ||||
| } | } | ||||
| static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) | static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) | ||||
| Context not available. | |||||
| float pose_initial_co[3]; | float pose_initial_co[3]; | ||||
| float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4]; | float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4]; | ||||
| if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { | |||||
| return; | |||||
| } | |||||
| copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); | copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); | ||||
| copy_v3_v3(pose_origin, ss->cache->pose_origin); | copy_v3_v3(pose_origin, ss->cache->pose_origin); | ||||
| Context not available. | |||||
| int tot_co; | int tot_co; | ||||
| } PoseFloodFillData; | } PoseFloodFillData; | ||||
| static bool pose_floodfill_cb( | static bool pose_floodfill_cb(SculptSession *ss, | ||||
| SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) | const SculptFloodFillIterator *UNUSED(from), | ||||
| SculptFloodFillIterator *to, | |||||
| void *userdata) | |||||
| { | { | ||||
| PoseFloodFillData *data = userdata; | PoseFloodFillData *data = userdata; | ||||
| if (data->pose_factor) { | if (data->pose_factor) { | ||||
| data->pose_factor[to_v] = 1.0f; | data->pose_factor[to->v] = 1.0f; | ||||
| } | } | ||||
| const float *co = sculpt_vertex_co_get(ss, to_v); | const float *co = sculpt_vertex_co_get(ss, to->v); | ||||
| if (sculpt_pose_brush_is_vertex_inside_brush_radius( | if (sculpt_pose_brush_is_vertex_inside_brush_radius( | ||||
| co, data->pose_initial_co, data->radius, data->symm)) { | co, data->pose_initial_co, data->radius, data->symm)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) { | else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) { | ||||
| if (!is_duplicate) { | add_v3_v3(data->pose_origin, co); | ||||
| add_v3_v3(data->pose_origin, co); | data->tot_co++; | ||||
| data->tot_co++; | |||||
| } | |||||
| } | } | ||||
| return false; | return false; | ||||
| Context not available. | |||||
| if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time && | if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time && | ||||
| ss->cache->mirror_symmetry_pass == 0) { | ss->cache->mirror_symmetry_pass == 0) { | ||||
| sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); | if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) { | ||||
| sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); | |||||
| } | |||||
| } | } | ||||
| /* Apply one type of brush action */ | /* Apply one type of brush action */ | ||||
| Context not available. | |||||
| bool use_normals; | bool use_normals; | ||||
| } MaskExpandFloodFillData; | } MaskExpandFloodFillData; | ||||
| static bool mask_expand_floodfill_cb( | static bool mask_expand_floodfill_cb(SculptSession *ss, | ||||
| SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) | const SculptFloodFillIterator *from, | ||||
| SculptFloodFillIterator *to, | |||||
| void *userdata) | |||||
| { | { | ||||
| MaskExpandFloodFillData *data = userdata; | MaskExpandFloodFillData *data = userdata; | ||||
| if (!is_duplicate) { | ss->filter_cache->mask_update_it[to->v] = to->it; | ||||
| int to_it = ss->filter_cache->mask_update_it[from_v] + 1; | if (to->it > ss->filter_cache->mask_update_last_it) { | ||||
| ss->filter_cache->mask_update_it[to_v] = to_it; | ss->filter_cache->mask_update_last_it = to->it; | ||||
| if (to_it > ss->filter_cache->mask_update_last_it) { | |||||
| ss->filter_cache->mask_update_last_it = to_it; | |||||
| } | |||||
| if (data->use_normals) { | |||||
| float current_normal[3], prev_normal[3]; | |||||
| sculpt_vertex_normal_get(ss, to_v, current_normal); | |||||
| sculpt_vertex_normal_get(ss, from_v, prev_normal); | |||||
| const float from_edge_factor = ss->filter_cache->edge_factor[from_v]; | |||||
| ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * | |||||
| from_edge_factor; | |||||
| ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) * | |||||
| powf(from_edge_factor, data->edge_sensitivity); | |||||
| CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f); | |||||
| } | |||||
| } | } | ||||
| else { | |||||
| /* PBVH_GRIDS duplicate handling */ | if (data->use_normals) { | ||||
| ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v]; | float current_normal[3], prev_normal[3]; | ||||
| if (data->use_normals) { | sculpt_vertex_normal_get(ss, to->v, current_normal); | ||||
| ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v]; | sculpt_vertex_normal_get(ss, from->v, prev_normal); | ||||
| ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v]; | to->edge_factor = dot_v3v3(current_normal, prev_normal) * from->edge_factor; | ||||
| } | ss->filter_cache->normal_factor[to->v] = dot_v3v3(data->original_normal, current_normal) * | ||||
| powf(from->edge_factor, data->edge_sensitivity); | |||||
| CLAMP(ss->filter_cache->normal_factor[to->v], 0.0f, 1.0f); | |||||
| } | } | ||||
| return true; | return true; | ||||
| Context not available. | |||||
| mouse[0] = event->mval[0]; | mouse[0] = event->mval[0]; | ||||
| mouse[1] = event->mval[1]; | mouse[1] = event->mval[1]; | ||||
| if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| sculpt_vertex_random_access_init(ss); | sculpt_vertex_random_access_init(ss); | ||||
| op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position"); | op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position"); | ||||
| Context not available. | |||||
| if (use_normals) { | if (use_normals) { | ||||
| ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count, | ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count, | ||||
| "mask update normal factor"); | "mask update normal factor"); | ||||
| ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count, | |||||
| "mask update normal factor"); | |||||
| for (int i = 0; i < vertex_count; i++) { | |||||
| ss->filter_cache->edge_factor[i] = 1.0f; | |||||
| } | |||||
| } | } | ||||
| ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); | ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); | ||||
| Context not available. | |||||
| ss->filter_cache->normal_factor[i] = avg / ni.size; | ss->filter_cache->normal_factor[i] = avg / ni.size; | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(ss->filter_cache->edge_factor); | |||||
| } | } | ||||
| SculptThreadedTaskData data = { | SculptThreadedTaskData data = { | ||||
| Context not available. | |||||