93 return (
ULData *)&
l->head.index;
103 const int cd_loop_uv_offset)
105 BMLoop *l_other =
nullptr;
107 if (l_iter != l_src) {
113 if (l_other ==
nullptr) {
129 const int cd_loop_uv_offset)
132 BMLoop *l_other =
nullptr;
134 if (l_iter != l_src) {
140 if (l_other ==
nullptr) {
151 if (l_other !=
nullptr) {
152 if (l_other->
v == v_src) {
155 else if (l_other->
next->
v == v_src) {
156 l_other = l_other->
next;
158 else if (l_other->
prev->
v == v_src) {
159 l_other = l_other->
prev;
175 if (
l->e == e_prev) {
178 else if (
l->prev->e == e_prev) {
196 bool is_single_vert =
true;
201 is_single_vert =
false;
206 if (is_single_vert ==
false) {
208 if (
UL(
l)->is_select_vert_single) {
226 const float aspect_y,
227 const int cd_loop_uv_offset,
228 float *r_corner_angle,
240 dir_test[0][1] /= aspect_y;
241 dir_test[2][1] /= aspect_y;
247 sub_v2_v2v2(dir_test[1], dir_test[0], dir_test[2]);
251 std::swap(dir_test[1][0], dir_test[1][1]);
252 dir_test[1][1] *= -1.0f;
255 dir_test[1] *= -1.0f;
258 const float angles[3] = {
265 *r_corner_angle = angles[1];
268 if (angles[0] < angles[2]) {
269 *r_edge_angle = angles[0];
273 *r_edge_angle = angles[2];
305 const float aspect_y,
306 const int cd_loop_uv_offset)
315 BMLoop *l_init_edge =
nullptr;
316 float corner_angle_best =
FLT_MAX;
317 float edge_angle_best =
FLT_MAX;
318 int edge_index_best = 0;
323 dir_co[1] /= aspect_y;
328 int uv_fan_count_all = 0;
336 uv_fan_count_all += 1;
343 float corner_angle_test;
344 float edge_angle_test;
353 if ((corner_angle_best ==
FLT_MAX) || (corner_angle_test < corner_angle_best)) {
354 corner_angle_best = corner_angle_test;
359 edge_angle_test =
min_ff(corner_angle_test, edge_angle_test);
361 if ((edge_angle_best ==
FLT_MAX) || (edge_angle_test < edge_angle_best)) {
362 edge_angle_best = edge_angle_test;
363 edge_index_best = edge_index_test;
372 int uv_fan_count_contiguous = 1;
374 for (
int i = 0;
i < 2;
i += 1) {
378 (l_iter !=
nullptr) && (
UL(l_iter)->side == 0))
380 uv_fan_count_contiguous += 1;
386 if (l_iter == l_init) {
392 if (uv_fan_count_contiguous != uv_fan_count_all) {
402 if (uv_fan_count_contiguous <= 2) {
408 BMLoop *l_radial_init = (edge_index_best == -1) ? l_init_edge->
prev : l_init_edge;
409 BMLoop *l_radial_iter = l_radial_init;
412 BMLoop *
l = (l_radial_iter->
v == l_init->
v) ? l_radial_iter : l_radial_iter->
next;
417 }
while ((l_radial_iter = l_radial_iter->
radial_next) != l_radial_init);
465 const float aspect_y,
466 const int cd_loop_uv_offset)
470 float angle_of_side = 0.0f;
473 if (
UL(
l)->in_rip_pairs) {
474 if (
UL(
l)->side == side) {
479 float dir_prev[2], dir_next[2];
482 dir_prev[1] /= aspect_y;
483 dir_next[1] /= aspect_y;
484 const float luv_angle =
angle_v2v2(dir_prev, dir_next);
485 if (
LIKELY(isfinite(luv_angle))) {
486 angle_of_side += luv_angle;
492 return angle_of_side;
502 if (
UL(
l)->in_rip_pairs) {
503 if (
UL(
l)->side == side) {
516 const float aspect_y,
517 const int cd_loop_uv_offset)
519 const int side_a =
UL(l_switch)->
side;
520 const int side_b =
UL(l_target)->
side;
528 if (count_a + count_b == 4) {
529 return count_a > count_b;
533 l_switch, side_a, aspect_y, cd_loop_uv_offset);
535 l_target, side_b, aspect_y, cd_loop_uv_offset);
537 UL(l_switch)->
side = side_b;
540 l_switch, side_a, aspect_y, cd_loop_uv_offset);
542 l_target, side_b, aspect_y, cd_loop_uv_offset);
544 UL(l_switch)->
side = side_a;
546 return fabsf(angle_a_before - angle_b_before) >
fabsf(angle_a_after - angle_b_after);
558 const float aspect_y,
559 const int cd_loop_uv_offset)
572#define UV_SET_SIDE_AND_REMOVE_FROM_RAIL(loop, side_value) \
574 BLI_assert(UL(loop)->side_was_swapped == false); \
575 BLI_assert(UL(loop)->side != side_value); \
576 if (!UL(loop)->in_stack) { \
577 BLI_SMALLSTACK_PUSH(stack, loop); \
578 UL(loop)->in_stack = true; \
580 if (UL(loop)->in_rip_pairs) { \
581 uv_rip_pairs_remove(rip, loop); \
583 UL(loop)->side = side_value; \
584 UL(loop)->side_was_swapped = true; \
593 int side =
UL(l_step)->
side;
601 if (
UL(l_step)->is_select_edge) {
604 if (l_other !=
nullptr) {
605 if (!
UL(l_other)->in_rip_pairs && !
UL(l_other)->in_stack) {
608 UL(l_other)->
side = !side;
611 if (
UL(l_other)->side == side) {
612 if (
UL(l_other)->side_was_swapped ==
false) {
620 l_other = l_step->
next;
621 if (!
UL(l_other)->in_rip_pairs && !
UL(l_other)->in_stack) {
627 if (
UL(l_other)->side != side) {
628 if ((
UL(l_other)->side_was_swapped ==
false) &&
638 for (
int i = 0;
i < 2;
i++) {
639 BMLoop *l_radial_first =
i ? l_step : l_step->
prev;
640 if (l_radial_first != l_radial_first->
radial_next) {
641 BMEdge *e_radial = l_radial_first->
e;
645 if (!
UL(l_radial_iter)->is_select_edge &&
648 BMLoop *l_other = (l_radial_iter->
v == l_step->
v) ? l_radial_iter :
652 if (!
UL(l_other)->in_rip_pairs && !
UL(l_other)->in_stack) {
658 if (
UL(l_other)->side != side) {
659 if ((
UL(l_other)->side_was_swapped ==
false) &&
661 l_other, l_step, aspect_y, cd_loop_uv_offset))
669 }
while ((l_radial_iter = l_radial_iter->
radial_next) != l_radial_first);
674#undef UV_SET_SIDE_AND_REMOVE_FROM_RAIL
689 const int cd_loop_uv_offset,
691 float r_dir_side[2][2])
694 int center_total = 0;
695 int side_total[2] = {0, 0};
697 for (
int i = 0;
i < 2;
i++) {
708 if (!
UL(
l)->is_select_edge) {
718 side_total[side] += 1;
722 for (
int i = 0;
i < 2;
i++) {
725 mul_v2_fl(r_center, 1.0f / center_total);
728 return side_total[0] && side_total[1];
761 const ULData ul_clear = {0};
763 bool changed =
false;
774 bool is_select_all_any =
false;
801 is_select_all_any =
true;
810 if (
UL(
l)->is_select_vert_single) {
823 if (is_select_all_any) {
826 if (!
UL(
l)->is_select_all) {
845 if (
UL(
l)->is_select_edge) {
846 if (!
UL(
l)->in_rip_pairs) {
850 float dir_side[2][2];
851 int side_from_cursor = -1;
853 for (
int i = 0;
i < 2;
i++) {
857 side_from_cursor = (
dot_v2v2(dir_side[0], dir_cursor) -
858 dot_v2v2(dir_side[1], dir_cursor)) < 0.0f;
864 if (ul->
side == side_from_cursor) {
874 else if (
UL(
l)->is_select_vert_single) {
877 const int side_from_cursor = 0;
882 if (ul->
side == side_from_cursor) {
931 "Rip is only compatible with sync-select with vertex/edge selection");
936 bool changed_multi =
false;
947 const float aspect_y = aspx / aspy;
950 scene, view_layer,
nullptr);
958 for (
Object *obedit : objects) {
960 changed_multi =
true;
967 if (!changed_multi) {
989 ot->description =
"Rip selected vertices or a selected region";
990 ot->idname =
"UV_OT_rip";
1010 "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
SpaceImage * CTX_wm_space_image(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_unreachable()
#define BLI_STATIC_ASSERT(a, msg)
GSet * BLI_gset_ptr_new(const char *info)
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
#define GSET_ITER(gs_iter_, gset_)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
BLI_LINKSTACK_*** wrapper macros for using a LinkNode to store a stack of pointers,...
#define BLI_SMALLSTACK_DECLARE(var, type)
#define BLI_SMALLSTACK_POP(var)
#define BLI_SMALLSTACK_PUSH(var, data)
MINLINE float min_ff(float a, float b)
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float n[2])
void DEG_id_tag_update(ID *id, unsigned int flags)
Object is a sort of wrapper for general info.
bool EDBM_selectmode_set_multi_ex(Scene *scene, blender::Span< Object * > objects, const short selectmode)
bool ED_operator_uvedit(bContext *C)
bool uvedit_loop_vert_select_get(const ToolSettings *ts, const BMesh *bm, const BMLoop *l)
bool ED_uvedit_sync_uvselect_ignore(const ToolSettings *ts)
void uvedit_select_flush_from_verts(const Scene *scene, BMesh *bm, bool select)
void uvedit_uv_select_disable(const Scene *scene, BMesh *bm, BMLoop *l)
void uvedit_loop_vert_select_set(const ToolSettings *ts, const BMesh *bm, BMLoop *l, const bool select)
bool uvedit_loop_edge_select_get(const ToolSettings *ts, const BMesh *bm, const BMLoop *l)
void ED_uvedit_get_aspect(Object *obedit, float *r_aspx, float *r_aspy)
void uvedit_loop_edge_select_set(const ToolSettings *ts, const BMesh *bm, BMLoop *l, const bool select)
bool uvedit_face_visible_test(const Scene *scene, const BMFace *efa)
Read Guarded memory(de)allocation.
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
@ OPTYPE_DEPENDS_ON_CURSOR
#define BM_ELEM_CD_GET_FLOAT_P(ele, offset)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
BMUVOffsets BM_uv_map_offsets_get(const BMesh *bm)
bool BM_loop_uv_share_edge_check(const BMLoop *l_a, const BMLoop *l_b, const int cd_loop_uv_offset)
bool BM_edge_uv_share_vert_check(const BMEdge *e, const BMLoop *l_a, const BMLoop *l_b, const int cd_loop_uv_offset)
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
void BM_mesh_uvselect_flush_from_loop_verts(BMesh *bm)
void * MEM_callocN(size_t len, const char *str)
void MEM_freeN(void *vmemh)
VecBase< float, 2 > float2
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
struct BMLoop * radial_next
struct ToolSettings * toolsettings
uint is_select_vert_single
struct ReportList * reports
void uvedit_select_prepare_sync_select(const Scene *scene, BMesh *bm)
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
void uvedit_select_prepare_custom_data(const Scene *scene, BMesh *bm)
static wmOperatorStatus uv_rip_exec(bContext *C, wmOperator *op)
static wmOperatorStatus uv_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static BMLoop * bm_loop_find_other_fan_loop_with_visible_face(BMLoop *l_src, BMVert *v_src, const int cd_loop_uv_offset)
#define UV_SET_SIDE_AND_REMOVE_FROM_RAIL(loop, side_value)
static void bm_loop_uv_select_single_vert_validate(BMLoop *l_init, const int cd_loop_uv_offset)
static void uv_rip_pairs_free(UVRipPairs *rip)
BLI_INLINE ULData * UL(BMLoop *l)
static void uv_rip_single_free(UVRipSingle *rip)
static void uv_rip_pairs_remove(UVRipPairs *rip, BMLoop *l)
static void uv_rip_pairs_add(UVRipPairs *rip, BMLoop *l)
static int uv_rip_pairs_loop_count_on_side(BMLoop *l_init, uint side, const int cd_loop_uv_offset)
static UVRipSingle * uv_rip_single_from_loop(BMLoop *l_init_orig, const float co[2], const float aspect_y, const int cd_loop_uv_offset)
static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const float aspect_y)
static BMLoop * bm_loop_find_other_radial_loop_with_visible_face(BMLoop *l_src, const int cd_loop_uv_offset)
void UV_OT_rip(wmOperatorType *ot)
static UVRipPairs * uv_rip_pairs_from_loop(BMLoop *l_init, const float aspect_y, const int cd_loop_uv_offset)
static float uv_rip_pairs_calc_uv_angle(BMLoop *l_init, uint side, const float aspect_y, const int cd_loop_uv_offset)
static bool uv_rip_pairs_calc_center_and_direction(UVRipPairs *rip, const int cd_loop_uv_offset, float r_center[2], float r_dir_side[2][2])
static bool uv_rip_pairs_loop_change_sides_test(BMLoop *l_switch, BMLoop *l_target, const float aspect_y, const int cd_loop_uv_offset)
static void bm_loop_calc_uv_angle_from_dir(BMLoop *l, const float dir[2], const float aspect_y, const int cd_loop_uv_offset, float *r_corner_angle, float *r_edge_angle, int *r_edge_index)
static BMLoop * bm_vert_step_fan_loop_uv(BMLoop *l, BMEdge **e_step, const int cd_loop_uv_offset)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)