Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/multires_reshape_smooth.c')
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c268
1 files changed, 229 insertions, 39 deletions
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 0fe0ac4b66a..7312ac2bf5e 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -95,6 +95,30 @@ typedef struct Edge {
float sharpness;
} Edge;
+/* Storage of data which is linearly interpolated from the reshape level to the top level. */
+
+typedef struct LinearGridElement {
+ float mask;
+} LinearGridElement;
+
+typedef struct LinearGrid {
+ LinearGridElement *elements;
+} LinearGrid;
+
+typedef struct LinearGrids {
+ int num_grids;
+ int level;
+
+ /* Cached size for the grid, for faster lookup. */
+ int grid_size;
+
+ /* Indexed by grid index. */
+ LinearGrid *grids;
+
+ /* Elements for all grids are allocated in a single array, for the allocation performance. */
+ LinearGridElement *elements_storage;
+} LinearGrids;
+
/* Context which holds all information eeded during propagation and smoothing. */
typedef struct MultiresReshapeSmoothContext {
@@ -122,6 +146,10 @@ typedef struct MultiresReshapeSmoothContext {
Face *faces;
} geometry;
+ /* Grids of data which is linearly interpolated between grid elements at the reshape level.
+ * The data is actually stored as a delta, which is then to be added to the higher levels. */
+ LinearGrids linear_delta_grids;
+
/* Index i of this map indicates that base edge i is adjacent to at least one face. */
BLI_bitmap *non_loose_base_edge_map;
@@ -150,51 +178,79 @@ typedef struct MultiresReshapeSmoothContext {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Masks
+/** \name Linear grids manipulation
* \{ */
-/* Interpolate mask grid at a reshape level.
- * Will return 0 if there is no masks custom data layer. */
-static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_smooth_context,
- const GridCoord *grid_coord)
+static void linear_grids_init(LinearGrids *linear_grids)
{
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- if (reshape_context->orig.grid_paint_masks == NULL) {
- return 0.0f;
- }
+ linear_grids->num_grids = 0;
+ linear_grids->level = 0;
- const GridPaintMask *grid = &reshape_context->orig.grid_paint_masks[grid_coord->grid_index];
- const int grid_size = BKE_subdiv_grid_size_from_level(grid->level);
- const int grid_size_1 = grid_size - 1;
- const float grid_size_1_inv = 1.0f / (float)(grid_size_1);
+ linear_grids->grids = NULL;
+ linear_grids->elements_storage = NULL;
+}
- const float x_f = grid_coord->u * grid_size_1;
- const float y_f = grid_coord->v * grid_size_1;
+static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
+{
+ const size_t grid_size = BKE_subdiv_grid_size_from_level(level);
+ const size_t grid_area = grid_size * grid_size;
+ const size_t num_grid_elements = num_grids * grid_area;
- const int x_i = x_f;
- const int y_i = y_f;
- const int x_n_i = (x_i == grid_size - 1) ? (x_i) : (x_i + 1);
- const int y_n_i = (y_i == grid_size - 1) ? (y_i) : (y_i + 1);
+ linear_grids->num_grids = num_grids;
+ linear_grids->level = level;
+ linear_grids->grid_size = grid_size;
- const int corners[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
- float mask_elements[4];
- for (int i = 0; i < 4; ++i) {
- GridCoord corner_grid_coord;
- corner_grid_coord.grid_index = grid_coord->grid_index;
- corner_grid_coord.u = corners[i][0] * grid_size_1_inv;
- corner_grid_coord.v = corners[i][1] * grid_size_1_inv;
+ linear_grids->grids = MEM_malloc_arrayN(num_grids, sizeof(LinearGrid), "linear grids");
+ linear_grids->elements_storage = MEM_calloc_arrayN(
+ num_grid_elements, sizeof(LinearGridElement), "linear elements storage");
- ReshapeConstGridElement element = multires_reshape_orig_grid_element_for_grid_coord(
- reshape_context, &corner_grid_coord);
- mask_elements[i] = element.mask;
+ for (int i = 0; i < num_grids; ++i) {
+ const size_t element_offset = grid_area * i;
+ linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset];
}
+}
- const float u = x_f - x_i;
- const float v = y_f - y_i;
- const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+static LinearGridElement *linear_grid_element_get(const LinearGrids *linear_grids,
+ const GridCoord *grid_coord)
+{
+ BLI_assert(grid_coord->grid_index >= 0);
+ BLI_assert(grid_coord->grid_index < linear_grids->num_grids);
+
+ const int grid_size = linear_grids->grid_size;
- return mask_elements[0] * weights[0] + mask_elements[1] * weights[1] +
- mask_elements[2] * weights[2] + mask_elements[3] * weights[3];
+ const int grid_x = lround(grid_coord->u * (grid_size - 1));
+ const int grid_y = lround(grid_coord->v * (grid_size - 1));
+ const int grid_element_index = grid_y * grid_size + grid_x;
+
+ LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index];
+ return &grid->elements[grid_element_index];
+}
+
+static void linear_grids_free(LinearGrids *linear_grids)
+{
+ MEM_SAFE_FREE(linear_grids->grids);
+ MEM_SAFE_FREE(linear_grids->elements_storage);
+}
+
+static void linear_grid_element_init(LinearGridElement *linear_grid_element)
+{
+ linear_grid_element->mask = 0.0f;
+}
+
+/* result = a - b. */
+static void linear_grid_element_sub(LinearGridElement *result,
+ const LinearGridElement *a,
+ const LinearGridElement *b)
+{
+ result->mask = a->mask - b->mask;
+}
+
+static void linear_grid_element_interpolate(LinearGridElement *result,
+ const LinearGridElement elements[4],
+ const float weights[4])
+{
+ result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] +
+ elements[2].mask * weights[2] + elements[3].mask * weights[3];
}
/** \} */
@@ -465,6 +521,8 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
reshape_smooth_context->geometry.num_faces = 0;
reshape_smooth_context->geometry.faces = NULL;
+ linear_grids_init(&reshape_smooth_context->linear_delta_grids);
+
reshape_smooth_context->non_loose_base_edge_map = NULL;
reshape_smooth_context->reshape_subdiv = NULL;
reshape_smooth_context->base_surface_grids = NULL;
@@ -483,6 +541,8 @@ static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_c
MEM_SAFE_FREE(reshape_smooth_context->geometry.corners);
MEM_SAFE_FREE(reshape_smooth_context->geometry.faces);
MEM_SAFE_FREE(reshape_smooth_context->geometry.edges);
+
+ linear_grids_free(&reshape_smooth_context->linear_delta_grids);
}
static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -1101,6 +1161,133 @@ static void reshape_subdiv_evaluate_limit_at_grid(
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Linearly interpolated data
+ * \{ */
+
+static LinearGridElement linear_grid_element_orig_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ linear_grid_element.mask = orig_grid_element.mask;
+
+ return linear_grid_element;
+}
+
+static LinearGridElement linear_grid_element_final_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeGridElement final_grid_element = multires_reshape_grid_element_for_grid_coord(
+ reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ if (final_grid_element.mask != NULL) {
+ linear_grid_element.mask = *final_grid_element.mask;
+ }
+
+ return linear_grid_element;
+}
+
+/* Interpolate difference of the linear data.
+ *
+ * Will access final data and original data at the grid elements at the reshape level,
+ * calculate difference between final and original, and linearly interpolate to get value at the
+ * top level. */
+static void linear_grid_element_delta_interpolate(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const GridCoord *grid_coord,
+ LinearGridElement *result)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ const int reshape_level = reshape_context->reshape.level;
+ const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
+ const float reshape_level_grid_size_1_inv = 1.0f / (float)(reshape_level_grid_size_1);
+
+ const float x_f = grid_coord->u * reshape_level_grid_size_1;
+ const float y_f = grid_coord->v * reshape_level_grid_size_1;
+
+ const int x_i = x_f;
+ const int y_i = y_f;
+ const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1);
+ const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1);
+
+ const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
+
+ LinearGridElement corner_elements[4];
+ for (int i = 0; i < 4; ++i) {
+ GridCoord corner_grid_coord;
+ corner_grid_coord.grid_index = grid_coord->grid_index;
+ corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv;
+ corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv;
+
+ const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context,
+ &corner_grid_coord);
+ const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context,
+ &corner_grid_coord);
+ linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element);
+ }
+
+ const float u = x_f - x_i;
+ const float v = y_f - y_i;
+ const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+
+ linear_grid_element_interpolate(result, corner_elements, weights);
+}
+
+static void evaluate_linear_delta_grids_callback(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const PTexCoord *UNUSED(ptex_coord),
+ const GridCoord *grid_coord,
+ void *UNUSED(userdata_v))
+{
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ linear_grid_element_delta_interpolate(reshape_smooth_context, grid_coord, linear_delta_element);
+}
+
+static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const int num_grids = reshape_context->num_grids;
+ const int top_level = reshape_context->top.level;
+
+ linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level);
+
+ foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_linear_delta_grids_callback, NULL);
+}
+
+static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ ReshapeGridElement *final_grid_element,
+ const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ if (final_grid_element->mask != NULL) {
+ *final_grid_element->mask = clamp_f(
+ orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Evaluation of base surface
* \{ */
@@ -1201,7 +1388,11 @@ static void evaluate_higher_grid_positions_with_details_callback(
grid_coord);
add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta);
+
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
+
static void evaluate_higher_grid_positions_with_details(
const MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -1222,17 +1413,14 @@ static void evaluate_higher_grid_positions_callback(
grid_coord);
/* Surface. */
-
float P[3];
BKE_subdiv_eval_limit_point(
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
copy_v3_v3(grid_element.displacement, P);
- /* Masks. */
- if (grid_element.mask != NULL) {
- *grid_element.mask = interpolate_masks_grid(reshape_smooth_context, grid_coord);
- }
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
static void evaluate_higher_grid_positions(
@@ -1266,6 +1454,7 @@ void multires_reshape_smooth_object_grids_with_details(
}
geometry_create(&reshape_smooth_context);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);
@@ -1292,6 +1481,7 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
context_init(&reshape_smooth_context, reshape_context, mode);
geometry_create(&reshape_smooth_context);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);