Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/multires_unsubdivide.c
| Show All 27 Lines | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_modifier_types.h" | #include "DNA_modifier_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "BLI_gsqueue.h" | #include "BLI_gsqueue.h" | ||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | ||||
| #include "BLI_task.h" | |||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | ||||
| #include "BKE_lib_id.h" | #include "BKE_lib_id.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_multires.h" | #include "BKE_multires.h" | ||||
| #include "BKE_subdiv.h" | #include "BKE_subdiv.h" | ||||
| ▲ Show 20 Lines • Show All 947 Lines • ▼ Show 20 Lines | if (next_l_index < p->loopstart + p->totloop) { | ||||
| if (l_next->v == v_x) { | if (l_next->v == v_x) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context) | typedef struct UnsubdivideExtractGridsData { | ||||
| { | MultiresUnsubdivideContext *context; | ||||
| Mesh *original_mesh = context->original_mesh; | |||||
| Mesh *base_mesh = context->base_mesh; | |||||
| BMesh *bm_original_mesh = context->bm_original_mesh; | int *orig_to_base_vmap; | ||||
| int *base_to_orig_vmap; | |||||
sergey: Seems these can become `const`.
Add comments from the below about mapping from base to… | |||||
| context->num_grids = base_mesh->totloop; | BMesh *bm_original_mesh; | ||||
| context->base_mesh_grids = MEM_calloc_arrayN( | |||||
| sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids"); | |||||
| /* Based on the existing indices in the data-layers, generate two vertex indices maps. */ | BMesh *bm_base_mesh; | ||||
| /* From vertex index in original to vertex index in base and from vertex index in base to vertex | Mesh *base_mesh; | ||||
| * index in original. */ | int base_l_offset; | ||||
sergeyUnsubmitted Done Inline Actionsbase_loop_offset. With description about what it is. sergey: `base_loop_offset`. With description about what it is. | |||||
| int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap"); | } UnsubdivideExtractGridsData; | ||||
| int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap"); | |||||
| context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname); | static void unsubdivide_extract_grids_task(void *__restrict userdata_v, | ||||
| for (int i = 0; i < base_mesh->totvert; i++) { | const int vertex_index, | ||||
| base_to_orig_vmap[i] = context->base_to_orig_vmap[i]; | const TaskParallelTLS *__restrict UNUSED(tls)) | ||||
| } | { | ||||
| UnsubdivideExtractGridsData *data = userdata_v; | |||||
| MultiresUnsubdivideContext *context = data->context; | |||||
| /* If an index in original does not exist in base (it was dissolved when creating the new base | int *orig_to_base_vmap = data->orig_to_base_vmap; | ||||
| * mesh, return -1. */ | int *base_to_orig_vmap = data->base_to_orig_vmap; | ||||
| for (int i = 0; i < original_mesh->totvert; i++) { | |||||
| orig_to_base_vmap[i] = -1; | |||||
| } | |||||
| for (int i = 0; i < base_mesh->totvert; i++) { | BMesh *bm_base_mesh = data->bm_base_mesh; | ||||
| const int orig_vertex_index = context->base_to_orig_vmap[i]; | Mesh *base_mesh = data->base_mesh; | ||||
| orig_to_base_vmap[orig_vertex_index] = i; | const int base_l_offset = data->base_l_offset; | ||||
| } | |||||
| /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer, | BMesh *bm_original_mesh = data->bm_original_mesh; | ||||
| * so they can be used from #BMesh. */ | |||||
| multires_unsubdivide_add_original_index_datalayers(base_mesh); | |||||
| const int base_l_layer_index = CustomData_get_named_layer_index( | BMVert *v = BM_vert_at_index(data->bm_base_mesh, vertex_index); | ||||
| &base_mesh->ldata, CD_PROP_INT32, lname); | BMIter iter_a, iter_b; | ||||
| BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh); | |||||
| BMIter iter, iter_a, iter_b; | |||||
| BMVert *v; | |||||
| BMLoop *l, *lb; | BMLoop *l, *lb; | ||||
| BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT); | |||||
| BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE); | |||||
| /* Get the data-layer that contains the loops indices. */ | |||||
| const int base_l_offset = CustomData_get_n_offset( | |||||
| &bm_base_mesh->ldata, CD_PROP_INT32, base_l_layer_index); | |||||
| /* Main loop for extracting the grids. Iterates over the base mesh vertices. */ | |||||
| BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) { | |||||
| /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the | /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the | ||||
| * vertex map. */ | * vertex map. */ | ||||
| const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)]; | const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)]; | ||||
| BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index); | BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index); | ||||
| /* Iterate over the loops of that vertex in the original mesh. */ | /* Iterate over the loops of that vertex in the original mesh. */ | ||||
| BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) { | ||||
| /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the | /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the | ||||
| * base mesh of the poly of grid that is going to be extracted. */ | * base mesh of the poly of grid that is going to be extracted. */ | ||||
| BMVert *corner_x, *corner_y; | BMVert *corner_x, *corner_y; | ||||
| multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y); | multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y); | ||||
| /* Map the two obtained vertices to the base mesh. */ | /* Map the two obtained vertices to the base mesh. */ | ||||
| const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)]; | const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)]; | ||||
| const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)]; | const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)]; | ||||
| /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained | /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained | ||||
| * vertices and the current vertex it is possible to get the index of the loop in the base | * vertices and the current vertex it is possible to get the index of the loop in the base | ||||
| * mesh the grid that is going to be extracted belongs to. */ | * mesh the grid that is going to be extracted belongs to. */ | ||||
| BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) { | ||||
| BMFace *base_face = lb->f; | BMFace *base_face = lb->f; | ||||
| BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index); | BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index); | ||||
| BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index); | BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index); | ||||
| /* If this is the correct loop in the base mesh, the original vertex and the two corners | /* If this is the correct loop in the base mesh, the original vertex and the two corners | ||||
| * should be in the loop's face. */ | * should be in the loop's face. */ | ||||
| if (BM_vert_in_face(base_corner_x, base_face) && | if (BM_vert_in_face(base_corner_x, base_face) && BM_vert_in_face(base_corner_y, base_face)) { | ||||
| BM_vert_in_face(base_corner_y, base_face)) { | |||||
| /* Get the index of the loop. */ | /* Get the index of the loop. */ | ||||
| const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset); | const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset); | ||||
| const int base_mesh_face_index = BM_elem_index_get(base_face); | const int base_mesh_face_index = BM_elem_index_get(base_face); | ||||
| /* Check the orientation of the loops in case that is needed to flip the x and y axis | /* Check the orientation of the loops in case that is needed to flip the x and y axis | ||||
| * when extracting the grid. */ | * when extracting the grid. */ | ||||
| const bool flip_grid = multires_unsubdivide_flip_grid_x_axis( | const bool flip_grid = multires_unsubdivide_flip_grid_x_axis( | ||||
| base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index); | base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index); | ||||
| /* Extract the grid for that loop. */ | /* Extract the grid for that loop. */ | ||||
| context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index; | context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index; | ||||
| multires_unsubdivide_extract_single_grid_from_face_edge( | multires_unsubdivide_extract_single_grid_from_face_edge( | ||||
| context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]); | context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context) | |||||
| { | |||||
| Mesh *original_mesh = context->original_mesh; | |||||
| Mesh *base_mesh = context->base_mesh; | |||||
| BMesh *bm_original_mesh = context->bm_original_mesh; | |||||
| context->num_grids = base_mesh->totloop; | |||||
| context->base_mesh_grids = MEM_calloc_arrayN( | |||||
| sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids"); | |||||
| /* Based on the existing indices in the data-layers, generate two vertex indices maps. */ | |||||
| /* From vertex index in original to vertex index in base and from vertex index in base to vertex | |||||
| * index in original. */ | |||||
| int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap"); | |||||
| int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap"); | |||||
| context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT32, vname); | |||||
| for (int i = 0; i < base_mesh->totvert; i++) { | |||||
| base_to_orig_vmap[i] = context->base_to_orig_vmap[i]; | |||||
| } | |||||
| /* If an index in original does not exist in base (it was dissolved when creating the new base | |||||
| * mesh, return -1. */ | |||||
| for (int i = 0; i < original_mesh->totvert; i++) { | |||||
| orig_to_base_vmap[i] = -1; | |||||
| } | |||||
| for (int i = 0; i < base_mesh->totvert; i++) { | |||||
| const int orig_vertex_index = context->base_to_orig_vmap[i]; | |||||
| orig_to_base_vmap[orig_vertex_index] = i; | |||||
| } | |||||
sergeyUnsubmitted Done Inline ActionsYou can move map initialization to own functions, keeping pointers outside of initialization always const. sergey: You can move map initialization to own functions, keeping pointers outside of initialization… | |||||
| /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer, | |||||
| * so they can be used from #BMesh. */ | |||||
| multires_unsubdivide_add_original_index_datalayers(base_mesh); | |||||
| const int base_l_layer_index = CustomData_get_named_layer_index( | |||||
| &base_mesh->ldata, CD_PROP_INT32, lname); | |||||
| BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh); | |||||
| BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT); | |||||
| BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE); | |||||
| /* Get the data-layer that contains the loops indices. */ | |||||
| const int base_l_offset = CustomData_get_n_offset( | |||||
| &bm_base_mesh->ldata, CD_PROP_INT32, base_l_layer_index); | |||||
| UnsubdivideExtractGridsData data; | |||||
| data.context = context; | |||||
| data.orig_to_base_vmap = orig_to_base_vmap; | |||||
| data.base_to_orig_vmap = base_to_orig_vmap; | |||||
| data.base_mesh = base_mesh; | |||||
| data.bm_base_mesh = bm_base_mesh; | |||||
| data.base_l_offset = base_l_offset; | |||||
| data.bm_original_mesh = bm_original_mesh; | |||||
| TaskParallelSettings parallel_range_settings; | |||||
| BLI_parallel_range_settings_defaults(¶llel_range_settings); | |||||
| BLI_task_parallel_range( | |||||
| 0, bm_base_mesh->totvert, &data, unsubdivide_extract_grids_task, ¶llel_range_settings); | |||||
| MEM_freeN(orig_to_base_vmap); | MEM_freeN(orig_to_base_vmap); | ||||
| MEM_freeN(base_to_orig_vmap); | MEM_freeN(base_to_orig_vmap); | ||||
| BM_mesh_free(bm_base_mesh); | BM_mesh_free(bm_base_mesh); | ||||
| multires_unsubdivide_free_original_datalayers(base_mesh); | multires_unsubdivide_free_original_datalayers(base_mesh); | ||||
| } | } | ||||
| static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context) | static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context) | ||||
| ▲ Show 20 Lines • Show All 190 Lines • Show Last 20 Lines | |||||
Seems these can become const.
Add comments from the below about mapping from base to original vertex index mapping.
Also make sure the definition of base and original is present.