diff options
Diffstat (limited to 'source/blender/blenkernel/intern/subdiv_ccg.c')
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_ccg.c | 148 |
1 files changed, 131 insertions, 17 deletions
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index bfcd4b8d52d..c35b38b4184 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -41,6 +41,19 @@ #include "opensubdiv_topology_refiner_capi.h" /* ============================================================================= + * Various forward declarations. + */ + +static void subdiv_ccg_average_all_boundaries_and_corners( + SubdivCCG *subdiv_ccg, + CCGKey *key); + +static void subdiv_ccg_average_inner_face_grids( + SubdivCCG *subdiv_ccg, + CCGKey *key, + SubdivCCGFace *face); + +/* ============================================================================= * Generally useful internal helpers. */ @@ -163,7 +176,8 @@ typedef struct CCGEvalGridsData { SubdivCCG *subdiv_ccg; Subdiv *subdiv; int *face_ptex_offset; - SubdivCCGMask *mask_evaluator; + SubdivCCGMaskEvaluator *mask_evaluator; + SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator; } CCGEvalGridsData; static void subdiv_ccg_eval_grid_element( @@ -232,6 +246,10 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, } /* Assign grid's face. */ grid_faces[grid_index] = &faces[face_index]; + /* Assign material flags. */ + subdiv_ccg->grid_flag_mats[grid_index] = + data->material_flags_evaluator->eval_material_flags( + data->material_flags_evaluator, face_index); } } @@ -247,13 +265,13 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const SubdivCCGFace *face = &faces[face_index]; for (int corner = 0; corner < face->num_grids; corner++) { const int grid_index = face->start_grid_index + corner; + const int ptex_face_index = + data->face_ptex_offset[face_index] + 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++) { const float v = 1.0f - ((float)x * grid_size_1_inv); - const int ptex_face_index = - data->face_ptex_offset[face_index] + corner; const size_t grid_element_index = (size_t)y * grid_size + x; const size_t grid_element_offset = grid_element_index * element_size; @@ -265,6 +283,10 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, } /* Assign grid's face. */ grid_faces[grid_index] = &faces[face_index]; + /* Assign material flags. */ + subdiv_ccg->grid_flag_mats[grid_index] = + data->material_flags_evaluator->eval_material_flags( + data->material_flags_evaluator, face_index); } } @@ -287,7 +309,8 @@ static void subdiv_ccg_eval_grids_task( static bool subdiv_ccg_evaluate_grids( SubdivCCG *subdiv_ccg, Subdiv *subdiv, - SubdivCCGMask *mask_evaluator) + SubdivCCGMaskEvaluator *mask_evaluator, + SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator) { OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; const int num_faces = topology_refiner->getNumFaces(topology_refiner); @@ -297,6 +320,7 @@ static bool subdiv_ccg_evaluate_grids( data.subdiv = subdiv; data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); data.mask_evaluator = mask_evaluator; + data.material_flags_evaluator = material_flags_evaluator; /* Threaded grids evaluation. */ ParallelRangeSettings parallel_range_settings; BLI_parallel_range_settings_defaults(¶llel_range_settings); @@ -591,7 +615,8 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg) SubdivCCG *BKE_subdiv_to_ccg( Subdiv *subdiv, const SubdivToCCGSettings *settings, - SubdivCCGMask *mask_evaluator) + SubdivCCGMaskEvaluator *mask_evaluator, + SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator) { BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg"); @@ -602,7 +627,8 @@ SubdivCCG *BKE_subdiv_to_ccg( subdiv_ccg_alloc_elements(subdiv_ccg, subdiv); subdiv_ccg_init_faces(subdiv_ccg); subdiv_ccg_init_faces_neighborhood(subdiv_ccg); - if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, mask_evaluator)) { + if (!subdiv_ccg_evaluate_grids( + subdiv_ccg, subdiv, mask_evaluator, material_flags_evaluator)) { BKE_subdiv_ccg_destroy(subdiv_ccg); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); return NULL; @@ -624,11 +650,17 @@ Mesh *BKE_subdiv_to_ccg_mesh( } } BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); - SubdivCCGMask mask_evaluator; + SubdivCCGMaskEvaluator mask_evaluator; bool has_mask = BKE_subdiv_ccg_mask_init_from_paint( - &mask_evaluator, coarse_mesh); + &mask_evaluator, coarse_mesh); + SubdivCCGMaterialFlagsEvaluator material_flags_evaluator; + BKE_subdiv_ccg_material_flags_init_from_mesh( + &material_flags_evaluator, coarse_mesh); SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg( - subdiv, settings, has_mask ? &mask_evaluator : NULL); + subdiv, + settings, + has_mask ? &mask_evaluator : NULL, + &material_flags_evaluator); if (has_mask) { mask_evaluator.free(&mask_evaluator); } @@ -723,12 +755,11 @@ typedef struct RecalcInnerNormalsTLSData { * * The result is stored in normals storage from TLS. */ static void subdiv_ccg_recalc_inner_face_normals( - RecalcInnerNormalsData *data, + SubdivCCG *subdiv_ccg, + CCGKey *key, RecalcInnerNormalsTLSData *tls, const int grid_index) { - SubdivCCG *subdiv_ccg = data->subdiv_ccg; - CCGKey *key = data->key; const int grid_size = subdiv_ccg->grid_size; const int grid_size_1 = grid_size - 1; CCGElem *grid = subdiv_ccg->grids[grid_index]; @@ -761,12 +792,11 @@ static void subdiv_ccg_recalc_inner_face_normals( /* Average normals at every grid element, using adjacent faces normals. */ static void subdiv_ccg_average_inner_face_normals( - RecalcInnerNormalsData *data, + SubdivCCG *subdiv_ccg, + CCGKey *key, RecalcInnerNormalsTLSData *tls, const int grid_index) { - SubdivCCG *subdiv_ccg = data->subdiv_ccg; - CCGKey *key = data->key; const int grid_size = subdiv_ccg->grid_size; const int grid_size_1 = grid_size - 1; CCGElem *grid = subdiv_ccg->grids[grid_index]; @@ -811,8 +841,10 @@ static void subdiv_ccg_recalc_inner_normal_task( { RecalcInnerNormalsData *data = userdata_v; RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk; - subdiv_ccg_recalc_inner_face_normals(data, tls, grid_index); - subdiv_ccg_average_inner_face_normals(data, tls, grid_index); + subdiv_ccg_recalc_inner_face_normals( + data->subdiv_ccg, data->key, tls, grid_index); + subdiv_ccg_average_inner_face_normals( + data->subdiv_ccg, data->key, tls, grid_index); } static void subdiv_ccg_recalc_inner_normal_finalize( @@ -855,6 +887,88 @@ void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg) BKE_subdiv_ccg_average_grids(subdiv_ccg); } +typedef struct RecalcModifiedInnerNormalsData { + SubdivCCG *subdiv_ccg; + CCGKey *key; + SubdivCCGFace **effected_ccg_faces; +} RecalcModifiedInnerNormalsData; + +static void subdiv_ccg_recalc_modified_inner_normal_task( + void *__restrict userdata_v, + const int face_index, + const ParallelRangeTLS *__restrict tls_v) +{ + RecalcModifiedInnerNormalsData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk; + SubdivCCGFace **faces = data->effected_ccg_faces; + SubdivCCGFace *face = faces[face_index]; + const int num_face_grids = face->num_grids; + for (int i = 0; i < num_face_grids; i++) { + const int grid_index = face->start_grid_index + i; + subdiv_ccg_recalc_inner_face_normals( + data->subdiv_ccg, data->key, tls, grid_index); + subdiv_ccg_average_inner_face_normals( + data->subdiv_ccg, data->key, tls, grid_index); + } + subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face); +} + +static void subdiv_ccg_recalc_modified_inner_normal_finalize( + void *__restrict UNUSED(userdata), + void *__restrict tls_v) +{ + RecalcInnerNormalsTLSData *tls = tls_v; + MEM_SAFE_FREE(tls->face_normals); +} + +static void subdiv_ccg_recalc_modified_inner_grid_normals( + SubdivCCG *subdiv_ccg, + struct CCGFace **effected_faces, + int num_effected_faces) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + RecalcModifiedInnerNormalsData data = { + .subdiv_ccg = subdiv_ccg, + .key = &key, + .effected_ccg_faces = (SubdivCCGFace **)effected_faces, + }; + RecalcInnerNormalsTLSData tls_data = {NULL}; + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.userdata_chunk = &tls_data; + parallel_range_settings.userdata_chunk_size = sizeof(tls_data); + parallel_range_settings.func_finalize = + subdiv_ccg_recalc_modified_inner_normal_finalize; + BLI_task_parallel_range(0, num_effected_faces, + &data, + subdiv_ccg_recalc_modified_inner_normal_task, + ¶llel_range_settings); +} + +void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg, + struct CCGFace **effected_faces, + int num_effected_faces) +{ + if (!subdiv_ccg->has_normal) { + /* Grids don't have normals, can do early output. */ + return; + } + if (num_effected_faces == 0) { + /* No faces changed, so nothing to do here. */ + return; + } + subdiv_ccg_recalc_modified_inner_grid_normals( + subdiv_ccg, effected_faces, num_effected_faces); + /* TODO(sergey): Only average elements which are adjacent to modified + * faces. */ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key); +} + /* ============================================================================= * Boundary averaging/stitching. */ |