Changeset View
Changeset View
Standalone View
Standalone View
source/blender/bmesh/intern/bmesh_query_uv.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| /** \file | /** \file | ||||
| * \ingroup bmesh | * \ingroup bmesh | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_array.hh" | #include "BLI_array.hh" | ||||
| #include "BLI_linklist.h" | #include "BLI_linklist.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_math_vector_types.hh" | #include "BLI_math_vector_types.hh" | ||||
| #include "BLI_utildefines_stack.h" | #include "BLI_utildefines_stack.h" | ||||
| #include "BKE_attribute.hh" | |||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "bmesh.h" | #include "bmesh.h" | ||||
| #include "intern/bmesh_private.h" | #include "intern/bmesh_private.h" | ||||
| BMUVOffsets BM_uv_map_get_offsets(const BMesh *bm) | |||||
| { | |||||
| using namespace blender; | |||||
| using namespace blender::bke; | |||||
| const int layer_index = CustomData_get_active_layer_index(&bm->ldata, CD_PROP_FLOAT2); | |||||
| if (layer_index == -1) { | |||||
| return {-1, -1, -1, -1}; | |||||
| } | |||||
| char const *name = bm->ldata.layers[layer_index].name; | |||||
| char buffer[MAX_CUSTOMDATA_LAYER_NAME]; | |||||
| BMUVOffsets offsets; | |||||
| offsets.uv = bm->ldata.layers[layer_index].offset; | |||||
| offsets.select_vert = CustomData_get_offset_named( | |||||
| &bm->ldata, CD_PROP_BOOL, BKE_uv_map_vert_select_name_get(name, buffer)); | |||||
| offsets.select_edge = CustomData_get_offset_named( | |||||
| &bm->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(name, buffer)); | |||||
| offsets.pin = CustomData_get_offset_named( | |||||
| &bm->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(name, buffer)); | |||||
| return offsets; | |||||
| } | |||||
| static void uv_aspect(const BMLoop *l, | static void uv_aspect(const BMLoop *l, | ||||
| const float aspect[2], | const float aspect[2], | ||||
| const int cd_loop_uv_offset, | const int cd_loop_uv_offset, | ||||
| float r_uv[2]) | float r_uv[2]) | ||||
| { | { | ||||
| const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; | const float *uv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); | ||||
| r_uv[0] = uv[0] * aspect[0]; | r_uv[0] = uv[0] * aspect[0]; | ||||
| r_uv[1] = uv[1] * aspect[1]; | r_uv[1] = uv[1] * aspect[1]; | ||||
| } | } | ||||
| /** | /** | ||||
| * Typically we avoid hiding arguments, | * Typically we avoid hiding arguments, | ||||
| * make this an exception since it reads poorly with so many repeated arguments. | * make this an exception since it reads poorly with so many repeated arguments. | ||||
| */ | */ | ||||
| Show All 40 Lines | |||||
| void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2]) | void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2]) | ||||
| { | { | ||||
| const BMLoop *l_iter; | const BMLoop *l_iter; | ||||
| const BMLoop *l_first; | const BMLoop *l_first; | ||||
| zero_v2(r_cent); | zero_v2(r_cent); | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | const float *luv = BM_ELEM_CD_GET_FLOAT_P(l_iter, cd_loop_uv_offset); | ||||
| add_v2_v2(r_cent, luv->uv); | add_v2_v2(r_cent, luv); | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| mul_v2_fl(r_cent, 1.0f / float(f->len)); | mul_v2_fl(r_cent, 1.0f / float(f->len)); | ||||
| } | } | ||||
| float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) | float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) | ||||
| { | { | ||||
| blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> uvs(f->len); | blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> uvs(f->len); | ||||
| const BMLoop *l_iter; | const BMLoop *l_iter; | ||||
| const BMLoop *l_first; | const BMLoop *l_first; | ||||
| int i = 0; | int i = 0; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | uvs[i++] = BM_ELEM_CD_GET_FLOAT2_P(l_iter, cd_loop_uv_offset); | ||||
| uvs[i++] = luv->uv; | |||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| return cross_poly_v2(reinterpret_cast<const float(*)[2]>(uvs.data()), f->len); | return cross_poly_v2(reinterpret_cast<const float(*)[2]>(uvs.data()), f->len); | ||||
| } | } | ||||
| void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset) | void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset) | ||||
| { | { | ||||
| const BMLoop *l_iter; | const BMLoop *l_iter; | ||||
| const BMLoop *l_first; | const BMLoop *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | const float *luv = BM_ELEM_CD_GET_FLOAT_P(l_iter, cd_loop_uv_offset); | ||||
| minmax_v2v2_v2(min, max, luv->uv); | minmax_v2v2_v2(min, max, luv); | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| } | } | ||||
| bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | ||||
| { | { | ||||
| BLI_assert(l_a->e == l_b->e); | BLI_assert(l_a->e == l_b->e); | ||||
| MLoopUV *luv_a_curr = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); | float *luv_a_curr = BM_ELEM_CD_GET_FLOAT_P(l_a, cd_loop_uv_offset); | ||||
| MLoopUV *luv_a_next = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a->next, cd_loop_uv_offset); | float *luv_a_next = BM_ELEM_CD_GET_FLOAT_P(l_a->next, cd_loop_uv_offset); | ||||
| MLoopUV *luv_b_curr = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); | float *luv_b_curr = BM_ELEM_CD_GET_FLOAT_P(l_b, cd_loop_uv_offset); | ||||
| MLoopUV *luv_b_next = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b->next, cd_loop_uv_offset); | float *luv_b_next = BM_ELEM_CD_GET_FLOAT_P(l_b->next, cd_loop_uv_offset); | ||||
| if (l_a->v != l_b->v) { | if (l_a->v != l_b->v) { | ||||
| std::swap(luv_b_curr, luv_b_next); | std::swap(luv_b_curr, luv_b_next); | ||||
| } | } | ||||
| return (equals_v2v2(luv_a_curr->uv, luv_b_curr->uv) && | return (equals_v2v2(luv_a_curr, luv_b_curr) && equals_v2v2(luv_a_next, luv_b_next)); | ||||
| equals_v2v2(luv_a_next->uv, luv_b_next->uv)); | |||||
| } | } | ||||
| bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | ||||
| { | { | ||||
| BLI_assert(l_a->v == l_b->v); | BLI_assert(l_a->v == l_b->v); | ||||
| const MLoopUV *luv_a = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset); | const float *luv_a = BM_ELEM_CD_GET_FLOAT_P(l_a, cd_loop_uv_offset); | ||||
| const MLoopUV *luv_b = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset); | const float *luv_b = BM_ELEM_CD_GET_FLOAT_P(l_b, cd_loop_uv_offset); | ||||
| if (!equals_v2v2(luv_a->uv, luv_b->uv)) { | if (!equals_v2v2(luv_a, luv_b)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset) | ||||
| { | { | ||||
| BLI_assert(l_a->v == l_b->v); | BLI_assert(l_a->v == l_b->v); | ||||
| if (!BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) { | if (!BM_loop_uv_share_vert_check(l_a, l_b, cd_loop_uv_offset)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* No need for NULL checks, these will always succeed. */ | /* No need for NULL checks, these will always succeed. */ | ||||
| const BMLoop *l_other_a = BM_loop_other_vert_loop_by_edge(l_a, e); | const BMLoop *l_other_a = BM_loop_other_vert_loop_by_edge(l_a, e); | ||||
| const BMLoop *l_other_b = BM_loop_other_vert_loop_by_edge(l_b, e); | const BMLoop *l_other_b = BM_loop_other_vert_loop_by_edge(l_b, e); | ||||
| { | { | ||||
| const MLoopUV *luv_other_a = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_other_a, | const float *luv_other_a = BM_ELEM_CD_GET_FLOAT_P(l_other_a, cd_loop_uv_offset); | ||||
| cd_loop_uv_offset); | const float *luv_other_b = BM_ELEM_CD_GET_FLOAT_P(l_other_b, cd_loop_uv_offset); | ||||
| const MLoopUV *luv_other_b = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_other_b, | if (!equals_v2v2(luv_other_a, luv_other_b)) { | ||||
| cd_loop_uv_offset); | |||||
| if (!equals_v2v2(luv_other_a->uv, luv_other_b->uv)) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset) | bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset) | ||||
| { | { | ||||
| blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> projverts(f->len); | blender::Array<blender::float2, BM_DEFAULT_NGON_STACK_SIZE> projverts(f->len); | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| int i; | int i; | ||||
| BLI_assert(BM_face_is_normal_valid(f)); | BLI_assert(BM_face_is_normal_valid(f)); | ||||
| for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) { | for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) { | ||||
| projverts[i] = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; | projverts[i] = BM_ELEM_CD_GET_FLOAT2_P(l_iter, cd_loop_uv_offset); | ||||
| } | } | ||||
| return isect_point_poly_v2( | return isect_point_poly_v2( | ||||
| co, reinterpret_cast<const float(*)[2]>(projverts.data()), f->len, false); | co, reinterpret_cast<const float(*)[2]>(projverts.data()), f->len, false); | ||||
| } | } | ||||