Cleanup: spelling, comments
This commit is contained in:
parent
0cb53d4740
commit
5ee1c7f695
|
@ -19,6 +19,9 @@
|
|||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* This implements the un-subdivide algorithm, which generates a lower resolution base mesh and
|
||||
* its corresponding grids to match a given original mesh.
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
@ -47,33 +50,36 @@
|
|||
#include "multires_reshape.h"
|
||||
#include "multires_unsubdivide.h"
|
||||
|
||||
/* This implements the unsubdivide algorithm, which generates a lower resolution base mesh and its
|
||||
* corresponding grids to match a given original mesh. */
|
||||
|
||||
/* This is done in the following steps:
|
||||
* - If there are already grids in the original mesh, convert them from tangent displacement to
|
||||
object space coordinates.
|
||||
* - Assign datalayers to the original mesh to map vertices to a new base mesh. These datalayes
|
||||
store the indicies of the elements in the original mesh. This way the original inidices are
|
||||
preserved when doing mesh modifications (removing and disolving vertices) when building the new
|
||||
base mesh.
|
||||
*
|
||||
* - If there are already grids in the original mesh,
|
||||
* convert them from tangent displacement to object space coordinates.
|
||||
* - Assign data-layers to the original mesh to map vertices to a new base mesh.
|
||||
* These data-layers store the indices of the elements in the original mesh.
|
||||
* This way the original indices are
|
||||
* preserved when doing mesh modifications (removing and dissolving vertices)
|
||||
* when building the new base mesh.
|
||||
* - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
|
||||
center vertices of the lower level grid. If the algorithm can tag all vertices correctly, the lower
|
||||
level base mesh is generated by dissolving the tagged vertices.
|
||||
* - Use the datalayers to map vertices from the base mesh to the original mesh and original to
|
||||
base mesh.
|
||||
* center vertices of the lower level grid.
|
||||
* If the algorithm can tag all vertices correctly,
|
||||
* the lower level base mesh is generated by dissolving the tagged vertices.
|
||||
* - Use the data-layers to map vertices from the base mesh to the original mesh and original to
|
||||
* base mesh.
|
||||
* - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
|
||||
to original mesh
|
||||
* to original mesh
|
||||
* - Extract the grid from the original mesh from that loop. If there are no grids in the original
|
||||
mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern over
|
||||
them. If there are grids in the original mesh, iterate in a grid pattern over the polys, reorder
|
||||
all the coordinates of the grid in that poly and copy those coordinates to the new base mesh grid.
|
||||
* - Copy the new grid data over to a new allocated MDISP layer with the appropiate size to store
|
||||
the new levels.
|
||||
* mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
|
||||
* over them. If there are grids in the original mesh, iterate in a grid pattern over the polys,
|
||||
* reorder all the coordinates of the grid in that poly and copy those coordinates to the new
|
||||
* base mesh grid.
|
||||
* - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
|
||||
* the new levels.
|
||||
* - Convert the grid data from object space to tangent displacement.
|
||||
*/
|
||||
|
||||
/* Used to check if a vertex is in a disconnected element ID. */
|
||||
/**
|
||||
* Used to check if a vertex is in a disconnected element ID.
|
||||
*/
|
||||
static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem)
|
||||
{
|
||||
const int v_index = BM_elem_index_get(v);
|
||||
|
@ -90,9 +96,12 @@ static bool is_vertex_pole(BMVert *v)
|
|||
return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5);
|
||||
}
|
||||
|
||||
/* Returns the first pole that is found in an element ID. */
|
||||
/* Tries to give priority to 3 vert poles as they generally generate better results in cases were
|
||||
* the unsubdivide solution is ambiguous. */
|
||||
/**
|
||||
* Returns the first pole that is found in an element ID.
|
||||
*
|
||||
* Tries to give priority to 3 vert poles as they generally generate better results in cases were
|
||||
* the un-subdivide solution is ambiguous.
|
||||
*/
|
||||
static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
|
||||
{
|
||||
BMIter iter;
|
||||
|
@ -109,9 +118,12 @@ static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
|
|||
return pole;
|
||||
}
|
||||
|
||||
/* Checks if the mesh is all quads. */
|
||||
/* TODO(pablodp606). This can perform additional checks if they are faster than trying to search
|
||||
* for an unsubidivide solution. This way it is possible to cancel the operation faster. */
|
||||
/**
|
||||
* Checks if the mesh is all quads.
|
||||
*
|
||||
* TODO(pablodp606): This can perform additional checks if they are faster than trying to search
|
||||
* for an un-subdivide solution. This way it is possible to cancel the operation faster.
|
||||
*/
|
||||
static bool unsubdivide_is_all_quads(BMesh *bm)
|
||||
{
|
||||
BMIter iter;
|
||||
|
@ -146,17 +158,23 @@ static bool unsubdivide_is_all_quads(BMesh *bm)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Returns true if from_v and to_v, which should be part of the same quad face, are diagonals. */
|
||||
/**
|
||||
* Returns true if from_v and to_v, which should be part of the same quad face, are diagonals.
|
||||
*/
|
||||
static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
|
||||
{
|
||||
return !BM_edge_exists(from_v, to_v);
|
||||
}
|
||||
|
||||
/* Generates a possible solution for unsubdivision by tagging the (0,0) vertices of the possible
|
||||
* grids. */
|
||||
/* This works using a flood fill operation using the quads diagonals to jump to the next vertex. */
|
||||
/* If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0)
|
||||
* vertices of the grids that need to be dissolved, and nothing else. */
|
||||
/**
|
||||
* Generates a possible solution for un-subdivision by tagging the (0,0)
|
||||
* vertices of the possible grids.
|
||||
*
|
||||
* This works using a flood fill operation using the quads diagonals to jump to the next vertex.
|
||||
*
|
||||
* If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0)
|
||||
* vertices of the grids that need to be dissolved, and nothing else.
|
||||
*/
|
||||
static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
|
||||
{
|
||||
bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
|
||||
|
@ -225,10 +243,13 @@ static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex
|
|||
MEM_freeN(visited_vertices);
|
||||
}
|
||||
|
||||
/* This function checks if the current status of the BMVert tags corresponds to a valid unsubdivide
|
||||
* solution. */
|
||||
/* This means that all vertices corresponding to the (0,0) grid coordinate should be tagged. */
|
||||
/* On a valid solution, the following things should happen:
|
||||
/**
|
||||
* This function checks if the current status of the #BMVert tags
|
||||
* corresponds to a valid un-subdivide solution.
|
||||
*
|
||||
* This means that all vertices corresponding to the (0,0) grid coordinate should be tagged.
|
||||
*
|
||||
* On a valid solution, the following things should happen:
|
||||
* - No boundary vertices should be tagged
|
||||
* - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged
|
||||
* - All boundary vertices should have one vertex connected by an edge or a diagonal tagged
|
||||
|
@ -256,7 +277,7 @@ static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int
|
|||
}
|
||||
}
|
||||
if (BM_vert_is_boundary(v)) {
|
||||
/* Untagged vertex in boundary without connected tagged vertices. */
|
||||
/* Un-tagged vertex in boundary without connected tagged vertices. */
|
||||
bool any_tagged = false;
|
||||
BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
|
||||
BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
|
||||
|
@ -275,12 +296,14 @@ static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Searchs and validates an unsubdivide solution for a given element ID. */
|
||||
/**
|
||||
* Search and validates an un-subdivide solution for a given element ID.
|
||||
*/
|
||||
static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
|
||||
{
|
||||
/* First, get vertex candidates to try to generate possible unsubdivide solution. */
|
||||
/* First, get vertex candidates to try to generate possible un-subdivide solution. */
|
||||
/* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
|
||||
* part of the base mesh. If it isnt, then there is no solution. */
|
||||
* part of the base mesh. If it isn't, then there is no solution. */
|
||||
GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
|
||||
BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
|
||||
if (initial_vertex_pole != NULL) {
|
||||
|
@ -340,7 +363,9 @@ static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, i
|
|||
return valid_tag_found;
|
||||
}
|
||||
|
||||
/* Uses a flood fill operation to generate a different ID for each disconnected mesh element. */
|
||||
/**
|
||||
* Uses a flood fill operation to generate a different ID for each disconnected mesh element.
|
||||
*/
|
||||
static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
|
||||
{
|
||||
bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
|
||||
|
@ -378,8 +403,10 @@ static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
|
|||
return current_id;
|
||||
}
|
||||
|
||||
/* Builds a base mesh one subdiv level down from the current original mesh if the original mesh has
|
||||
* a valid solution stored in the BMVert tags. */
|
||||
/**
|
||||
* Builds a base mesh one subdivision level down from the current original mesh if the original
|
||||
* mesh has a valid solution stored in the #BMVert tags.
|
||||
*/
|
||||
static void unsubdivide_build_base_mesh_from_tags(BMesh *bm)
|
||||
{
|
||||
BMVert *v;
|
||||
|
@ -425,37 +452,42 @@ static void unsubdivide_build_base_mesh_from_tags(BMesh *bm)
|
|||
true);
|
||||
}
|
||||
|
||||
/* Main function to get a base mesh one level down from the current original mesh if it exists. */
|
||||
/* This searchs for different unsubdivide solutions and stores them as a combination of BMVert
|
||||
* flags for each disconnected mesh element. */
|
||||
/* If the solution for all elements are valid, it builds a new base mesh based on those tags by
|
||||
* dissolving and merging vertices. */
|
||||
/**
|
||||
* Main function to get a base mesh one level down from the current original mesh if it exists.
|
||||
*
|
||||
* This searches for different un-subdivide solutions and stores them as a combination of #BMVert
|
||||
* flags for each disconnected mesh element.
|
||||
*
|
||||
* If the solution for all elements are valid, it builds a new base mesh based on those tags by
|
||||
* dissolving and merging vertices.
|
||||
*/
|
||||
static bool multires_unsubdivide_single_level(BMesh *bm)
|
||||
{
|
||||
|
||||
/* Do a first check to make sure that it makes sense to search for unsubdivision in this mesh. */
|
||||
/* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
|
||||
*/
|
||||
if (!unsubdivide_is_all_quads(bm)) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/* Init the vertex table. */
|
||||
/* Initialize the vertex table. */
|
||||
BM_mesh_elem_table_init(bm, BM_VERT);
|
||||
BM_mesh_elem_table_ensure(bm, BM_VERT);
|
||||
|
||||
/* Build disconnected elements IDs. Each dissconnected mesh element is evaluated separatedly. */
|
||||
/* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
|
||||
int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID");
|
||||
const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
|
||||
|
||||
bool valid_tag_found = true;
|
||||
|
||||
/* Reset the BMesh flags as they are used to store data during the unsudivide process. */
|
||||
/* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
|
||||
|
||||
/* For each disconnected mesh element ID, search if an unsubdividie solution is possible. The
|
||||
* whole unsubdivide process fails if a single disconnected mesh element fails. */
|
||||
/* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
|
||||
* whole un-subdivide process fails if a single disconnected mesh element fails. */
|
||||
for (int id = 0; id < tot_ids; id++) {
|
||||
/* Try to the BMesh vertex flag tags corresponding to an unsubdivide solution. */
|
||||
/* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
|
||||
if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) {
|
||||
valid_tag_found = false;
|
||||
break;
|
||||
|
@ -472,7 +504,9 @@ static bool multires_unsubdivide_single_level(BMesh *bm)
|
|||
return valid_tag_found;
|
||||
}
|
||||
|
||||
/* Returns the next edge and vertex in the direction of a given edge. */
|
||||
/**
|
||||
* Returns the next edge and vertex in the direction of a given edge.
|
||||
*/
|
||||
static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
|
||||
{
|
||||
BMIter iter;
|
||||
|
@ -503,8 +537,10 @@ static BMFace *face_step(BMEdge *edge, BMFace *f)
|
|||
return f;
|
||||
}
|
||||
|
||||
/* Returns the other edge which belongs to the face f which is different from edge_x and shares
|
||||
* initial_vertex. */
|
||||
/**
|
||||
* Returns the other edge which belongs to the face f which is different from edge_x and shares
|
||||
* initial_vertex.
|
||||
*/
|
||||
static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
|
||||
{
|
||||
BMIter iter;
|
||||
|
@ -522,7 +558,8 @@ static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_ver
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop.
|
||||
/**
|
||||
* Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop.
|
||||
*/
|
||||
static void write_loop_in_face_grid(
|
||||
float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
|
||||
|
@ -581,8 +618,10 @@ static void write_loop_in_face_grid(
|
|||
}
|
||||
}
|
||||
|
||||
/* Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into
|
||||
* the main MultiresUnsubdivideGrid that is being extracted. */
|
||||
/**
|
||||
* Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into
|
||||
* the main #MultiresUnsubdivideGrid that is being extracted.
|
||||
*/
|
||||
static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid,
|
||||
float (*face_grid)[3],
|
||||
int face_grid_size,
|
||||
|
@ -603,9 +642,12 @@ static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid,
|
|||
}
|
||||
}
|
||||
|
||||
/* Stores the data from the mdisps grids of the loops of the face f into the new grid for the new
|
||||
* base mesh. */
|
||||
/* Used when there are already grids in the original mesh. */
|
||||
/**
|
||||
* Stores the data from the mdisps grids of the loops of the face f
|
||||
* into the new grid for the new base mesh.
|
||||
*
|
||||
* Used when there are already grids in the original mesh.
|
||||
*/
|
||||
static void store_grid_data(MultiresUnsubdivideContext *context,
|
||||
MultiresUnsubdivideGrid *grid,
|
||||
BMVert *v,
|
||||
|
@ -620,7 +662,7 @@ static void store_grid_data(MultiresUnsubdivideContext *context,
|
|||
const int corner_vertex_index = BM_elem_index_get(v);
|
||||
|
||||
/* Calculates an offset to write the grids correctly oriented in the main
|
||||
* MultiresUnsubdivideGrid. */
|
||||
* #MultiresUnsubdivideGrid. */
|
||||
int loop_offset = 0;
|
||||
for (int i = 0; i < poly->totloop; i++) {
|
||||
const int loop_index = poly->loopstart + i;
|
||||
|
@ -650,15 +692,17 @@ static void store_grid_data(MultiresUnsubdivideContext *context,
|
|||
write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
|
||||
}
|
||||
|
||||
/* Write the face_grid buffer in the correct position in the MultiresUnsubdivideGrids that is
|
||||
/* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
|
||||
* being extracted. */
|
||||
write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
|
||||
|
||||
MEM_freeN(face_grid);
|
||||
}
|
||||
|
||||
/* Stores the data into the new grid from a bmesh vertex. Used when there are no grids in the
|
||||
* original mesh. */
|
||||
/**
|
||||
* Stores the data into the new grid from a #BMVert.
|
||||
* Used when there are no grids in the original mesh.
|
||||
*/
|
||||
static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
|
||||
{
|
||||
const int remap_index_y = grid->grid_size - 1 - grid_x;
|
||||
|
@ -669,7 +713,8 @@ static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid
|
|||
copy_v3_v3(grid->grid_co[grid_index], v->co);
|
||||
}
|
||||
|
||||
/* Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh.
|
||||
/**
|
||||
* Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh.
|
||||
*/
|
||||
static void multires_unsubdivide_extract_single_grid_from_face_edge(
|
||||
MultiresUnsubdivideContext *context,
|
||||
|
@ -743,7 +788,7 @@ static void multires_unsubdivide_extract_single_grid_from_face_edge(
|
|||
edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x);
|
||||
}
|
||||
else {
|
||||
/* If there were grids in the original mesh, extrat the data from the grids and iterate
|
||||
/* If there were grids in the original mesh, extract the data from the grids and iterate
|
||||
* over the faces. */
|
||||
store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
|
||||
edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x);
|
||||
|
@ -780,9 +825,12 @@ static void multires_unsubdivide_extract_single_grid_from_face_edge(
|
|||
}
|
||||
}
|
||||
|
||||
/* Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge
|
||||
* e1 is going to be extracted. */
|
||||
/* These vertes should always have an corresponding existing vertex on the base mesh. */
|
||||
/**
|
||||
* Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge
|
||||
* e1 is going to be extracted.
|
||||
*
|
||||
* These vertices should always have an corresponding existing vertex on the base mesh.
|
||||
*/
|
||||
static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1,
|
||||
BMEdge *e1,
|
||||
BMVert **r_corner_x,
|
||||
|
@ -842,7 +890,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
|
|||
return bm;
|
||||
}
|
||||
|
||||
/* Datalayer names to store the original indices of the elements before modifying the mesh. */
|
||||
/* Data-layer names to store the original indices of the elements before modifying the mesh. */
|
||||
static const char lname[] = "l_remap_index";
|
||||
static const char vname[] = "v_remap_index";
|
||||
|
||||
|
@ -859,8 +907,10 @@ static void multires_unsubdivide_free_original_datalayers(Mesh *mesh)
|
|||
}
|
||||
}
|
||||
|
||||
/* Generates two datalayers to map loops and vertices from base mesh to original mesh after
|
||||
* dissolving the vertices. */
|
||||
/**
|
||||
* Generates two data-layers to map loops and vertices from base mesh to original mesh after
|
||||
* dissolving the vertices.
|
||||
*/
|
||||
static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh)
|
||||
{
|
||||
multires_unsubdivide_free_original_datalayers(mesh);
|
||||
|
@ -871,7 +921,7 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh)
|
|||
int *v_index = CustomData_add_layer_named(
|
||||
&mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname);
|
||||
|
||||
/* Init these datalayer with the indicies in the current mesh. */
|
||||
/* Initialize these data-layer with the indices in the current mesh. */
|
||||
for (int i = 0; i < mesh->totloop; i++) {
|
||||
l_index[i] = i;
|
||||
}
|
||||
|
@ -889,7 +939,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
|
|||
|
||||
BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
|
||||
|
||||
/* Init the elem tables. */
|
||||
/* Initialize the elem tables. */
|
||||
BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE);
|
||||
BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE);
|
||||
BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT);
|
||||
|
@ -900,7 +950,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
|
|||
BM_mesh_elem_hflag_disable_all(
|
||||
bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
|
||||
|
||||
/* Get the mapping datalayer. */
|
||||
/* Get the mapping data-layer. */
|
||||
context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname);
|
||||
|
||||
/* Tag the base mesh vertices in the original mesh. */
|
||||
|
@ -922,8 +972,10 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
|
|||
}
|
||||
}
|
||||
|
||||
/* Checks the orientation of the loops to flip the x and y axis when extracting the grid if
|
||||
* necessary. */
|
||||
/**
|
||||
* Checks the orientation of the loops to flip the x and y axis when extracting the grid if
|
||||
* necessary.
|
||||
*/
|
||||
static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
|
||||
{
|
||||
MPoly *p = &mesh->mpoly[poly];
|
||||
|
@ -955,7 +1007,7 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
|
|||
context->base_mesh_grids = MEM_calloc_arrayN(
|
||||
sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids");
|
||||
|
||||
/* Based on the exising indicies in the datalayers, generate two vertex indices maps. */
|
||||
/* 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");
|
||||
|
@ -977,8 +1029,8 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
|
|||
orig_to_base_vmap[orig_vertex_index] = i;
|
||||
}
|
||||
|
||||
/* Add the original datalayers to the base mesh to have the loop indicies stored in a datalayer,
|
||||
* so they can be used from BMesh. */
|
||||
/* 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(
|
||||
|
@ -991,14 +1043,14 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
|
|||
BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT);
|
||||
BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE);
|
||||
|
||||
/* Get the datalayer that contains the loops indicies. */
|
||||
/* Get the data-layer that contains the loops indices. */
|
||||
const int base_l_offset = CustomData_get_n_offset(
|
||||
&bm_base_mesh->ldata, CD_PROP_INT, 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. */
|
||||
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);
|
||||
|
@ -1074,11 +1126,11 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
|
|||
{
|
||||
Mesh *original_mesh = context->original_mesh;
|
||||
|
||||
/* Prepare the datalayers to map base to original. */
|
||||
/* Prepare the data-layers to map base to original. */
|
||||
multires_unsubdivide_add_original_index_datalayers(original_mesh);
|
||||
BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
|
||||
|
||||
/* Unsubdivide as many iterations as possible. */
|
||||
/* Un-subdivide as many iterations as possible. */
|
||||
context->num_new_levels = 0;
|
||||
int num_levels_left = context->max_new_levels;
|
||||
while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
|
||||
|
@ -1086,7 +1138,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
|
|||
num_levels_left--;
|
||||
}
|
||||
|
||||
/* If no unsubdivide steps were possible, free the bmesh, the map datalayers and stop. */
|
||||
/* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
|
||||
if (context->num_new_levels == 0) {
|
||||
multires_unsubdivide_free_original_datalayers(original_mesh);
|
||||
BM_mesh_free(bm_base_mesh);
|
||||
|
@ -1096,7 +1148,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
|
|||
/* Calculate the final levels for the new grids over base mesh. */
|
||||
context->num_total_levels = context->num_new_levels + context->num_original_levels;
|
||||
|
||||
/* Store the new basemesh as a mesh in context, free bmesh. */
|
||||
/* Store the new base-mesh as a mesh in context, free bmesh. */
|
||||
context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
|
||||
BM_mesh_bm_to_me(NULL,
|
||||
bm_base_mesh,
|
||||
|
@ -1106,7 +1158,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
|
|||
}));
|
||||
BM_mesh_free(bm_base_mesh);
|
||||
|
||||
/* Init bmesh and maps for the original mesh and extract the grids. */
|
||||
/* Initialize bmesh and maps for the original mesh and extract the grids. */
|
||||
|
||||
multires_unsubdivide_prepare_original_bmesh_for_extract(context);
|
||||
multires_unsubdivide_extract_grids(context);
|
||||
|
@ -1125,8 +1177,10 @@ void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context)
|
|||
MEM_SAFE_FREE(context->base_mesh_grids);
|
||||
}
|
||||
|
||||
/* This functiona allocates new mdisps with the right size to fit the new extracted grids from the
|
||||
* base mesh and copies the data to them. */
|
||||
/**
|
||||
* This function allocates new mdisps with the right size to fit the new extracted grids from the
|
||||
* base mesh and copies the data to them.
|
||||
*/
|
||||
static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context,
|
||||
Mesh *base_mesh)
|
||||
{
|
||||
|
@ -1191,7 +1245,7 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
|
|||
/* Set the limit for the levels that should be rebuild. */
|
||||
unsubdiv_context.max_new_levels = rebuild_limit;
|
||||
|
||||
/* Unsubdivide and create the data for the new grids. */
|
||||
/* Un-subdivide and create the data for the new grids. */
|
||||
if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
|
||||
/* If there was no possible to rebuild any level, free the data and return. */
|
||||
if (mmd->totlvl != 0) {
|
||||
|
@ -1227,15 +1281,15 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
|
|||
|
||||
mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels);
|
||||
|
||||
/* Create a resape context to convert the MDISPS data to tangent displacement. It can be the same
|
||||
* as the previous one as a new Subdiv needs to be created for the new base mesh. */
|
||||
/* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
|
||||
* same as the previous one as a new Subdivision needs to be created for the new base mesh. */
|
||||
if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
|
||||
return 0;
|
||||
}
|
||||
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
|
||||
multires_reshape_context_free(&reshape_context);
|
||||
|
||||
/* Free the unsubdivide context and return the total number of levels that were rebuild. */
|
||||
/* Free the un-subdivide context and return the total number of levels that were rebuild. */
|
||||
const int rebuild_subdvis = unsubdiv_context.num_new_levels;
|
||||
multires_unsubdivide_context_free(&unsubdiv_context);
|
||||
|
||||
|
|
|
@ -37,34 +37,35 @@ typedef struct MultiresUnsubdivideGrid {
|
|||
int grid_index;
|
||||
int grid_size;
|
||||
|
||||
/* Grid coordinates in object space. */
|
||||
/** Grid coordinates in object space. */
|
||||
float (*grid_co)[3];
|
||||
|
||||
} MultiresUnsubdivideGrid;
|
||||
|
||||
typedef struct MultiresUnsubdivideContext {
|
||||
/* Input Mesh to unsubdivide. */
|
||||
/* Input Mesh to un-subdivide. */
|
||||
struct Mesh *original_mesh;
|
||||
struct MDisps *original_mdisp;
|
||||
|
||||
/* Number of subdivision in the grids of the input mesh. */
|
||||
/** Number of subdivision in the grids of the input mesh. */
|
||||
int num_original_levels;
|
||||
|
||||
/* Level 0 base mesh after applying the maximum amount of unsubdivisions. */
|
||||
/** Level 0 base mesh after applying the maximum amount of unsubdivisions. */
|
||||
struct Mesh *base_mesh;
|
||||
|
||||
/* Limit on how many levels down the unsubdivide operation should create, if possible. */
|
||||
/** Limit on how many levels down the unsubdivide operation should create, if possible. */
|
||||
int max_new_levels;
|
||||
|
||||
/* New levels that were created after unsubdividing. */
|
||||
/** New levels that were created after unsubdividing. */
|
||||
int num_new_levels;
|
||||
|
||||
/* Number of subdivisions that should be applied to the base mesh. (num_new_levels +
|
||||
* num_original_levels)
|
||||
/**
|
||||
* Number of subdivisions that should be applied to the base mesh.
|
||||
* (num_new_levels + num_original_levels).
|
||||
*/
|
||||
int num_total_levels;
|
||||
|
||||
/* Data for the new grids, indexed by base mesh loop index. */
|
||||
/** Data for the new grids, indexed by base mesh loop index. */
|
||||
int num_grids;
|
||||
struct MultiresUnsubdivideGrid *base_mesh_grids;
|
||||
|
||||
|
@ -74,7 +75,7 @@ typedef struct MultiresUnsubdivideContext {
|
|||
int *base_to_orig_vmap;
|
||||
} MultiresUnsubdivideContext;
|
||||
|
||||
/* ================================================================================================
|
||||
/* --------------------------------------------------------------------
|
||||
* Construct/destruct reshape context.
|
||||
*/
|
||||
|
||||
|
@ -83,7 +84,7 @@ void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
|
|||
struct MultiresModifierData *mmd);
|
||||
void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context);
|
||||
|
||||
/* ================================================================================================
|
||||
/* --------------------------------------------------------------------
|
||||
* Rebuild Lower Subdivisions.
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in New Issue