Changeset View
Changeset View
Standalone View
Standalone View
source/blender/bmesh/intern/bmesh_mesh_normals.cc
- This file was moved from source/blender/bmesh/intern/bmesh_mesh_normals.c.
| Show First 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | static void bm_vert_calc_normals_impl(BMVert *v) | ||||
| * In conclusion, the cost of caching & looking up edge-vectors both globally or per-vertex | * In conclusion, the cost of caching & looking up edge-vectors both globally or per-vertex | ||||
| * doesn't save enough time to make it worthwhile. | * doesn't save enough time to make it worthwhile. | ||||
| * - Campbell. */ | * - Campbell. */ | ||||
| float *v_no = v->no; | float *v_no = v->no; | ||||
| zero_v3(v_no); | zero_v3(v_no); | ||||
| BMEdge *e_first = v->e; | BMEdge *e_first = v->e; | ||||
| if (e_first != NULL) { | if (e_first != nullptr) { | ||||
| float e1diff[3], e2diff[3]; | float e1diff[3], e2diff[3]; | ||||
| BMEdge *e_iter = e_first; | BMEdge *e_iter = e_first; | ||||
| do { | do { | ||||
| BMLoop *l_first = e_iter->l; | BMLoop *l_first = e_iter->l; | ||||
| if (l_first != NULL) { | if (l_first != nullptr) { | ||||
| sub_v3_v3v3(e2diff, e_iter->v1->co, e_iter->v2->co); | sub_v3_v3v3(e2diff, e_iter->v1->co, e_iter->v2->co); | ||||
| normalize_v3(e2diff); | normalize_v3(e2diff); | ||||
| BMLoop *l_iter = l_first; | BMLoop *l_iter = l_first; | ||||
| do { | do { | ||||
| if (l_iter->v == v) { | if (l_iter->v == v) { | ||||
| BMEdge *e_prev = l_iter->prev->e; | BMEdge *e_prev = l_iter->prev->e; | ||||
| sub_v3_v3v3(e1diff, e_prev->v1->co, e_prev->v2->co); | sub_v3_v3v3(e1diff, e_prev->v1->co, e_prev->v2->co); | ||||
| Show All 24 Lines | |||||
| static void bm_vert_calc_normals_with_coords(BMVert *v, BMVertsCalcNormalsWithCoordsData *data) | static void bm_vert_calc_normals_with_coords(BMVert *v, BMVertsCalcNormalsWithCoordsData *data) | ||||
| { | { | ||||
| /* See #bm_vert_calc_normals_impl note on performance. */ | /* See #bm_vert_calc_normals_impl note on performance. */ | ||||
| float *v_no = data->vnos[BM_elem_index_get(v)]; | float *v_no = data->vnos[BM_elem_index_get(v)]; | ||||
| zero_v3(v_no); | zero_v3(v_no); | ||||
| /* Loop over edges. */ | /* Loop over edges. */ | ||||
| BMEdge *e_first = v->e; | BMEdge *e_first = v->e; | ||||
| if (e_first != NULL) { | if (e_first != nullptr) { | ||||
| float e1diff[3], e2diff[3]; | float e1diff[3], e2diff[3]; | ||||
| BMEdge *e_iter = e_first; | BMEdge *e_iter = e_first; | ||||
| do { | do { | ||||
| BMLoop *l_first = e_iter->l; | BMLoop *l_first = e_iter->l; | ||||
| if (l_first != NULL) { | if (l_first != nullptr) { | ||||
| sub_v3_v3v3(e2diff, | sub_v3_v3v3(e2diff, | ||||
| data->vcos[BM_elem_index_get(e_iter->v1)], | data->vcos[BM_elem_index_get(e_iter->v1)], | ||||
| data->vcos[BM_elem_index_get(e_iter->v2)]); | data->vcos[BM_elem_index_get(e_iter->v2)]); | ||||
| normalize_v3(e2diff); | normalize_v3(e2diff); | ||||
| BMLoop *l_iter = l_first; | BMLoop *l_iter = l_first; | ||||
| do { | do { | ||||
| if (l_iter->v == v) { | if (l_iter->v == v) { | ||||
| Show All 17 Lines | static void bm_vert_calc_normals_with_coords(BMVert *v, BMVertsCalcNormalsWithCoordsData *data) | ||||
| /* Fallback normal. */ | /* Fallback normal. */ | ||||
| normalize_v3_v3(v_no, data->vcos[BM_elem_index_get(v)]); | normalize_v3_v3(v_no, data->vcos[BM_elem_index_get(v)]); | ||||
| } | } | ||||
| static void bm_vert_calc_normals_with_coords_cb(void *userdata, | static void bm_vert_calc_normals_with_coords_cb(void *userdata, | ||||
| MempoolIterData *mp_v, | MempoolIterData *mp_v, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict UNUSED(tls)) | ||||
| { | { | ||||
| BMVertsCalcNormalsWithCoordsData *data = userdata; | BMVertsCalcNormalsWithCoordsData *data = static_cast<BMVertsCalcNormalsWithCoordsData *>( | ||||
| userdata); | |||||
| BMVert *v = (BMVert *)mp_v; | BMVert *v = (BMVert *)mp_v; | ||||
| bm_vert_calc_normals_with_coords(v, data); | bm_vert_calc_normals_with_coords(v, data); | ||||
| } | } | ||||
| static void bm_mesh_verts_calc_normals(BMesh *bm, | static void bm_mesh_verts_calc_normals(BMesh *bm, | ||||
| const float (*fnos)[3], | const float (*fnos)[3], | ||||
| const float (*vcos)[3], | const float (*vcos)[3], | ||||
| float (*vnos)[3]) | float (*vnos)[3]) | ||||
| { | { | ||||
| BM_mesh_elem_index_ensure(bm, BM_FACE | ((vnos || vcos) ? BM_VERT : 0)); | BM_mesh_elem_index_ensure(bm, BM_FACE | ((vnos || vcos) ? BM_VERT : 0)); | ||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BLI_parallel_mempool_settings_defaults(&settings); | BLI_parallel_mempool_settings_defaults(&settings); | ||||
| settings.use_threading = bm->totvert >= BM_OMP_LIMIT; | settings.use_threading = bm->totvert >= BM_OMP_LIMIT; | ||||
| if (vcos == NULL) { | if (vcos == nullptr) { | ||||
| BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_cb, NULL, &settings); | BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_cb, nullptr, &settings); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(!ELEM(NULL, fnos, vnos)); | BLI_assert(!ELEM(nullptr, fnos, vnos)); | ||||
| BMVertsCalcNormalsWithCoordsData data = { | BMVertsCalcNormalsWithCoordsData data{}; | ||||
| .fnos = fnos, | data.fnos = fnos; | ||||
| .vcos = vcos, | data.vcos = vcos; | ||||
| .vnos = vnos, | data.vnos = vnos; | ||||
| }; | |||||
| BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_with_coords_cb, &data, &settings); | BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_with_coords_cb, &data, &settings); | ||||
| } | } | ||||
| } | } | ||||
| static void bm_face_calc_normals_cb(void *UNUSED(userdata), | static void bm_face_calc_normals_cb(void *UNUSED(userdata), | ||||
| MempoolIterData *mp_f, | MempoolIterData *mp_f, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict UNUSED(tls)) | ||||
| { | { | ||||
| BMFace *f = (BMFace *)mp_f; | BMFace *f = (BMFace *)mp_f; | ||||
| BM_face_calc_normal(f, f->no); | BM_face_calc_normal(f, f->no); | ||||
| } | } | ||||
| void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params) | void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params) | ||||
| { | { | ||||
| if (params->face_normals) { | if (params->face_normals) { | ||||
| /* Calculate all face normals. */ | /* Calculate all face normals. */ | ||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BLI_parallel_mempool_settings_defaults(&settings); | BLI_parallel_mempool_settings_defaults(&settings); | ||||
| settings.use_threading = bm->totedge >= BM_OMP_LIMIT; | settings.use_threading = bm->totedge >= BM_OMP_LIMIT; | ||||
| BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, NULL, &settings); | BM_iter_parallel(bm, BM_FACES_OF_MESH, bm_face_calc_normals_cb, nullptr, &settings); | ||||
| } | } | ||||
| /* Add weighted face normals to vertices, and normalize vert normals. */ | /* Add weighted face normals to vertices, and normalize vert normals. */ | ||||
| bm_mesh_verts_calc_normals(bm, NULL, NULL, NULL); | bm_mesh_verts_calc_normals(bm, nullptr, nullptr, nullptr); | ||||
| } | } | ||||
| void BM_mesh_normals_update(BMesh *bm) | void BM_mesh_normals_update(BMesh *bm) | ||||
| { | { | ||||
| BM_mesh_normals_update_ex(bm, | BMeshNormalsUpdate_Params params{}; | ||||
| &(const struct BMeshNormalsUpdate_Params){ | params.face_normals = true; | ||||
| .face_normals = true, | BM_mesh_normals_update_ex(bm, ¶ms); | ||||
| }); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Update Vertex & Face Normals (Partial Updates) | /** \name Update Vertex & Face Normals (Partial Updates) | ||||
| * \{ */ | * \{ */ | ||||
| Show All 37 Lines | void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm), | ||||
| /* Verts. */ | /* Verts. */ | ||||
| BLI_task_parallel_range( | BLI_task_parallel_range( | ||||
| 0, verts_len, verts, bm_partial_verts_parallel_range_calc_normal_cb, &settings); | 0, verts_len, verts, bm_partial_verts_parallel_range_calc_normal_cb, &settings); | ||||
| } | } | ||||
| void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo) | void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpinfo) | ||||
| { | { | ||||
| BM_mesh_normals_update_with_partial_ex(bm, | BMeshNormalsUpdate_Params params{}; | ||||
| bmpinfo, | params.face_normals = true; | ||||
| &(const struct BMeshNormalsUpdate_Params){ | BM_mesh_normals_update_with_partial_ex(bm, bmpinfo, ¶ms); | ||||
| .face_normals = true, | |||||
| }); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Update Vertex & Face Normals (Custom Coords) | /** \name Update Vertex & Face Normals (Custom Coords) | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | static void bm_mesh_edges_sharp_tag(BMesh *bm, | ||||
| if (fnos) { | if (fnos) { | ||||
| BM_mesh_elem_index_ensure(bm, BM_FACE); | BM_mesh_elem_index_ensure(bm, BM_FACE); | ||||
| } | } | ||||
| if (do_sharp_edges_tag) { | if (do_sharp_edges_tag) { | ||||
| BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { | BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { | ||||
| BM_elem_index_set(e, i); /* set_inline */ | BM_elem_index_set(e, i); /* set_inline */ | ||||
| if (e->l != NULL) { | if (e->l != nullptr) { | ||||
| bm_edge_tag_from_smooth_and_set_sharp(fnos, e, split_angle_cos); | bm_edge_tag_from_smooth_and_set_sharp(fnos, e, split_angle_cos); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { | BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { | ||||
| BM_elem_index_set(e, i); /* set_inline */ | BM_elem_index_set(e, i); /* set_inline */ | ||||
| if (e->l != NULL) { | if (e->l != nullptr) { | ||||
| bm_edge_tag_from_smooth(fnos, e, split_angle_cos); | bm_edge_tag_from_smooth(fnos, e, split_angle_cos); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bm->elem_index_dirty &= ~BM_EDGE; | bm->elem_index_dirty &= ~BM_EDGE; | ||||
| } | } | ||||
| void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle) | void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle) | ||||
| { | { | ||||
| if (split_angle >= (float)M_PI) { | if (split_angle >= (float)M_PI) { | ||||
| /* Nothing to do! */ | /* Nothing to do! */ | ||||
| return; | return; | ||||
| } | } | ||||
| bm_mesh_edges_sharp_tag(bm, NULL, cosf(split_angle), true); | bm_mesh_edges_sharp_tag(bm, nullptr, cosf(split_angle), true); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Loop Normals Calculation API | /** \name Loop Normals Calculation API | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm, | ||||
| BLI_Stack *edge_vectors, | BLI_Stack *edge_vectors, | ||||
| /* Iterate. */ | /* Iterate. */ | ||||
| BMLoop *l_curr, | BMLoop *l_curr, | ||||
| /* Result. */ | /* Result. */ | ||||
| float (*r_lnos)[3], | float (*r_lnos)[3], | ||||
| MLoopNorSpaceArray *r_lnors_spacearr) | MLoopNorSpaceArray *r_lnors_spacearr) | ||||
| { | { | ||||
| BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0); | BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0); | ||||
| BLI_assert((fnos == NULL) || ((bm->elem_index_dirty & BM_FACE) == 0)); | BLI_assert((fnos == nullptr) || ((bm->elem_index_dirty & BM_FACE) == 0)); | ||||
| BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0)); | BLI_assert((vcos == nullptr) || ((bm->elem_index_dirty & BM_VERT) == 0)); | ||||
| UNUSED_VARS_NDEBUG(bm); | UNUSED_VARS_NDEBUG(bm); | ||||
| int handled = 0; | int handled = 0; | ||||
| /* Temp normal stack. */ | /* Temp normal stack. */ | ||||
| BLI_SMALLSTACK_DECLARE(normal, float *); | BLI_SMALLSTACK_DECLARE(normal, float *); | ||||
| /* Temp clnors stack. */ | /* Temp clnors stack. */ | ||||
| BLI_SMALLSTACK_DECLARE(clnors, short *); | BLI_SMALLSTACK_DECLARE(clnors, short *); | ||||
| Show All 38 Lines | if (r_lnors_spacearr) { | ||||
| BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot)); | BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot)); | ||||
| sub_v3_v3v3(vec_curr, co_1, co_pivot); | sub_v3_v3v3(vec_curr, co_1, co_pivot); | ||||
| normalize_v3(vec_curr); | normalize_v3(vec_curr); | ||||
| sub_v3_v3v3(vec_prev, co_2, co_pivot); | sub_v3_v3v3(vec_prev, co_2, co_pivot); | ||||
| normalize_v3(vec_prev); | normalize_v3(vec_prev); | ||||
| } | } | ||||
| BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL); | BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, nullptr); | ||||
| /* We know there is only one loop in this space, | /* We know there is only one loop in this space, | ||||
| * no need to create a linklist in this case... */ | * no need to create a linklist in this case... */ | ||||
| BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true); | BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true); | ||||
| if (has_clnors) { | if (has_clnors) { | ||||
| const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] : | const short(*clnor)[2] = clnors_data ? | ||||
| (const void *)BM_ELEM_CD_GET_VOID_P( | &clnors_data[l_curr_index] : | ||||
| l_curr, cd_loop_clnors_offset); | static_cast<const short(*)[2]>( | ||||
| BM_ELEM_CD_GET_VOID_P(l_curr, cd_loop_clnors_offset)); | |||||
| BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]); | BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]); | ||||
| } | } | ||||
| } | } | ||||
| handled = 1; | handled = 1; | ||||
| } | } | ||||
| /* We *do not need* to check/tag loops as already computed! | /* We *do not need* to check/tag loops as already computed! | ||||
| * Due to the fact a loop only links to one of its two edges, | * Due to the fact a loop only links to one of its two edges, | ||||
| * a same fan *will never be walked more than once!* | * a same fan *will never be walked more than once!* | ||||
| Show All 17 Lines | else { | ||||
| const BMEdge *e_org = l_curr->e; | const BMEdge *e_org = l_curr->e; | ||||
| BMLoop *lfan_pivot, *lfan_pivot_next; | BMLoop *lfan_pivot, *lfan_pivot_next; | ||||
| int lfan_pivot_index; | int lfan_pivot_index; | ||||
| float lnor[3] = {0.0f, 0.0f, 0.0f}; | float lnor[3] = {0.0f, 0.0f, 0.0f}; | ||||
| float vec_curr[3], vec_next[3], vec_org[3]; | float vec_curr[3], vec_next[3], vec_org[3]; | ||||
| /* We validate clnors data on the fly - cheapest way to do! */ | /* We validate clnors data on the fly - cheapest way to do! */ | ||||
| int clnors_avg[2] = {0, 0}; | int clnors_avg[2] = {0, 0}; | ||||
| const short(*clnor_ref)[2] = NULL; | const short(*clnor_ref)[2] = nullptr; | ||||
| int clnors_count = 0; | int clnors_count = 0; | ||||
| bool clnors_invalid = false; | bool clnors_invalid = false; | ||||
| const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; | const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co; | ||||
| MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : NULL; | MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : | ||||
| nullptr; | |||||
| BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors)); | BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors)); | ||||
| lfan_pivot = l_curr; | lfan_pivot = l_curr; | ||||
| lfan_pivot_index = BM_elem_index_get(lfan_pivot); | lfan_pivot_index = BM_elem_index_get(lfan_pivot); | ||||
| e_next = lfan_pivot->e; /* Current edge here, actually! */ | e_next = lfan_pivot->e; /* Current edge here, actually! */ | ||||
| /* Only need to compute previous edge's vector once, | /* Only need to compute previous edge's vector once, | ||||
| * then we can just reuse old current one! */ | * then we can just reuse old current one! */ | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | while (true) { | ||||
| const BMFace *f = lfan_pivot->f; | const BMFace *f = lfan_pivot->f; | ||||
| const float fac = saacos(dot_v3v3(vec_next, vec_curr)); | const float fac = saacos(dot_v3v3(vec_next, vec_curr)); | ||||
| const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; | const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; | ||||
| /* Accumulate */ | /* Accumulate */ | ||||
| madd_v3_v3fl(lnor, no, fac); | madd_v3_v3fl(lnor, no, fac); | ||||
| if (has_clnors) { | if (has_clnors) { | ||||
| /* Accumulate all clnors, if they are not all equal we have to fix that! */ | /* Accumulate all clnors, if they are not all equal we have to fix that! */ | ||||
| const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] : | const short(*clnor)[2] = clnors_data ? | ||||
| (const void *)BM_ELEM_CD_GET_VOID_P( | &clnors_data[lfan_pivot_index] : | ||||
| lfan_pivot, cd_loop_clnors_offset); | static_cast<const short(*)[2]>(BM_ELEM_CD_GET_VOID_P( | ||||
| lfan_pivot, cd_loop_clnors_offset)); | |||||
| if (clnors_count) { | if (clnors_count) { | ||||
| clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); | clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); | ||||
| } | } | ||||
| else { | else { | ||||
| clnor_ref = clnor; | clnor_ref = clnor; | ||||
| } | } | ||||
| clnors_avg[0] += (*clnor)[0]; | clnors_avg[0] += (*clnor)[0]; | ||||
| clnors_avg[1] += (*clnor)[1]; | clnors_avg[1] += (*clnor)[1]; | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | while (true) { | ||||
| clnors_avg[0] /= clnors_count; | clnors_avg[0] /= clnors_count; | ||||
| clnors_avg[1] /= clnors_count; | clnors_avg[1] /= clnors_count; | ||||
| /* Fix/update all clnors of this fan with computed average value. */ | /* Fix/update all clnors of this fan with computed average value. */ | ||||
| /* Prints continuously when merge custom normals, so commenting. */ | /* Prints continuously when merge custom normals, so commenting. */ | ||||
| // printf("Invalid clnors in this fan!\n"); | // printf("Invalid clnors in this fan!\n"); | ||||
| while ((clnor = BLI_SMALLSTACK_POP(clnors))) { | while ((clnor = static_cast<short *>(BLI_SMALLSTACK_POP(clnors)))) { | ||||
| // print_v2("org clnor", clnor); | // print_v2("org clnor", clnor); | ||||
| clnor[0] = (short)clnors_avg[0]; | clnor[0] = (short)clnors_avg[0]; | ||||
| clnor[1] = (short)clnors_avg[1]; | clnor[1] = (short)clnors_avg[1]; | ||||
| } | } | ||||
| // print_v2("new clnors", clnors_avg); | // print_v2("new clnors", clnors_avg); | ||||
| } | } | ||||
| else { | else { | ||||
| /* We still have to consume the stack! */ | /* We still have to consume the stack! */ | ||||
| while (BLI_SMALLSTACK_POP(clnors)) { | while (BLI_SMALLSTACK_POP(clnors)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| } | } | ||||
| BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); | BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); | ||||
| } | } | ||||
| } | } | ||||
| /* In case we get a zero normal here, just use vertex normal already set! */ | /* In case we get a zero normal here, just use vertex normal already set! */ | ||||
| if (LIKELY(lnor_len != 0.0f)) { | if (LIKELY(lnor_len != 0.0f)) { | ||||
| /* Copy back the final computed normal into all related loop-normals. */ | /* Copy back the final computed normal into all related loop-normals. */ | ||||
| float *nor; | float *nor; | ||||
| while ((nor = BLI_SMALLSTACK_POP(normal))) { | while ((nor = static_cast<float *>(BLI_SMALLSTACK_POP(normal)))) { | ||||
| copy_v3_v3(nor, lnor); | copy_v3_v3(nor, lnor); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* We still have to consume the stack! */ | /* We still have to consume the stack! */ | ||||
| while (BLI_SMALLSTACK_POP(normal)) { | while (BLI_SMALLSTACK_POP(normal)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| Show All 39 Lines | return ( | ||||
| /* The edge is smooth. */ | /* The edge is smooth. */ | ||||
| BM_elem_flag_test(e, BM_ELEM_SMOOTH) && | BM_elem_flag_test(e, BM_ELEM_SMOOTH) && | ||||
| /* Both faces are smooth. */ | /* Both faces are smooth. */ | ||||
| BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH)); | BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH)); | ||||
| } | } | ||||
| static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const float split_angle_cos) | static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const float split_angle_cos) | ||||
| { | { | ||||
| BLI_assert(e->l != NULL); | BLI_assert(e->l != nullptr); | ||||
| BMLoop *l_a = e->l, *l_b = l_a->radial_next; | BMLoop *l_a = e->l, *l_b = l_a->radial_next; | ||||
| bool is_smooth = false; | bool is_smooth = false; | ||||
| if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { | if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { | ||||
| if (split_angle_cos != -1.0f) { | if (split_angle_cos != -1.0f) { | ||||
| const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) : | const float dot = (fnos == nullptr) ? dot_v3v3(l_a->f->no, l_b->f->no) : | ||||
| dot_v3v3(fnos[BM_elem_index_get(l_a->f)], | dot_v3v3(fnos[BM_elem_index_get(l_a->f)], | ||||
| fnos[BM_elem_index_get(l_b->f)]); | fnos[BM_elem_index_get(l_b->f)]); | ||||
| if (dot >= split_angle_cos) { | if (dot >= split_angle_cos) { | ||||
| is_smooth = true; | is_smooth = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| is_smooth = true; | is_smooth = true; | ||||
| } | } | ||||
| } | } | ||||
| Show All 17 Lines | |||||
| * | * | ||||
| * \note This doesn't have the same atomic requirement as #bm_edge_tag_from_smooth | * \note This doesn't have the same atomic requirement as #bm_edge_tag_from_smooth | ||||
| * since it isn't run from multiple threads at once. | * since it isn't run from multiple threads at once. | ||||
| */ | */ | ||||
| static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3], | static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3], | ||||
| BMEdge *e, | BMEdge *e, | ||||
| const float split_angle_cos) | const float split_angle_cos) | ||||
| { | { | ||||
| BLI_assert(e->l != NULL); | BLI_assert(e->l != nullptr); | ||||
| BMLoop *l_a = e->l, *l_b = l_a->radial_next; | BMLoop *l_a = e->l, *l_b = l_a->radial_next; | ||||
| bool is_smooth = false; | bool is_smooth = false; | ||||
| if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { | if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) { | ||||
| if (split_angle_cos != -1.0f) { | if (split_angle_cos != -1.0f) { | ||||
| const float dot = (fnos == NULL) ? dot_v3v3(l_a->f->no, l_b->f->no) : | const float dot = (fnos == nullptr) ? dot_v3v3(l_a->f->no, l_b->f->no) : | ||||
| dot_v3v3(fnos[BM_elem_index_get(l_a->f)], | dot_v3v3(fnos[BM_elem_index_get(l_a->f)], | ||||
| fnos[BM_elem_index_get(l_b->f)]); | fnos[BM_elem_index_get(l_b->f)]); | ||||
| if (dot >= split_angle_cos) { | if (dot >= split_angle_cos) { | ||||
| is_smooth = true; | is_smooth = true; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Note that we do not care about the other sharp-edge cases | /* Note that we do not care about the other sharp-edge cases | ||||
| * (sharp poly, non-manifold edge, etc.), | * (sharp poly, non-manifold edge, etc.), | ||||
| * only tag edge as sharp when it is due to angle threshold. */ | * only tag edge as sharp when it is due to angle threshold. */ | ||||
| BM_elem_flag_disable(e, BM_ELEM_SMOOTH); | BM_elem_flag_disable(e, BM_ELEM_SMOOTH); | ||||
| Show All 31 Lines | static void bm_mesh_loops_calc_normals_for_vert_with_clnors(BMesh *bm, | ||||
| * | * | ||||
| * Logically we could sort the loops by their index & loop over them | * Logically we could sort the loops by their index & loop over them | ||||
| * however it's faster to use the lowest index of an un-ordered list | * however it's faster to use the lowest index of an un-ordered list | ||||
| * since it's common that smooth vertices only ever need to pick one loop | * since it's common that smooth vertices only ever need to pick one loop | ||||
| * which then handles all the others. | * which then handles all the others. | ||||
| * | * | ||||
| * Sorting is only performed when multiple fans are found. */ | * Sorting is only performed when multiple fans are found. */ | ||||
| const bool has_clnors = true; | const bool has_clnors = true; | ||||
| LinkNode *loops_of_vert = NULL; | LinkNode *loops_of_vert = nullptr; | ||||
| int loops_of_vert_count = 0; | int loops_of_vert_count = 0; | ||||
| /* When false the caller must have already tagged the edges. */ | /* When false the caller must have already tagged the edges. */ | ||||
| const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | ||||
| /* The loop with the lowest index. */ | /* The loop with the lowest index. */ | ||||
| { | { | ||||
| LinkNode *link_best; | LinkNode *link_best; | ||||
| uint index_best = UINT_MAX; | uint index_best = UINT_MAX; | ||||
| BMEdge *e_curr_iter = v->e; | BMEdge *e_curr_iter = v->e; | ||||
| do { /* Edges of vertex. */ | do { /* Edges of vertex. */ | ||||
| BMLoop *l_curr = e_curr_iter->l; | BMLoop *l_curr = e_curr_iter->l; | ||||
| if (l_curr == NULL) { | if (l_curr == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (do_edge_tag) { | if (do_edge_tag) { | ||||
| bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); | bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); | ||||
| } | } | ||||
| do { /* Radial loops. */ | do { /* Radial loops. */ | ||||
| Show All 11 Lines | do { /* Edges of vertex. */ | ||||
| const uint index_test = (uint)BM_elem_index_get(l_curr); | const uint index_test = (uint)BM_elem_index_get(l_curr); | ||||
| if (index_best > index_test) { | if (index_best > index_test) { | ||||
| index_best = index_test; | index_best = index_test; | ||||
| link_best = loops_of_vert; | link_best = loops_of_vert; | ||||
| } | } | ||||
| } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | ||||
| } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | ||||
| if (UNLIKELY(loops_of_vert == NULL)) { | if (UNLIKELY(loops_of_vert == nullptr)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Immediately pop the best element. | /* Immediately pop the best element. | ||||
| * The order doesn't matter, so swap the links as it's simpler than tracking | * The order doesn't matter, so swap the links as it's simpler than tracking | ||||
| * reference to `link_best`. */ | * reference to `link_best`. */ | ||||
| if (link_best != loops_of_vert) { | if (link_best != loops_of_vert) { | ||||
| SWAP(void *, link_best->link, loops_of_vert->link); | SWAP(void *, link_best->link, loops_of_vert->link); | ||||
| } | } | ||||
| } | } | ||||
| bool loops_of_vert_is_sorted = false; | bool loops_of_vert_is_sorted = false; | ||||
| /* Keep track of the number of loops that have been assigned. */ | /* Keep track of the number of loops that have been assigned. */ | ||||
| int loops_of_vert_handled = 0; | int loops_of_vert_handled = 0; | ||||
| while (loops_of_vert != NULL) { | while (loops_of_vert != nullptr) { | ||||
| BMLoop *l_best = loops_of_vert->link; | BMLoop *l_best = static_cast<BMLoop *>(loops_of_vert->link); | ||||
| loops_of_vert = loops_of_vert->next; | loops_of_vert = loops_of_vert->next; | ||||
| BLI_assert(l_best->v == v); | BLI_assert(l_best->v == v); | ||||
| loops_of_vert_handled += bm_mesh_loops_calc_normals_for_loop(bm, | loops_of_vert_handled += bm_mesh_loops_calc_normals_for_loop(bm, | ||||
| vcos, | vcos, | ||||
| fnos, | fnos, | ||||
| clnors_data, | clnors_data, | ||||
| cd_loop_clnors_offset, | cd_loop_clnors_offset, | ||||
| Show All 35 Lines | static void bm_mesh_loops_calc_normals_for_vert_without_clnors( | ||||
| const float split_angle_cos, | const float split_angle_cos, | ||||
| /* TLS */ | /* TLS */ | ||||
| MLoopNorSpaceArray *r_lnors_spacearr, | MLoopNorSpaceArray *r_lnors_spacearr, | ||||
| BLI_Stack *edge_vectors, | BLI_Stack *edge_vectors, | ||||
| /* Iterate over. */ | /* Iterate over. */ | ||||
| BMVert *v) | BMVert *v) | ||||
| { | { | ||||
| const bool has_clnors = false; | const bool has_clnors = false; | ||||
| const short(*clnors_data)[2] = NULL; | const short(*clnors_data)[2] = nullptr; | ||||
| /* When false the caller must have already tagged the edges. */ | /* When false the caller must have already tagged the edges. */ | ||||
| const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | ||||
| const int cd_loop_clnors_offset = -1; | const int cd_loop_clnors_offset = -1; | ||||
| BMEdge *e_curr_iter; | BMEdge *e_curr_iter; | ||||
| /* Unfortunately a loop is needed just to clear loop-tags. */ | /* Unfortunately a loop is needed just to clear loop-tags. */ | ||||
| e_curr_iter = v->e; | e_curr_iter = v->e; | ||||
| do { /* Edges of vertex. */ | do { /* Edges of vertex. */ | ||||
| BMLoop *l_curr = e_curr_iter->l; | BMLoop *l_curr = e_curr_iter->l; | ||||
| if (l_curr == NULL) { | if (l_curr == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (do_edge_tag) { | if (do_edge_tag) { | ||||
| bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); | bm_edge_tag_from_smooth(fnos, e_curr_iter, split_angle_cos); | ||||
| } | } | ||||
| do { /* Radial loops. */ | do { /* Radial loops. */ | ||||
| if (l_curr->v != v) { | if (l_curr->v != v) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_elem_flag_disable(l_curr, BM_ELEM_TAG); | BM_elem_flag_disable(l_curr, BM_ELEM_TAG); | ||||
| } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | ||||
| } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | ||||
| e_curr_iter = v->e; | e_curr_iter = v->e; | ||||
| do { /* Edges of vertex. */ | do { /* Edges of vertex. */ | ||||
| BMLoop *l_curr = e_curr_iter->l; | BMLoop *l_curr = e_curr_iter->l; | ||||
| if (l_curr == NULL) { | if (l_curr == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| do { /* Radial loops. */ | do { /* Radial loops. */ | ||||
| if (l_curr->v != v) { | if (l_curr->v != v) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) && | if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) && | ||||
| !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) { | !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL)) { | ||||
| Show All 11 Lines | do { /* Radial loops. */ | ||||
| r_lnors_spacearr); | r_lnors_spacearr); | ||||
| } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | } while ((l_curr = l_curr->radial_next) != e_curr_iter->l); | ||||
| } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | } while ((e_curr_iter = BM_DISK_EDGE_NEXT(e_curr_iter, v)) != v->e); | ||||
| } | } | ||||
| /** | /** | ||||
| * BMesh version of BKE_mesh_normals_loop_split() in `mesh_evaluate.cc` | * BMesh version of BKE_mesh_normals_loop_split() in `mesh_evaluate.cc` | ||||
| * Will use first clnors_data array, and fallback to cd_loop_clnors_offset | * Will use first clnors_data array, and fallback to cd_loop_clnors_offset | ||||
| * (use NULL and -1 to not use clnors). | * (use nullptr and -1 to not use clnors). | ||||
| * | * | ||||
| * \note This sets #BM_ELEM_TAG which is used in tool code (e.g. T84426). | * \note This sets #BM_ELEM_TAG which is used in tool code (e.g. T84426). | ||||
| * we could add a low-level API flag for this, see #BM_ELEM_API_FLAG_ENABLE and friends. | * we could add a low-level API flag for this, see #BM_ELEM_API_FLAG_ENABLE and friends. | ||||
| */ | */ | ||||
| static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm, | static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm, | ||||
| const float (*vcos)[3], | const float (*vcos)[3], | ||||
| const float (*fnos)[3], | const float (*fnos)[3], | ||||
| float (*r_lnos)[3], | float (*r_lnos)[3], | ||||
| MLoopNorSpaceArray *r_lnors_spacearr, | MLoopNorSpaceArray *r_lnors_spacearr, | ||||
| const short (*clnors_data)[2], | const short (*clnors_data)[2], | ||||
| const int cd_loop_clnors_offset, | const int cd_loop_clnors_offset, | ||||
| const bool do_rebuild, | const bool do_rebuild, | ||||
| const float split_angle_cos) | const float split_angle_cos) | ||||
| { | { | ||||
| BMIter fiter; | BMIter fiter; | ||||
| BMFace *f_curr; | BMFace *f_curr; | ||||
| const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); | const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); | ||||
| /* When false the caller must have already tagged the edges. */ | /* When false the caller must have already tagged the edges. */ | ||||
| const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | const bool do_edge_tag = (split_angle_cos != EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | ||||
| MLoopNorSpaceArray _lnors_spacearr = {NULL}; | MLoopNorSpaceArray _lnors_spacearr = {nullptr}; | ||||
| BLI_Stack *edge_vectors = NULL; | BLI_Stack *edge_vectors = nullptr; | ||||
| { | { | ||||
| char htype = 0; | char htype = 0; | ||||
| if (vcos) { | if (vcos) { | ||||
| htype |= BM_VERT; | htype |= BM_VERT; | ||||
| } | } | ||||
| /* Face/Loop indices are set inline below. */ | /* Face/Loop indices are set inline below. */ | ||||
| BM_mesh_elem_index_ensure(bm, htype); | BM_mesh_elem_index_ensure(bm, htype); | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| typedef struct BMLoopsCalcNormalsWithCoordsData { | typedef struct BMLoopsCalcNormalsWithCoordsData { | ||||
| /* Read-only data. */ | /* Read-only data. */ | ||||
| const float (*fnos)[3]; | const float (*fnos)[3]; | ||||
| const float (*vcos)[3]; | const float (*vcos)[3]; | ||||
| BMesh *bm; | BMesh *bm; | ||||
| const short (*clnors_data)[2]; | const short (*clnors_data)[2]; | ||||
| const int cd_loop_clnors_offset; | int cd_loop_clnors_offset; | ||||
| const bool do_rebuild; | bool do_rebuild; | ||||
| const float split_angle_cos; | float split_angle_cos; | ||||
| /* Output. */ | /* Output. */ | ||||
| float (*r_lnos)[3]; | float (*r_lnos)[3]; | ||||
| MLoopNorSpaceArray *r_lnors_spacearr; | MLoopNorSpaceArray *r_lnors_spacearr; | ||||
| } BMLoopsCalcNormalsWithCoordsData; | } BMLoopsCalcNormalsWithCoordsData; | ||||
| typedef struct BMLoopsCalcNormalsWithCoords_TLS { | typedef struct BMLoopsCalcNormalsWithCoords_TLS { | ||||
| BLI_Stack *edge_vectors; | BLI_Stack *edge_vectors; | ||||
| /** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not NULL. */ | /** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not nullptr. */ | ||||
| MLoopNorSpaceArray *lnors_spacearr; | MLoopNorSpaceArray *lnors_spacearr; | ||||
| MLoopNorSpaceArray lnors_spacearr_buf; | MLoopNorSpaceArray lnors_spacearr_buf; | ||||
| } BMLoopsCalcNormalsWithCoords_TLS; | } BMLoopsCalcNormalsWithCoords_TLS; | ||||
| static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict userdata, | static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict userdata, | ||||
| void *__restrict chunk) | void *__restrict chunk) | ||||
| { | { | ||||
| const BMLoopsCalcNormalsWithCoordsData *data = userdata; | auto *data = static_cast<const BMLoopsCalcNormalsWithCoordsData *>(userdata); | ||||
| BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; | auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk); | ||||
| if (data->r_lnors_spacearr) { | if (data->r_lnors_spacearr) { | ||||
| tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); | tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); | ||||
| BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf); | BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf); | ||||
| tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf; | tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf; | ||||
| } | } | ||||
| else { | else { | ||||
| tls_data->lnors_spacearr = NULL; | tls_data->lnors_spacearr = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| static void bm_mesh_loops_calc_normals_for_vert_reduce_fn(const void *__restrict userdata, | static void bm_mesh_loops_calc_normals_for_vert_reduce_fn(const void *__restrict userdata, | ||||
| void *__restrict UNUSED(chunk_join), | void *__restrict UNUSED(chunk_join), | ||||
| void *__restrict chunk) | void *__restrict chunk) | ||||
| { | { | ||||
| const BMLoopsCalcNormalsWithCoordsData *data = userdata; | auto *data = static_cast<const BMLoopsCalcNormalsWithCoordsData *>(userdata); | ||||
| BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; | auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk); | ||||
| if (data->r_lnors_spacearr) { | if (data->r_lnors_spacearr) { | ||||
| BKE_lnor_spacearr_tls_join(data->r_lnors_spacearr, tls_data->lnors_spacearr); | BKE_lnor_spacearr_tls_join(data->r_lnors_spacearr, tls_data->lnors_spacearr); | ||||
| } | } | ||||
| } | } | ||||
| static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict userdata, | static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict userdata, | ||||
| void *__restrict chunk) | void *__restrict chunk) | ||||
| { | { | ||||
| const BMLoopsCalcNormalsWithCoordsData *data = userdata; | auto *data = static_cast<const BMLoopsCalcNormalsWithCoordsData *>(userdata); | ||||
| BMLoopsCalcNormalsWithCoords_TLS *tls_data = chunk; | auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk); | ||||
| if (data->r_lnors_spacearr) { | if (data->r_lnors_spacearr) { | ||||
| BLI_stack_free(tls_data->edge_vectors); | BLI_stack_free(tls_data->edge_vectors); | ||||
| } | } | ||||
| } | } | ||||
| static void bm_mesh_loops_calc_normals_for_vert_with_clnors_fn( | static void bm_mesh_loops_calc_normals_for_vert_with_clnors_fn( | ||||
| void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) | void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) | ||||
| { | { | ||||
| BMVert *v = (BMVert *)mp_v; | BMVert *v = (BMVert *)mp_v; | ||||
| if (v->e == NULL) { | if (v->e == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| BMLoopsCalcNormalsWithCoordsData *data = userdata; | auto *data = static_cast<BMLoopsCalcNormalsWithCoordsData *>(userdata); | ||||
| BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk; | auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(tls->userdata_chunk); | ||||
| bm_mesh_loops_calc_normals_for_vert_with_clnors(data->bm, | bm_mesh_loops_calc_normals_for_vert_with_clnors(data->bm, | ||||
| data->vcos, | data->vcos, | ||||
| data->fnos, | data->fnos, | ||||
| data->r_lnos, | data->r_lnos, | ||||
| data->clnors_data, | data->clnors_data, | ||||
| data->cd_loop_clnors_offset, | data->cd_loop_clnors_offset, | ||||
| data->do_rebuild, | data->do_rebuild, | ||||
| data->split_angle_cos, | data->split_angle_cos, | ||||
| /* Thread local. */ | /* Thread local. */ | ||||
| tls_data->lnors_spacearr, | tls_data->lnors_spacearr, | ||||
| tls_data->edge_vectors, | tls_data->edge_vectors, | ||||
| /* Iterate over. */ | /* Iterate over. */ | ||||
| v); | v); | ||||
| } | } | ||||
| static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn( | static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn( | ||||
| void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) | void *userdata, MempoolIterData *mp_v, const TaskParallelTLS *__restrict tls) | ||||
| { | { | ||||
| BMVert *v = (BMVert *)mp_v; | BMVert *v = (BMVert *)mp_v; | ||||
| if (v->e == NULL) { | if (v->e == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| BMLoopsCalcNormalsWithCoordsData *data = userdata; | auto *data = static_cast<BMLoopsCalcNormalsWithCoordsData *>(userdata); | ||||
| BMLoopsCalcNormalsWithCoords_TLS *tls_data = tls->userdata_chunk; | auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(tls->userdata_chunk); | ||||
| bm_mesh_loops_calc_normals_for_vert_without_clnors(data->bm, | bm_mesh_loops_calc_normals_for_vert_without_clnors(data->bm, | ||||
| data->vcos, | data->vcos, | ||||
| data->fnos, | data->fnos, | ||||
| data->r_lnos, | data->r_lnos, | ||||
| data->do_rebuild, | data->do_rebuild, | ||||
| data->split_angle_cos, | data->split_angle_cos, | ||||
| /* Thread local. */ | /* Thread local. */ | ||||
| Show All 9 Lines | static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm, | ||||
| float (*r_lnos)[3], | float (*r_lnos)[3], | ||||
| MLoopNorSpaceArray *r_lnors_spacearr, | MLoopNorSpaceArray *r_lnors_spacearr, | ||||
| const short (*clnors_data)[2], | const short (*clnors_data)[2], | ||||
| const int cd_loop_clnors_offset, | const int cd_loop_clnors_offset, | ||||
| const bool do_rebuild, | const bool do_rebuild, | ||||
| const float split_angle_cos) | const float split_angle_cos) | ||||
| { | { | ||||
| const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); | const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); | ||||
| MLoopNorSpaceArray _lnors_spacearr = {NULL}; | MLoopNorSpaceArray _lnors_spacearr = {nullptr}; | ||||
| { | { | ||||
| char htype = BM_LOOP; | char htype = BM_LOOP; | ||||
| if (vcos) { | if (vcos) { | ||||
| htype |= BM_VERT; | htype |= BM_VERT; | ||||
| } | } | ||||
| if (fnos) { | if (fnos) { | ||||
| htype |= BM_FACE; | htype |= BM_FACE; | ||||
| Show All 13 Lines | static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm, | ||||
| /* We now know edges that can be smoothed (they are tagged), | /* We now know edges that can be smoothed (they are tagged), | ||||
| * and edges that will be hard (they aren't). | * and edges that will be hard (they aren't). | ||||
| * Now, time to generate the normals. | * Now, time to generate the normals. | ||||
| */ | */ | ||||
| TaskParallelSettings settings; | TaskParallelSettings settings; | ||||
| BLI_parallel_mempool_settings_defaults(&settings); | BLI_parallel_mempool_settings_defaults(&settings); | ||||
| BMLoopsCalcNormalsWithCoords_TLS tls = {NULL}; | BMLoopsCalcNormalsWithCoords_TLS tls = {nullptr}; | ||||
| settings.userdata_chunk = &tls; | settings.userdata_chunk = &tls; | ||||
| settings.userdata_chunk_size = sizeof(tls); | settings.userdata_chunk_size = sizeof(tls); | ||||
| settings.func_init = bm_mesh_loops_calc_normals_for_vert_init_fn; | settings.func_init = bm_mesh_loops_calc_normals_for_vert_init_fn; | ||||
| settings.func_reduce = bm_mesh_loops_calc_normals_for_vert_reduce_fn; | settings.func_reduce = bm_mesh_loops_calc_normals_for_vert_reduce_fn; | ||||
| settings.func_free = bm_mesh_loops_calc_normals_for_vert_free_fn; | settings.func_free = bm_mesh_loops_calc_normals_for_vert_free_fn; | ||||
| BMLoopsCalcNormalsWithCoordsData data = { | BMLoopsCalcNormalsWithCoordsData data{}; | ||||
| .bm = bm, | data.bm = bm; | ||||
| .vcos = vcos, | data.vcos = vcos; | ||||
| .fnos = fnos, | data.fnos = fnos; | ||||
| .r_lnos = r_lnos, | data.r_lnos = r_lnos; | ||||
| .r_lnors_spacearr = r_lnors_spacearr, | data.r_lnors_spacearr = r_lnors_spacearr; | ||||
| .clnors_data = clnors_data, | data.clnors_data = clnors_data; | ||||
| .cd_loop_clnors_offset = cd_loop_clnors_offset, | data.cd_loop_clnors_offset = cd_loop_clnors_offset; | ||||
| .do_rebuild = do_rebuild, | data.do_rebuild = do_rebuild; | ||||
| .split_angle_cos = split_angle_cos, | data.split_angle_cos = split_angle_cos; | ||||
| }; | |||||
| BM_iter_parallel(bm, | BM_iter_parallel(bm, | ||||
| BM_VERTS_OF_MESH, | BM_VERTS_OF_MESH, | ||||
| has_clnors ? bm_mesh_loops_calc_normals_for_vert_with_clnors_fn : | has_clnors ? bm_mesh_loops_calc_normals_for_vert_with_clnors_fn : | ||||
| bm_mesh_loops_calc_normals_for_vert_without_clnors_fn, | bm_mesh_loops_calc_normals_for_vert_without_clnors_fn, | ||||
| &data, | &data, | ||||
| &settings); | &settings); | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | static bool bm_mesh_loops_split_lnor_fans(BMesh *bm, | ||||
| BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)bm->totloop, __func__); | BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)bm->totloop, __func__); | ||||
| bool changed = false; | bool changed = false; | ||||
| BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | ||||
| for (int i = 0; i < bm->totloop; i++) { | for (int i = 0; i < bm->totloop; i++) { | ||||
| if (!lnors_spacearr->lspacearr[i]) { | if (!lnors_spacearr->lspacearr[i]) { | ||||
| /* This should not happen in theory, but in some rare case (probably ugly geometry) | /* This should not happen in theory, but in some rare case (probably ugly geometry) | ||||
| * we can get some NULL loopspacearr at this point. :/ | * we can get some nullptr loopspacearr at this point. :/ | ||||
| * Maybe we should set those loops' edges as sharp? | * Maybe we should set those loops' edges as sharp? | ||||
| */ | */ | ||||
| BLI_BITMAP_ENABLE(done_loops, i); | BLI_BITMAP_ENABLE(done_loops, i); | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i); | printf("WARNING! Getting invalid nullptr loop space for loop %d!\n", i); | ||||
| } | } | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!BLI_BITMAP_TEST(done_loops, i)) { | if (!BLI_BITMAP_TEST(done_loops, i)) { | ||||
| /* Notes: | /* Notes: | ||||
| * * In case of mono-loop smooth fan, we have nothing to do. | * * In case of mono-loop smooth fan, we have nothing to do. | ||||
| * * Loops in this linklist are ordered (in reversed order compared to how they were | * * Loops in this linklist are ordered (in reversed order compared to how they were | ||||
| * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). | * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). | ||||
| * Which means if we find a mismatching clnor, | * Which means if we find a mismatching clnor, | ||||
| * we know all remaining loops will have to be in a new, different smooth fan/lnor space. | * we know all remaining loops will have to be in a new, different smooth fan/lnor space. | ||||
| * * In smooth fan case, we compare each clnor against a ref one, | * * In smooth fan case, we compare each clnor against a ref one, | ||||
| * to avoid small differences adding up into a real big one in the end! | * to avoid small differences adding up into a real big one in the end! | ||||
| */ | */ | ||||
| if (lnors_spacearr->lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { | if (lnors_spacearr->lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { | ||||
| BLI_BITMAP_ENABLE(done_loops, i); | BLI_BITMAP_ENABLE(done_loops, i); | ||||
| continue; | continue; | ||||
| } | } | ||||
| LinkNode *loops = lnors_spacearr->lspacearr[i]->loops; | LinkNode *loops = lnors_spacearr->lspacearr[i]->loops; | ||||
| BMLoop *prev_ml = NULL; | BMLoop *prev_ml = nullptr; | ||||
| const float *org_nor = NULL; | const float *org_nor = nullptr; | ||||
| while (loops) { | while (loops) { | ||||
| BMLoop *ml = loops->link; | BMLoop *ml = static_cast<BMLoop *>(loops->link); | ||||
| const int lidx = BM_elem_index_get(ml); | const int lidx = BM_elem_index_get(ml); | ||||
| const float *nor = new_lnors[lidx]; | const float *nor = new_lnors[lidx]; | ||||
| if (!org_nor) { | if (!org_nor) { | ||||
| org_nor = nor; | org_nor = nor; | ||||
| } | } | ||||
| else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { | else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { | ||||
| /* Current normal differs too much from org one, we have to tag the edge between | /* Current normal differs too much from org one, we have to tag the edge between | ||||
| Show All 15 Lines | if (!BLI_BITMAP_TEST(done_loops, i)) { | ||||
| } | } | ||||
| /* We also have to check between last and first loops, | /* We also have to check between last and first loops, | ||||
| * otherwise we may miss some sharp edges here! | * otherwise we may miss some sharp edges here! | ||||
| * This is just a simplified version of above while loop. | * This is just a simplified version of above while loop. | ||||
| * See T45984. */ | * See T45984. */ | ||||
| loops = lnors_spacearr->lspacearr[i]->loops; | loops = lnors_spacearr->lspacearr[i]->loops; | ||||
| if (loops && org_nor) { | if (loops && org_nor) { | ||||
| BMLoop *ml = loops->link; | BMLoop *ml = static_cast<BMLoop *>(loops->link); | ||||
| const int lidx = BM_elem_index_get(ml); | const int lidx = BM_elem_index_get(ml); | ||||
| const float *nor = new_lnors[lidx]; | const float *nor = new_lnors[lidx]; | ||||
| if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { | if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { | ||||
| BMEdge *e = (prev_ml->e == ml->prev->e) ? prev_ml->e : ml->e; | BMEdge *e = (prev_ml->e == ml->prev->e) ? prev_ml->e : ml->e; | ||||
| BM_elem_flag_disable(e, BM_ELEM_TAG | BM_ELEM_SMOOTH); | BM_elem_flag_disable(e, BM_ELEM_TAG | BM_ELEM_SMOOTH); | ||||
| changed = true; | changed = true; | ||||
| Show All 21 Lines | static void bm_mesh_loops_assign_normal_data(BMesh *bm, | ||||
| BLI_SMALLSTACK_DECLARE(clnors_data, short *); | BLI_SMALLSTACK_DECLARE(clnors_data, short *); | ||||
| BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | ||||
| for (int i = 0; i < bm->totloop; i++) { | for (int i = 0; i < bm->totloop; i++) { | ||||
| if (!lnors_spacearr->lspacearr[i]) { | if (!lnors_spacearr->lspacearr[i]) { | ||||
| BLI_BITMAP_ENABLE(done_loops, i); | BLI_BITMAP_ENABLE(done_loops, i); | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i); | printf("WARNING! Still getting invalid nullptr loop space in second loop for loop %d!\n", | ||||
| i); | |||||
| } | } | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!BLI_BITMAP_TEST(done_loops, i)) { | if (!BLI_BITMAP_TEST(done_loops, i)) { | ||||
| /* Note we accumulate and average all custom normals in current smooth fan, | /* Note we accumulate and average all custom normals in current smooth fan, | ||||
| * to avoid getting different clnors data (tiny differences in plain custom normals can | * to avoid getting different clnors data (tiny differences in plain custom normals can | ||||
| * give rather huge differences in computed 2D factors). | * give rather huge differences in computed 2D factors). | ||||
| */ | */ | ||||
| LinkNode *loops = lnors_spacearr->lspacearr[i]->loops; | LinkNode *loops = lnors_spacearr->lspacearr[i]->loops; | ||||
| if (lnors_spacearr->lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { | if (lnors_spacearr->lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { | ||||
| BMLoop *ml = (BMLoop *)loops; | BMLoop *ml = (BMLoop *)loops; | ||||
| const int lidx = BM_elem_index_get(ml); | const int lidx = BM_elem_index_get(ml); | ||||
| BLI_assert(lidx == i); | BLI_assert(lidx == i); | ||||
| const float *nor = new_lnors[lidx]; | const float *nor = new_lnors[lidx]; | ||||
| short *clnor = r_clnors_data ? &r_clnors_data[lidx] : | short *clnor = static_cast<short *>(r_clnors_data ? | ||||
| BM_ELEM_CD_GET_VOID_P(ml, cd_loop_clnors_offset); | &r_clnors_data[lidx] : | ||||
| BM_ELEM_CD_GET_VOID_P(ml, cd_loop_clnors_offset)); | |||||
| BKE_lnor_space_custom_normal_to_data(lnors_spacearr->lspacearr[i], nor, clnor); | BKE_lnor_space_custom_normal_to_data(lnors_spacearr->lspacearr[i], nor, clnor); | ||||
| BLI_BITMAP_ENABLE(done_loops, i); | BLI_BITMAP_ENABLE(done_loops, i); | ||||
| } | } | ||||
| else { | else { | ||||
| int avg_nor_count = 0; | int avg_nor_count = 0; | ||||
| float avg_nor[3]; | float avg_nor[3]; | ||||
| short clnor_data_tmp[2], *clnor_data; | short clnor_data_tmp[2], *clnor_data; | ||||
| zero_v3(avg_nor); | zero_v3(avg_nor); | ||||
| while (loops) { | while (loops) { | ||||
| BMLoop *ml = loops->link; | BMLoop *ml = static_cast<BMLoop *>(loops->link); | ||||
| const int lidx = BM_elem_index_get(ml); | const int lidx = BM_elem_index_get(ml); | ||||
| const float *nor = new_lnors[lidx]; | const float *nor = new_lnors[lidx]; | ||||
| short *clnor = r_clnors_data ? &r_clnors_data[lidx] : | short *clnor = static_cast<short *>( | ||||
| BM_ELEM_CD_GET_VOID_P(ml, cd_loop_clnors_offset); | r_clnors_data ? &r_clnors_data[lidx] : | ||||
| BM_ELEM_CD_GET_VOID_P(ml, cd_loop_clnors_offset)); | |||||
| avg_nor_count++; | avg_nor_count++; | ||||
| add_v3_v3(avg_nor, nor); | add_v3_v3(avg_nor, nor); | ||||
| BLI_SMALLSTACK_PUSH(clnors_data, clnor); | BLI_SMALLSTACK_PUSH(clnors_data, clnor); | ||||
| loops = loops->next; | loops = loops->next; | ||||
| BLI_BITMAP_ENABLE(done_loops, lidx); | BLI_BITMAP_ENABLE(done_loops, lidx); | ||||
| } | } | ||||
| mul_v3_fl(avg_nor, 1.0f / (float)avg_nor_count); | mul_v3_fl(avg_nor, 1.0f / (float)avg_nor_count); | ||||
| BKE_lnor_space_custom_normal_to_data( | BKE_lnor_space_custom_normal_to_data( | ||||
| lnors_spacearr->lspacearr[i], avg_nor, clnor_data_tmp); | lnors_spacearr->lspacearr[i], avg_nor, clnor_data_tmp); | ||||
| while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) { | while ((clnor_data = static_cast<short *>(BLI_SMALLSTACK_POP(clnors_data)))) { | ||||
| clnor_data[0] = clnor_data_tmp[0]; | clnor_data[0] = clnor_data_tmp[0]; | ||||
| clnor_data[1] = clnor_data_tmp[1]; | clnor_data[1] = clnor_data_tmp[1]; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(done_loops); | MEM_freeN(done_loops); | ||||
| Show All 14 Lines | static void bm_mesh_loops_custom_normals_set(BMesh *bm, | ||||
| const int cd_loop_clnors_offset, | const int cd_loop_clnors_offset, | ||||
| float (*new_lnors)[3], | float (*new_lnors)[3], | ||||
| const int cd_new_lnors_offset, | const int cd_new_lnors_offset, | ||||
| bool do_split_fans) | bool do_split_fans) | ||||
| { | { | ||||
| BMFace *f; | BMFace *f; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter, fiter; | BMIter liter, fiter; | ||||
| float(*cur_lnors)[3] = MEM_mallocN(sizeof(*cur_lnors) * bm->totloop, __func__); | float(*cur_lnors)[3] = static_cast<float(*)[3]>( | ||||
| MEM_mallocN(sizeof(*cur_lnors) * bm->totloop, __func__)); | |||||
| BKE_lnor_spacearr_clear(r_lnors_spacearr); | BKE_lnor_spacearr_clear(r_lnors_spacearr); | ||||
| /* Tag smooth edges and set lnos from vnos when they might be completely smooth... | /* Tag smooth edges and set lnos from vnos when they might be completely smooth... | ||||
| * When using custom loop normals, disable the angle feature! */ | * When using custom loop normals, disable the angle feature! */ | ||||
| bm_mesh_edges_sharp_tag(bm, fnos, -1.0f, false); | bm_mesh_edges_sharp_tag(bm, fnos, -1.0f, false); | ||||
| /* Finish computing lnos by accumulating face normals | /* Finish computing lnos by accumulating face normals | ||||
| * in each fan of faces defined by sharp edges. */ | * in each fan of faces defined by sharp edges. */ | ||||
| bm_mesh_loops_calc_normals(bm, | bm_mesh_loops_calc_normals(bm, | ||||
| vcos, | vcos, | ||||
| fnos, | fnos, | ||||
| cur_lnors, | cur_lnors, | ||||
| r_lnors_spacearr, | r_lnors_spacearr, | ||||
| r_clnors_data, | r_clnors_data, | ||||
| cd_loop_clnors_offset, | cd_loop_clnors_offset, | ||||
| false, | false, | ||||
| EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS); | ||||
| /* Extract new normals from the data layer if necessary. */ | /* Extract new normals from the data layer if necessary. */ | ||||
| float(*custom_lnors)[3] = new_lnors; | float(*custom_lnors)[3] = new_lnors; | ||||
| if (new_lnors == NULL) { | if (new_lnors == nullptr) { | ||||
| custom_lnors = MEM_mallocN(sizeof(*new_lnors) * bm->totloop, __func__); | custom_lnors = static_cast<float(*)[3]>( | ||||
| MEM_mallocN(sizeof(*new_lnors) * bm->totloop, __func__)); | |||||
| BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| const float *normal = BM_ELEM_CD_GET_VOID_P(l, cd_new_lnors_offset); | const float *normal = static_cast<float *>(BM_ELEM_CD_GET_VOID_P(l, cd_new_lnors_offset)); | ||||
| copy_v3_v3(custom_lnors[BM_elem_index_get(l)], normal); | copy_v3_v3(custom_lnors[BM_elem_index_get(l)], normal); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Validate the new normals. */ | /* Validate the new normals. */ | ||||
| for (int i = 0; i < bm->totloop; i++) { | for (int i = 0; i < bm->totloop; i++) { | ||||
| if (is_zero_v3(custom_lnors[i])) { | if (is_zero_v3(custom_lnors[i])) { | ||||
| ▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Loop Normal Space API | /** \name Loop Normal Space API | ||||
| * \{ */ | * \{ */ | ||||
| void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]) | void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]) | ||||
| { | { | ||||
| BLI_assert(bm->lnor_spacearr != NULL); | BLI_assert(bm->lnor_spacearr != nullptr); | ||||
| if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { | if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { | ||||
| BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL); | BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| } | } | ||||
| int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| BM_loops_calc_normal_vcos(bm, | BM_loops_calc_normal_vcos(bm, | ||||
| NULL, | nullptr, | ||||
| NULL, | nullptr, | ||||
| NULL, | nullptr, | ||||
| true, | true, | ||||
| M_PI, | M_PI, | ||||
| r_lnors, | r_lnors, | ||||
| bm->lnor_spacearr, | bm->lnor_spacearr, | ||||
| NULL, | nullptr, | ||||
| cd_loop_clnors_offset, | cd_loop_clnors_offset, | ||||
| false); | false); | ||||
| bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | ||||
| } | } | ||||
| #define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2) | #define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2) | ||||
| void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) | void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) | ||||
| { | { | ||||
| if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (do_invalidate_all || bm->totvertsel > CLEAR_SPACEARRAY_THRESHOLD(bm->totvert)) { | if (do_invalidate_all || bm->totvertsel > CLEAR_SPACEARRAY_THRESHOLD(bm->totvert)) { | ||||
| bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | ||||
| return; | return; | ||||
| } | } | ||||
| if (bm->lnor_spacearr == NULL) { | if (bm->lnor_spacearr == nullptr) { | ||||
| bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | ||||
| return; | return; | ||||
| } | } | ||||
| BMVert *v; | BMVert *v; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter viter, liter; | BMIter viter, liter; | ||||
| /* NOTE: we could use temp tag of BMItem for that, | /* NOTE: we could use temp tag of BMItem for that, | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) | ||||
| } | } | ||||
| MEM_freeN(done_verts); | MEM_freeN(done_verts); | ||||
| bm->spacearr_dirty |= BM_SPACEARR_DIRTY; | bm->spacearr_dirty |= BM_SPACEARR_DIRTY; | ||||
| } | } | ||||
| void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor) | void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor) | ||||
| { | { | ||||
| BLI_assert(bm->lnor_spacearr != NULL); | BLI_assert(bm->lnor_spacearr != nullptr); | ||||
| if (!(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL))) { | if (!(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL))) { | ||||
| return; | return; | ||||
| } | } | ||||
| BMFace *f; | BMFace *f; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter fiter, liter; | BMIter fiter, liter; | ||||
| float(*r_lnors)[3] = MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__); | float(*r_lnors)[3] = static_cast<float(*)[3]>( | ||||
| float(*oldnors)[3] = preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : | MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__)); | ||||
| NULL; | float(*oldnors)[3] = static_cast<float(*)[3]>( | ||||
| preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : nullptr); | |||||
| int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| BM_mesh_elem_index_ensure(bm, BM_LOOP); | BM_mesh_elem_index_ensure(bm, BM_LOOP); | ||||
| if (preserve_clnor) { | if (preserve_clnor) { | ||||
| BLI_assert(bm->lnor_spacearr->lspacearr != NULL); | BLI_assert(bm->lnor_spacearr->lspacearr != nullptr); | ||||
| BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || | if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || | ||||
| bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | ||||
| short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset); | short(*clnor)[2] = static_cast<short(*)[2]>( | ||||
| BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset)); | |||||
| int l_index = BM_elem_index_get(l); | int l_index = BM_elem_index_get(l); | ||||
| BKE_lnor_space_custom_data_to_normal( | BKE_lnor_space_custom_data_to_normal( | ||||
| bm->lnor_spacearr->lspacearr[l_index], *clnor, oldnors[l_index]); | bm->lnor_spacearr->lspacearr[l_index], *clnor, oldnors[l_index]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | ||||
| BKE_lnor_spacearr_clear(bm->lnor_spacearr); | BKE_lnor_spacearr_clear(bm->lnor_spacearr); | ||||
| } | } | ||||
| BM_loops_calc_normal_vcos(bm, | BM_loops_calc_normal_vcos(bm, | ||||
| NULL, | nullptr, | ||||
| NULL, | nullptr, | ||||
| NULL, | nullptr, | ||||
| true, | true, | ||||
| M_PI, | M_PI, | ||||
| r_lnors, | r_lnors, | ||||
| bm->lnor_spacearr, | bm->lnor_spacearr, | ||||
| NULL, | nullptr, | ||||
| cd_loop_clnors_offset, | cd_loop_clnors_offset, | ||||
| true); | true); | ||||
| MEM_freeN(r_lnors); | MEM_freeN(r_lnors); | ||||
| BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || | if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || | ||||
| bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) { | ||||
| if (preserve_clnor) { | if (preserve_clnor) { | ||||
| short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset); | short(*clnor)[2] = static_cast<short(*)[2]>( | ||||
| BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset)); | |||||
| int l_index = BM_elem_index_get(l); | int l_index = BM_elem_index_get(l); | ||||
| BKE_lnor_space_custom_normal_to_data( | BKE_lnor_space_custom_normal_to_data( | ||||
| bm->lnor_spacearr->lspacearr[l_index], oldnors[l_index], *clnor); | bm->lnor_spacearr->lspacearr[l_index], oldnors[l_index], *clnor); | ||||
| } | } | ||||
| BM_ELEM_API_FLAG_DISABLE(l, BM_LNORSPACE_UPDATE); | BM_ELEM_API_FLAG_DISABLE(l, BM_LNORSPACE_UPDATE); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(oldnors); | MEM_SAFE_FREE(oldnors); | ||||
| bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | ||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||
| BM_lnorspace_err(bm); | BM_lnorspace_err(bm); | ||||
| #endif | #endif | ||||
| } | } | ||||
| void BM_lnorspace_update(BMesh *bm) | void BM_lnorspace_update(BMesh *bm) | ||||
| { | { | ||||
| if (bm->lnor_spacearr == NULL) { | if (bm->lnor_spacearr == nullptr) { | ||||
| bm->lnor_spacearr = MEM_callocN(sizeof(*bm->lnor_spacearr), __func__); | bm->lnor_spacearr = MEM_cnew<MLoopNorSpaceArray>(__func__); | ||||
| } | } | ||||
| if (bm->lnor_spacearr->lspacearr == NULL) { | if (bm->lnor_spacearr->lspacearr == nullptr) { | ||||
| float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__); | float(*lnors)[3] = static_cast<float(*)[3]>( | ||||
| MEM_callocN(sizeof(*lnors) * bm->totloop, __func__)); | |||||
| BM_lnorspacearr_store(bm, lnors); | BM_lnorspacearr_store(bm, lnors); | ||||
| MEM_freeN(lnors); | MEM_freeN(lnors); | ||||
| } | } | ||||
| else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) { | else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) { | ||||
| BM_lnorspace_rebuild(bm, false); | BM_lnorspace_rebuild(bm, false); | ||||
| } | } | ||||
| Show All 13 Lines | |||||
| * lnor spaces to be rebuilt were not correctly marked. | * lnor spaces to be rebuilt were not correctly marked. | ||||
| */ | */ | ||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||
| void BM_lnorspace_err(BMesh *bm) | void BM_lnorspace_err(BMesh *bm) | ||||
| { | { | ||||
| bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; | ||||
| bool clear = true; | bool clear = true; | ||||
| MLoopNorSpaceArray *temp = MEM_callocN(sizeof(*temp), __func__); | MLoopNorSpaceArray *temp = MEM_cnew<MLoopNorSpaceArray>(__func__); | ||||
| temp->lspacearr = NULL; | temp->lspacearr = nullptr; | ||||
| BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR); | BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR); | ||||
| int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__); | float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__)); | ||||
| BM_loops_calc_normal_vcos( | BM_loops_calc_normal_vcos(bm, | ||||
| bm, NULL, NULL, NULL, true, M_PI, lnors, temp, NULL, cd_loop_clnors_offset, true); | nullptr, | ||||
| nullptr, | |||||
| nullptr, | |||||
| true, | |||||
| M_PI, | |||||
| lnors, | |||||
| temp, | |||||
| nullptr, | |||||
| cd_loop_clnors_offset, | |||||
| true); | |||||
| for (int i = 0; i < bm->totloop; i++) { | for (int i = 0; i < bm->totloop; i++) { | ||||
| int j = 0; | int j = 0; | ||||
| j += compare_ff( | j += compare_ff( | ||||
| temp->lspacearr[i]->ref_alpha, bm->lnor_spacearr->lspacearr[i]->ref_alpha, 1e-4f); | temp->lspacearr[i]->ref_alpha, bm->lnor_spacearr->lspacearr[i]->ref_alpha, 1e-4f); | ||||
| j += compare_ff( | j += compare_ff( | ||||
| temp->lspacearr[i]->ref_beta, bm->lnor_spacearr->lspacearr[i]->ref_beta, 1e-4f); | temp->lspacearr[i]->ref_beta, bm->lnor_spacearr->lspacearr[i]->ref_beta, 1e-4f); | ||||
| j += compare_v3v3( | j += compare_v3v3( | ||||
| Show All 18 Lines | |||||
| #endif | #endif | ||||
| static void bm_loop_normal_mark_indiv_do_loop(BMLoop *l, | static void bm_loop_normal_mark_indiv_do_loop(BMLoop *l, | ||||
| BLI_bitmap *loops, | BLI_bitmap *loops, | ||||
| MLoopNorSpaceArray *lnor_spacearr, | MLoopNorSpaceArray *lnor_spacearr, | ||||
| int *totloopsel, | int *totloopsel, | ||||
| const bool do_all_loops_of_vert) | const bool do_all_loops_of_vert) | ||||
| { | { | ||||
| if (l != NULL) { | if (l != nullptr) { | ||||
| const int l_idx = BM_elem_index_get(l); | const int l_idx = BM_elem_index_get(l); | ||||
| if (!BLI_BITMAP_TEST(loops, l_idx)) { | if (!BLI_BITMAP_TEST(loops, l_idx)) { | ||||
| /* If vert and face selected share a loop, mark it for editing. */ | /* If vert and face selected share a loop, mark it for editing. */ | ||||
| BLI_BITMAP_ENABLE(loops, l_idx); | BLI_BITMAP_ENABLE(loops, l_idx); | ||||
| (*totloopsel)++; | (*totloopsel)++; | ||||
| if (do_all_loops_of_vert) { | if (do_all_loops_of_vert) { | ||||
| Show All 34 Lines | static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops, const bool do_all_loops_of_vert) | ||||
| const bool sel_verts = (bm->selectmode & SCE_SELECT_VERTEX) != 0; | const bool sel_verts = (bm->selectmode & SCE_SELECT_VERTEX) != 0; | ||||
| const bool sel_edges = (bm->selectmode & SCE_SELECT_EDGE) != 0; | const bool sel_edges = (bm->selectmode & SCE_SELECT_EDGE) != 0; | ||||
| const bool sel_faces = (bm->selectmode & SCE_SELECT_FACE) != 0; | const bool sel_faces = (bm->selectmode & SCE_SELECT_FACE) != 0; | ||||
| const bool use_sel_face_history = sel_faces && (sel_edges || sel_verts); | const bool use_sel_face_history = sel_faces && (sel_edges || sel_verts); | ||||
| BM_mesh_elem_index_ensure(bm, BM_LOOP); | BM_mesh_elem_index_ensure(bm, BM_LOOP); | ||||
| BLI_assert(bm->lnor_spacearr != NULL); | BLI_assert(bm->lnor_spacearr != nullptr); | ||||
| BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); | ||||
| if (use_sel_face_history) { | if (use_sel_face_history) { | ||||
| /* Using face history allows to select a single loop from a single face... | /* Using face history allows to select a single loop from a single face... | ||||
| * Note that this is O(n^2) piece of code, | * Note that this is O(n^2) piece of code, | ||||
| * but it is not designed to be used with huge selection sets, | * but it is not designed to be used with huge selection sets, | ||||
| * rather with only a few items selected at most. */ | * rather with only a few items selected at most. */ | ||||
| /* Goes from last selected to the first selected element. */ | /* Goes from last selected to the first selected element. */ | ||||
| for (ese = bm->selected.last; ese; ese = ese->prev) { | for (ese = static_cast<BMEditSelection *>(bm->selected.last); ese; ese = ese->prev) { | ||||
| if (ese->htype == BM_FACE) { | if (ese->htype == BM_FACE) { | ||||
| /* If current face is selected, | /* If current face is selected, | ||||
| * then any verts to be edited must have been selected before it. */ | * then any verts to be edited must have been selected before it. */ | ||||
| for (ese_prev = ese->prev; ese_prev; ese_prev = ese_prev->prev) { | for (ese_prev = ese->prev; ese_prev; ese_prev = ese_prev->prev) { | ||||
| if (ese_prev->htype == BM_VERT) { | if (ese_prev->htype == BM_VERT) { | ||||
| bm_loop_normal_mark_indiv_do_loop( | bm_loop_normal_mark_indiv_do_loop( | ||||
| BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele), | BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele), | ||||
| loops, | loops, | ||||
| ▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops, const bool do_all_loops_of_vert) | ||||
| } | } | ||||
| return totloopsel; | return totloopsel; | ||||
| } | } | ||||
| static void loop_normal_editdata_init( | static void loop_normal_editdata_init( | ||||
| BMesh *bm, BMLoopNorEditData *lnor_ed, BMVert *v, BMLoop *l, const int offset) | BMesh *bm, BMLoopNorEditData *lnor_ed, BMVert *v, BMLoop *l, const int offset) | ||||
| { | { | ||||
| BLI_assert(bm->lnor_spacearr != NULL); | BLI_assert(bm->lnor_spacearr != nullptr); | ||||
| BLI_assert(bm->lnor_spacearr->lspacearr != NULL); | BLI_assert(bm->lnor_spacearr->lspacearr != nullptr); | ||||
| const int l_index = BM_elem_index_get(l); | const int l_index = BM_elem_index_get(l); | ||||
| short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, offset); | short *clnors_data = static_cast<short *>(BM_ELEM_CD_GET_VOID_P(l, offset)); | ||||
| lnor_ed->loop_index = l_index; | lnor_ed->loop_index = l_index; | ||||
| lnor_ed->loop = l; | lnor_ed->loop = l; | ||||
| float custom_normal[3]; | float custom_normal[3]; | ||||
| BKE_lnor_space_custom_data_to_normal( | BKE_lnor_space_custom_data_to_normal( | ||||
| bm->lnor_spacearr->lspacearr[l_index], clnors_data, custom_normal); | bm->lnor_spacearr->lspacearr[l_index], clnors_data, custom_normal); | ||||
| Show All 10 Lines | BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm, | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMVert *v; | BMVert *v; | ||||
| BMIter liter, viter; | BMIter liter, viter; | ||||
| int totloopsel = 0; | int totloopsel = 0; | ||||
| BLI_assert(bm->spacearr_dirty == 0); | BLI_assert(bm->spacearr_dirty == 0); | ||||
| BMLoopNorEditDataArray *lnors_ed_arr = MEM_callocN(sizeof(*lnors_ed_arr), __func__); | BMLoopNorEditDataArray *lnors_ed_arr = MEM_cnew<BMLoopNorEditDataArray>(__func__); | ||||
| lnors_ed_arr->lidx_to_lnor_editdata = MEM_callocN( | lnors_ed_arr->lidx_to_lnor_editdata = MEM_cnew_array<BMLoopNorEditData *>(bm->totloop, __func__); | ||||
| sizeof(*lnors_ed_arr->lidx_to_lnor_editdata) * bm->totloop, __func__); | |||||
| if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { | if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { | ||||
| BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL); | BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| } | } | ||||
| const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| BM_mesh_elem_index_ensure(bm, BM_LOOP); | BM_mesh_elem_index_ensure(bm, BM_LOOP); | ||||
| BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__); | BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__); | ||||
| /* This function define loop normals to edit, based on selection modes and history. */ | /* This function define loop normals to edit, based on selection modes and history. */ | ||||
| totloopsel = bm_loop_normal_mark_indiv(bm, loops, do_all_loops_of_vert); | totloopsel = bm_loop_normal_mark_indiv(bm, loops, do_all_loops_of_vert); | ||||
| if (totloopsel) { | if (totloopsel) { | ||||
| BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN( | BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = static_cast<BMLoopNorEditData *>( | ||||
| sizeof(*lnor_ed) * totloopsel, __func__); | MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__)); | ||||
| BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | ||||
| if (BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) { | if (BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) { | ||||
| loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset); | loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset); | ||||
| lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed; | lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed; | ||||
| lnor_ed++; | lnor_ed++; | ||||
| } | } | ||||
| Show All 40 Lines | bool BM_custom_loop_normals_to_vector_layer(BMesh *bm) | ||||
| } | } | ||||
| const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL); | const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL); | ||||
| int l_index = 0; | int l_index = 0; | ||||
| BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| const short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, cd_custom_normal_offset); | const short *clnors_data = static_cast<const short *>( | ||||
| float *normal = BM_ELEM_CD_GET_VOID_P(l, cd_normal_offset); | BM_ELEM_CD_GET_VOID_P(l, cd_custom_normal_offset)); | ||||
| float *normal = static_cast<float *>(BM_ELEM_CD_GET_VOID_P(l, cd_normal_offset)); | |||||
| BKE_lnor_space_custom_data_to_normal( | BKE_lnor_space_custom_data_to_normal( | ||||
| bm->lnor_spacearr->lspacearr[l_index], clnors_data, normal); | bm->lnor_spacearr->lspacearr[l_index], clnors_data, normal); | ||||
| l_index += 1; | l_index += 1; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges) | void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges) | ||||
| { | { | ||||
| if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL) || | if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL) || | ||||
| !CustomData_has_layer(&bm->ldata, CD_NORMAL)) { | !CustomData_has_layer(&bm->ldata, CD_NORMAL)) { | ||||
| return; | return; | ||||
| } | } | ||||
| const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL); | const int cd_normal_offset = CustomData_get_offset(&bm->ldata, CD_NORMAL); | ||||
| if (bm->lnor_spacearr == NULL) { | if (bm->lnor_spacearr == nullptr) { | ||||
| bm->lnor_spacearr = MEM_callocN(sizeof(*bm->lnor_spacearr), __func__); | bm->lnor_spacearr = MEM_cnew<MLoopNorSpaceArray>(__func__); | ||||
| } | } | ||||
| bm_mesh_loops_custom_normals_set(bm, | bm_mesh_loops_custom_normals_set(bm, | ||||
| NULL, | nullptr, | ||||
| NULL, | nullptr, | ||||
| bm->lnor_spacearr, | bm->lnor_spacearr, | ||||
| NULL, | nullptr, | ||||
| cd_custom_normal_offset, | cd_custom_normal_offset, | ||||
| NULL, | nullptr, | ||||
| cd_normal_offset, | cd_normal_offset, | ||||
| add_sharp_edges); | add_sharp_edges); | ||||
| bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||