|
|
|
|
@@ -44,6 +44,8 @@
|
|
|
|
|
#include "BKE_subdiv.h"
|
|
|
|
|
#include "BKE_subdiv_eval.h"
|
|
|
|
|
|
|
|
|
|
#include "opensubdiv_topology_refiner_capi.h"
|
|
|
|
|
|
|
|
|
|
/* =============================================================================
|
|
|
|
|
* Generally useful internal helpers.
|
|
|
|
|
*/
|
|
|
|
|
@@ -122,6 +124,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg,
|
|
|
|
|
{
|
|
|
|
|
const int element_size = element_size_bytes_get(subdiv_ccg);
|
|
|
|
|
/* Allocate memory for surface grids. */
|
|
|
|
|
const int num_faces = coarse_mesh->totpoly;
|
|
|
|
|
const int num_grids = coarse_mesh->totloop;
|
|
|
|
|
const int grid_size = grid_size_for_level_get(
|
|
|
|
|
subdiv_ccg, subdiv_ccg->level);
|
|
|
|
|
@@ -149,6 +152,14 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg,
|
|
|
|
|
BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
|
|
|
|
|
}
|
|
|
|
|
/* TOOD(sergey): Allocate memory for loose elements. */
|
|
|
|
|
/* Allocate memory for faces. */
|
|
|
|
|
subdiv_ccg->num_faces = num_faces;
|
|
|
|
|
if (num_faces) {
|
|
|
|
|
subdiv_ccg->faces = MEM_calloc_arrayN(
|
|
|
|
|
num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
|
|
|
|
|
subdiv_ccg->grid_faces = MEM_calloc_arrayN(
|
|
|
|
|
num_grids, sizeof(SubdivCCGFace*), "Subdiv CCG grid faces");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* =============================================================================
|
|
|
|
|
@@ -219,9 +230,11 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
|
|
|
|
|
const int grid_size = subdiv_ccg->grid_size;
|
|
|
|
|
const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
|
|
|
|
|
const int element_size = element_size_bytes_get(subdiv_ccg);
|
|
|
|
|
SubdivCCGFace *faces = subdiv_ccg->faces;
|
|
|
|
|
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
|
|
|
|
|
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
|
|
|
|
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
|
|
|
|
|
coarse_poly->loopstart + corner];
|
|
|
|
|
const int grid_index = coarse_poly->loopstart + corner;
|
|
|
|
|
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
|
|
|
|
|
for (int y = 0; y < grid_size; y++) {
|
|
|
|
|
const float grid_v = (float)y * grid_size_1_inv;
|
|
|
|
|
for (int x = 0; x < grid_size; x++) {
|
|
|
|
|
@@ -237,6 +250,8 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
|
|
|
|
|
&grid[grid_element_offset]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Assign grid's face. */
|
|
|
|
|
grid_faces[grid_index] = &faces[coarse_poly_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -248,9 +263,11 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
|
|
|
|
|
const int grid_size = subdiv_ccg->grid_size;
|
|
|
|
|
const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
|
|
|
|
|
const int element_size = element_size_bytes_get(subdiv_ccg);
|
|
|
|
|
SubdivCCGFace *faces = subdiv_ccg->faces;
|
|
|
|
|
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
|
|
|
|
|
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
|
|
|
|
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[
|
|
|
|
|
coarse_poly->loopstart + corner];
|
|
|
|
|
const int grid_index = coarse_poly->loopstart + corner;
|
|
|
|
|
unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
|
|
|
|
|
for (int y = 0; y < grid_size; y++) {
|
|
|
|
|
const float u = 1.0f - ((float)y * grid_size_1_inv);
|
|
|
|
|
for (int x = 0; x < grid_size; x++) {
|
|
|
|
|
@@ -266,6 +283,8 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
|
|
|
|
|
&grid[grid_element_offset]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Assign grid's face. */
|
|
|
|
|
grid_faces[grid_index] = &faces[coarse_poly_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -275,6 +294,7 @@ static void subdiv_ccg_eval_grids_task(
|
|
|
|
|
const ParallelRangeTLS *__restrict UNUSED(tls))
|
|
|
|
|
{
|
|
|
|
|
CCGEvalGridsData *data = userdata_v;
|
|
|
|
|
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
|
|
|
|
|
const Mesh *coarse_mesh = data->coarse_mesh;
|
|
|
|
|
const MPoly *coarse_mpoly = coarse_mesh->mpoly;
|
|
|
|
|
const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
|
|
|
|
|
@@ -284,6 +304,10 @@ static void subdiv_ccg_eval_grids_task(
|
|
|
|
|
else {
|
|
|
|
|
subdiv_ccg_eval_special_grid(data, coarse_poly);
|
|
|
|
|
}
|
|
|
|
|
/* Assign information in the faces. */
|
|
|
|
|
subdiv_ccg->faces[coarse_poly_index].num_grids = coarse_poly->totloop;
|
|
|
|
|
subdiv_ccg->faces[coarse_poly_index].start_grid_index =
|
|
|
|
|
coarse_poly->loopstart;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool subdiv_ccg_evaluate_grids(
|
|
|
|
|
@@ -330,6 +354,7 @@ SubdivCCG *BKE_subdiv_to_ccg(
|
|
|
|
|
{
|
|
|
|
|
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
|
|
|
|
SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
|
|
|
|
|
subdiv_ccg->subdiv = subdiv;
|
|
|
|
|
subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
|
|
|
|
|
subdiv_ccg->grid_size =
|
|
|
|
|
grid_size_for_level_get(subdiv_ccg, subdiv_ccg->level);
|
|
|
|
|
@@ -341,7 +366,6 @@ SubdivCCG *BKE_subdiv_to_ccg(
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
|
|
|
|
subdiv_ccg->subdiv = subdiv;
|
|
|
|
|
return subdiv_ccg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -378,6 +402,7 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
|
|
|
|
|
if (subdiv_ccg->subdiv != NULL) {
|
|
|
|
|
BKE_subdiv_free(subdiv_ccg->subdiv);
|
|
|
|
|
}
|
|
|
|
|
MEM_SAFE_FREE(subdiv_ccg->faces);
|
|
|
|
|
MEM_freeN(subdiv_ccg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -528,7 +553,8 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
|
|
|
|
|
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
|
|
|
|
|
RecalcInnerNormalsData data = {
|
|
|
|
|
.subdiv_ccg = subdiv_ccg,
|
|
|
|
|
.key = &key};
|
|
|
|
|
.key = &key
|
|
|
|
|
};
|
|
|
|
|
RecalcInnerNormalsTLSData tls_data = {NULL};
|
|
|
|
|
ParallelRangeSettings parallel_range_settings;
|
|
|
|
|
BLI_parallel_range_settings_defaults(¶llel_range_settings);
|
|
|
|
|
@@ -549,4 +575,76 @@ void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
|
|
|
|
|
BKE_subdiv_ccg_average_grids(subdiv_ccg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* =============================================================================
|
|
|
|
|
* Boundary averaging/stitching.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct AverageInnerGridsData {
|
|
|
|
|
SubdivCCG *subdiv_ccg;
|
|
|
|
|
CCGKey *key;
|
|
|
|
|
} AverageInnerGridsData;
|
|
|
|
|
|
|
|
|
|
static void average_grid_element_value_v3(float a[3], float b[3])
|
|
|
|
|
{
|
|
|
|
|
add_v3_v3(a, b);
|
|
|
|
|
mul_v3_fl(a, 0.5f);
|
|
|
|
|
copy_v3_v3(b, a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void average_grid_element(SubdivCCG *subdiv_ccg,
|
|
|
|
|
CCGKey *key,
|
|
|
|
|
CCGElem *grid_element_a,
|
|
|
|
|
CCGElem *grid_element_b)
|
|
|
|
|
{
|
|
|
|
|
average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
|
|
|
|
|
CCG_elem_co(key, grid_element_b));
|
|
|
|
|
if (subdiv_ccg->has_normal) {
|
|
|
|
|
average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
|
|
|
|
|
CCG_elem_no(key, grid_element_b));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void subdiv_ccg_average_inner_grids_task(
|
|
|
|
|
void *__restrict userdata_v,
|
|
|
|
|
const int face_index,
|
|
|
|
|
const ParallelRangeTLS *__restrict UNUSED(tls_v))
|
|
|
|
|
{
|
|
|
|
|
AverageInnerGridsData *data = userdata_v;
|
|
|
|
|
SubdivCCG *subdiv_ccg = data->subdiv_ccg;
|
|
|
|
|
CCGKey *key = data->key;
|
|
|
|
|
CCGElem **grids = subdiv_ccg->grids;
|
|
|
|
|
SubdivCCGFace *faces = subdiv_ccg->faces;
|
|
|
|
|
SubdivCCGFace *face = &faces[face_index];
|
|
|
|
|
const int num_face_grids = face->num_grids;
|
|
|
|
|
const int grid_size = subdiv_ccg->grid_size;
|
|
|
|
|
CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
|
|
|
|
|
for (int corner = 0; corner < num_face_grids; corner++) {
|
|
|
|
|
CCGElem *grid = grids[face->start_grid_index + corner];
|
|
|
|
|
for (int i = 0; i < grid_size; i++) {
|
|
|
|
|
CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
|
|
|
|
|
CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
|
|
|
|
|
average_grid_element(
|
|
|
|
|
subdiv_ccg, key, prev_grid_element, grid_element);
|
|
|
|
|
}
|
|
|
|
|
prev_grid = grid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg)
|
|
|
|
|
{
|
|
|
|
|
CCGKey key;
|
|
|
|
|
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
|
|
|
|
|
AverageInnerGridsData data = {
|
|
|
|
|
.subdiv_ccg = subdiv_ccg,
|
|
|
|
|
.key = &key,
|
|
|
|
|
};
|
|
|
|
|
ParallelRangeSettings parallel_range_settings;
|
|
|
|
|
BLI_parallel_range_settings_defaults(¶llel_range_settings);
|
|
|
|
|
BLI_task_parallel_range(0, subdiv_ccg->num_faces,
|
|
|
|
|
&data,
|
|
|
|
|
subdiv_ccg_average_inner_grids_task,
|
|
|
|
|
¶llel_range_settings);
|
|
|
|
|
}
|
|
|
|
|
|