Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt48
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c315
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c759
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h93
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c7665
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c6861
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h14
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c4920
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c3645
9 files changed, 12421 insertions, 11899 deletions
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 45cd9b09de3..240cfd382a4 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -16,42 +16,42 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
- ../../blenkernel
- ../../blenlib
- ../../blentranslation
- ../../bmesh
- ../../depsgraph
- ../../gpu
- ../../makesdna
- ../../makesrna
- ../../windowmanager
- ../../../../intern/guardedalloc
- ../../../../intern/eigen
- ../../../../intern/glew-mx
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../bmesh
+ ../../depsgraph
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/eigen
+ ../../../../intern/glew-mx
)
set(INC_SYS
- ${GLEW_INCLUDE_PATH}
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
- uvedit_buttons.c
- uvedit_draw.c
- uvedit_ops.c
- uvedit_parametrizer.c
- uvedit_smart_stitch.c
- uvedit_unwrap_ops.c
-
- uvedit_intern.h
- uvedit_parametrizer.h
+ uvedit_buttons.c
+ uvedit_draw.c
+ uvedit_ops.c
+ uvedit_parametrizer.c
+ uvedit_smart_stitch.c
+ uvedit_unwrap_ops.c
+
+ uvedit_intern.h
+ uvedit_parametrizer.h
)
set(LIB
)
if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 6f8bfac8c57..16620436029 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -53,62 +53,63 @@
#include "WM_api.h"
#include "WM_types.h"
-#define B_UVEDIT_VERTEX 3
+#define B_UVEDIT_VERTEX 3
/* UV Utilities */
static int uvedit_center(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float center[2])
{
- BMFace *f;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int tot = 0;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- zero_v2(center);
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f))
- continue;
-
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(center, luv->uv);
- tot++;
- }
- }
- }
-
- if (tot > 0) {
- center[0] /= tot;
- center[1] /= tot;
- }
-
- return tot;
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int tot = 0;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ zero_v2(center);
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, f))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(center, luv->uv);
+ tot++;
+ }
+ }
+ }
+
+ if (tot > 0) {
+ center[0] /= tot;
+ center[1] /= tot;
+ }
+
+ return tot;
}
-static void uvedit_translate(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float delta[2])
+static void uvedit_translate(
+ Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float delta[2])
{
- BMFace *f;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f))
- continue;
-
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(luv->uv, delta);
- }
- }
- }
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, f))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(luv->uv, delta);
+ }
+ }
+ }
}
/* Button Functions, using an evil static variable */
@@ -117,122 +118,144 @@ static float uvedit_old_center[2];
static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Image *ima = sima->image;
- BMEditMesh *em;
- float center[2];
- int imx, imy, step, digits;
- float width = 8 * UI_UNIT_X;
-
- ED_space_image_get_size(sima, &imx, &imy);
-
- em = BKE_editmesh_from_object(obedit);
-
- if (uvedit_center(scene, obedit, em, ima, center)) {
- float range_xy[2][2] = {
- {-10.0f, 10.0f},
- {-10.0f, 10.0f},
- };
-
- copy_v2_v2(uvedit_old_center, center);
-
- /* expand UI range by center */
- CLAMP_MAX(range_xy[0][0], uvedit_old_center[0]);
- CLAMP_MIN(range_xy[0][1], uvedit_old_center[0]);
- CLAMP_MAX(range_xy[1][0], uvedit_old_center[1]);
- CLAMP_MIN(range_xy[1][1], uvedit_old_center[1]);
-
- if (!(sima->flag & SI_COORDFLOATS)) {
- uvedit_old_center[0] *= imx;
- uvedit_old_center[1] *= imy;
-
- mul_v2_fl(range_xy[0], imx);
- mul_v2_fl(range_xy[1], imy);
- }
-
- if (sima->flag & SI_COORDFLOATS) {
- step = 1;
- digits = 3;
- }
- else {
- step = 100;
- digits = 2;
- }
-
- UI_block_align_begin(block);
- uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 0, 0, width, UI_UNIT_Y, &uvedit_old_center[0],
- UNPACK2(range_xy[0]), step, digits, "");
- uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), width, 0, width, UI_UNIT_Y, &uvedit_old_center[1],
- UNPACK2(range_xy[1]), step, digits, "");
- UI_block_align_end(block);
- }
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Image *ima = sima->image;
+ BMEditMesh *em;
+ float center[2];
+ int imx, imy, step, digits;
+ float width = 8 * UI_UNIT_X;
+
+ ED_space_image_get_size(sima, &imx, &imy);
+
+ em = BKE_editmesh_from_object(obedit);
+
+ if (uvedit_center(scene, obedit, em, ima, center)) {
+ float range_xy[2][2] = {
+ {-10.0f, 10.0f},
+ {-10.0f, 10.0f},
+ };
+
+ copy_v2_v2(uvedit_old_center, center);
+
+ /* expand UI range by center */
+ CLAMP_MAX(range_xy[0][0], uvedit_old_center[0]);
+ CLAMP_MIN(range_xy[0][1], uvedit_old_center[0]);
+ CLAMP_MAX(range_xy[1][0], uvedit_old_center[1]);
+ CLAMP_MIN(range_xy[1][1], uvedit_old_center[1]);
+
+ if (!(sima->flag & SI_COORDFLOATS)) {
+ uvedit_old_center[0] *= imx;
+ uvedit_old_center[1] *= imy;
+
+ mul_v2_fl(range_xy[0], imx);
+ mul_v2_fl(range_xy[1], imy);
+ }
+
+ if (sima->flag & SI_COORDFLOATS) {
+ step = 1;
+ digits = 3;
+ }
+ else {
+ step = 100;
+ digits = 2;
+ }
+
+ UI_block_align_begin(block);
+ uiDefButF(block,
+ UI_BTYPE_NUM,
+ B_UVEDIT_VERTEX,
+ IFACE_("X:"),
+ 0,
+ 0,
+ width,
+ UI_UNIT_Y,
+ &uvedit_old_center[0],
+ UNPACK2(range_xy[0]),
+ step,
+ digits,
+ "");
+ uiDefButF(block,
+ UI_BTYPE_NUM,
+ B_UVEDIT_VERTEX,
+ IFACE_("Y:"),
+ width,
+ 0,
+ width,
+ UI_UNIT_Y,
+ &uvedit_old_center[1],
+ UNPACK2(range_xy[1]),
+ step,
+ digits,
+ "");
+ UI_block_align_end(block);
+ }
}
static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Image *ima = sima->image;
- BMEditMesh *em;
- float center[2], delta[2];
- int imx, imy;
-
- if (event != B_UVEDIT_VERTEX)
- return;
-
- em = BKE_editmesh_from_object(obedit);
-
- ED_space_image_get_size(sima, &imx, &imy);
- uvedit_center(scene, obedit, em, ima, center);
-
- if (sima->flag & SI_COORDFLOATS) {
- delta[0] = uvedit_old_center[0] - center[0];
- delta[1] = uvedit_old_center[1] - center[1];
- }
- else {
- delta[0] = uvedit_old_center[0] / imx - center[0];
- delta[1] = uvedit_old_center[1] / imy - center[1];
- }
-
- uvedit_translate(scene, obedit, em, ima, delta);
-
- WM_event_add_notifier(C, NC_IMAGE, sima->image);
- DEG_id_tag_update((ID *)obedit->data, ID_RECALC_GEOMETRY);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Image *ima = sima->image;
+ BMEditMesh *em;
+ float center[2], delta[2];
+ int imx, imy;
+
+ if (event != B_UVEDIT_VERTEX)
+ return;
+
+ em = BKE_editmesh_from_object(obedit);
+
+ ED_space_image_get_size(sima, &imx, &imy);
+ uvedit_center(scene, obedit, em, ima, center);
+
+ if (sima->flag & SI_COORDFLOATS) {
+ delta[0] = uvedit_old_center[0] - center[0];
+ delta[1] = uvedit_old_center[1] - center[1];
+ }
+ else {
+ delta[0] = uvedit_old_center[0] / imx - center[0];
+ delta[1] = uvedit_old_center[1] / imy - center[1];
+ }
+
+ uvedit_translate(scene, obedit, em, ima, delta);
+
+ WM_event_add_notifier(C, NC_IMAGE, sima->image);
+ DEG_id_tag_update((ID *)obedit->data, ID_RECALC_GEOMETRY);
}
/* Panels */
static bool image_panel_uv_poll(const bContext *C, PanelType *UNUSED(pt))
{
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima->mode != SI_MODE_UV) {
- return false;
- }
- Object *obedit = CTX_data_edit_object(C);
- return ED_uvedit_test(obedit);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima->mode != SI_MODE_UV) {
+ return false;
+ }
+ Object *obedit = CTX_data_edit_object(C);
+ return ED_uvedit_test(obedit);
}
static void image_panel_uv(const bContext *C, Panel *pa)
{
- uiBlock *block;
+ uiBlock *block;
- block = uiLayoutAbsoluteBlock(pa->layout);
- UI_block_func_handle_set(block, do_uvedit_vertex, NULL);
+ block = uiLayoutAbsoluteBlock(pa->layout);
+ UI_block_func_handle_set(block, do_uvedit_vertex, NULL);
- uvedit_vertex_buttons(C, block);
+ uvedit_vertex_buttons(C, block);
}
void ED_uvedit_buttons_register(ARegionType *art)
{
- PanelType *pt;
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype image panel uv");
- strcpy(pt->idname, "IMAGE_PT_uv");
- strcpy(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */
- pt->draw = image_panel_uv;
- pt->poll = image_panel_uv_poll;
- BLI_addtail(&art->paneltypes, pt);
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype image panel uv");
+ strcpy(pt->idname, "IMAGE_PT_uv");
+ strcpy(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */
+ pt->draw = image_panel_uv;
+ pt->poll = image_panel_uv_poll;
+ BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 8bc2be11934..5ff90097840 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -21,7 +21,6 @@
* \ingroup eduv
*/
-
#include <float.h>
#include <math.h>
#include <stdlib.h>
@@ -71,434 +70,442 @@
static int draw_uvs_face_check(const ToolSettings *ts)
{
- /* checks if we are selecting only faces */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode == SCE_SELECT_FACE)
- return 2;
- else if (ts->selectmode & SCE_SELECT_FACE)
- return 1;
- else
- return 0;
- }
- else
- return (ts->uv_selectmode == UV_SELECT_FACE);
+ /* checks if we are selecting only faces */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode == SCE_SELECT_FACE)
+ return 2;
+ else if (ts->selectmode & SCE_SELECT_FACE)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return (ts->uv_selectmode == UV_SELECT_FACE);
}
/* ------------------------- */
void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
{
- float zoom[2], x_fac, y_fac;
+ float zoom[2], x_fac, y_fac;
- UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]);
+ UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]);
- mul_v2_fl(zoom, 256.0f * UI_DPI_FAC);
- x_fac = zoom[0];
- y_fac = zoom[1];
+ mul_v2_fl(zoom, 256.0f * UI_DPI_FAC);
+ x_fac = zoom[0];
+ y_fac = zoom[1];
- GPU_line_width(1.0f);
+ GPU_line_width(1.0f);
- GPU_matrix_translate_2fv(cursor);
+ GPU_matrix_translate_2fv(cursor);
- const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- immUniform1i("colors_len", 2); /* "advanced" mode */
- immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
- immUniform1f("dash_width", 8.0f);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv(
+ "colors", (float *)(float[][4]){{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
- immBegin(GPU_PRIM_LINES, 8);
+ immBegin(GPU_PRIM_LINES, 8);
- immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
- immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
- immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
- immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
- immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
- immEnd();
+ immEnd();
- immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
- immUniform1f("dash_width", 2.0f);
+ immUniformArray4fv(
+ "colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 2.0f);
- immBegin(GPU_PRIM_LINES, 8);
+ immBegin(GPU_PRIM_LINES, 8);
- immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f);
- immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f);
- immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac);
- immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac);
- immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac);
- immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac);
- immEnd();
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_matrix_translate_2f(-cursor[0], -cursor[1]);
+ GPU_matrix_translate_2f(-cursor[0], -cursor[1]);
}
-static void uvedit_get_batches(
- Object *ob, SpaceImage *sima, const ToolSettings *ts,
- GPUBatch **faces, GPUBatch **edges, GPUBatch **verts, GPUBatch **facedots)
+static void uvedit_get_batches(Object *ob,
+ SpaceImage *sima,
+ const ToolSettings *ts,
+ GPUBatch **faces,
+ GPUBatch **edges,
+ GPUBatch **verts,
+ GPUBatch **facedots)
{
- int drawfaces = draw_uvs_face_check(ts);
- const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
- const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
-
- *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
- *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
-
- if (drawfaces) {
- *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
- }
- else {
- *facedots = NULL;
- }
-
- if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
- }
- else if (draw_stretch) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
- }
- else if (draw_faces) {
- *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
- }
- else {
- *faces = NULL;
- }
-
- DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
+ int drawfaces = draw_uvs_face_check(ts);
+ const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
+ const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
+
+ *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+ *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+
+ if (drawfaces) {
+ *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+ }
+ else {
+ *facedots = NULL;
+ }
+
+ if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
+ *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data);
+ }
+ else if (draw_stretch) {
+ *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data);
+ }
+ else if (draw_faces) {
+ *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+ }
+ else {
+ *faces = NULL;
+ }
+
+ DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false);
}
-static void draw_uvs_shadow(SpaceImage *UNUSED(sima), Scene *scene, Object *obedit, Depsgraph *depsgraph)
+static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
+ Scene *scene,
+ Object *obedit,
+ Depsgraph *depsgraph)
{
- Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
- Mesh *me = eval_ob->data;
- float col[4];
- UI_GetThemeColor4fv(TH_UV_SHADOW, col);
-
- GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
-
- if (edges) {
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
- GPU_batch_uniform_4fv(edges, "color", col);
- GPU_batch_draw(edges);
- }
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
+ Mesh *me = eval_ob->data;
+ float col[4];
+ UI_GetThemeColor4fv(TH_UV_SHADOW, col);
+
+ GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+
+ if (edges) {
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(edges, "color", col);
+ GPU_batch_draw(edges);
+ }
}
static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
{
- Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *me = eval_ob->data;
- ToolSettings *ts = scene->toolsettings;
- float col[4];
- UI_GetThemeColor4fv(TH_UV_SHADOW, col);
-
- if (me->mloopuv == NULL) {
- return;
- }
-
- GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
-
- GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
- GPU_batch_uniform_4fv(geom, "color", col);
-
- const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE);
- if (do_material_masking && me->mloopuv) {
- /* Render loops that have the active material. Minize draw calls. */
- MPoly *mpoly = me->mpoly;
- uint draw_start = 0;
- uint idx = 0;
- bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
-
- GPU_matrix_bind(geom->interface);
-
- /* TODO(fclem): If drawcall count becomes a problem in the future
- * we can use multi draw indirect drawcalls for this.
- * (not implemented in GPU module at the time of writing). */
- for (int a = 0; a < me->totpoly; a++, mpoly++) {
- bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
- if (ma_match != prev_ma_match) {
- if (ma_match == false) {
- GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
- }
- else {
- draw_start = idx;
- }
- }
- idx += mpoly->totloop + 1;
- prev_ma_match = ma_match;
- }
- if (prev_ma_match == true) {
- GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
- }
-
- GPU_batch_program_use_end(geom);
- }
- else {
- GPU_batch_draw(geom);
- }
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me = eval_ob->data;
+ ToolSettings *ts = scene->toolsettings;
+ float col[4];
+ UI_GetThemeColor4fv(TH_UV_SHADOW, col);
+
+ if (me->mloopuv == NULL) {
+ return;
+ }
+
+ GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
+ DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false);
+
+ GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(geom, "color", col);
+
+ const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE);
+ if (do_material_masking && me->mloopuv) {
+ /* Render loops that have the active material. Minize draw calls. */
+ MPoly *mpoly = me->mpoly;
+ uint draw_start = 0;
+ uint idx = 0;
+ bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
+
+ GPU_matrix_bind(geom->interface);
+
+ /* TODO(fclem): If drawcall count becomes a problem in the future
+ * we can use multi draw indirect drawcalls for this.
+ * (not implemented in GPU module at the time of writing). */
+ for (int a = 0; a < me->totpoly; a++, mpoly++) {
+ bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
+ if (ma_match != prev_ma_match) {
+ if (ma_match == false) {
+ GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
+ }
+ else {
+ draw_start = idx;
+ }
+ }
+ idx += mpoly->totloop + 1;
+ prev_ma_match = ma_match;
+ }
+ if (prev_ma_match == true) {
+ GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
+ }
+
+ GPU_batch_program_use_end(geom);
+ }
+ else {
+ GPU_batch_draw(geom);
+ }
}
/* draws uv's in the image space */
static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
{
- GPUBatch *faces, *edges, *verts, *facedots;
- Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
- const ToolSettings *ts = scene->toolsettings;
- float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- if (sima->flag & SI_DRAWSHADOW) {
- bool is_cage_like_final_meshes = false;
- Mesh *me = (Mesh *)eval_ob->data;
- BMEditMesh *embm = me->edit_mesh;
- is_cage_like_final_meshes = embm &&
- embm->mesh_eval_final &&
- embm->mesh_eval_final->runtime.is_original;
-
- /* When sync selection is enabled, all faces are drawn (except for hidden)
- * so if cage is the same as the final, there is no point in drawing this. */
- if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
- draw_uvs_shadow(sima, scene, obedit, depsgraph);
- }
- }
-
- uvedit_get_batches(
- eval_ob, sima, ts,
- &faces, &edges, &verts, &facedots);
-
-
- bool interpedges;
- bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
- bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0);
- bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0;
- }
- else {
- interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX);
- }
-
- GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
-
- if (faces) {
- GPU_batch_program_set_builtin(faces, (draw_stretch)
- ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)
- ? GPU_SHADER_2D_UV_FACES_STRETCH_AREA
- : GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE
- : GPU_SHADER_2D_UV_FACES);
-
- if (!draw_stretch) {
- GPU_blend(true);
-
- UI_GetThemeColor4fv(TH_FACE, col1);
- UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
- UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
- col3[3] *= 0.2; /* Simulate dithering */
- GPU_batch_uniform_4fv(faces, "faceColor", col1);
- GPU_batch_uniform_4fv(faces, "selectColor", col2);
- GPU_batch_uniform_4fv(faces, "activeColor", col3);
- }
- else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
- float asp[2];
- ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
- GPU_batch_uniform_2fv(faces, "aspect", asp);
- }
-
- GPU_batch_draw(faces);
-
- if (!draw_stretch) {
- GPU_blend(false);
- }
- }
- if (edges) {
- if (sima->flag & SI_SMOOTH_UV) {
- GPU_line_smooth(true);
- GPU_blend(true);
- }
- switch (sima->dt_uv) {
- case SI_UVDT_DASH:
- {
- float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
-
- GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
- GPU_batch_uniform_2f(edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
- GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
- GPU_batch_draw(edges);
- break;
- }
- case SI_UVDT_BLACK:
- case SI_UVDT_WHITE:
- {
- GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
- if (sima->dt_uv == SI_UVDT_WHITE) {
- GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f);
- }
- else {
- GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
- }
- GPU_batch_draw(edges);
- break;
- }
- case SI_UVDT_OUTLINE:
- {
- GPU_line_width(3.0f);
- GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_draw(edges);
-
- UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
-
- /* We could modify the vbo's data filling
- * instead of modifying the provoking vert. */
- glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
-
- GPU_line_width(1.0f);
- GPU_batch_program_set_builtin(edges, (interpedges)
- ? GPU_SHADER_2D_UV_EDGES_SMOOTH
- : GPU_SHADER_2D_UV_EDGES);
- GPU_batch_uniform_4fv(edges, "edgeColor", col1);
- GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1);
- GPU_batch_draw(edges);
-
- if (do_elem_order_fix && do_selected_edges) {
- /* We have problem in this mode when face order make some edges
- * appear unselected because an adjacent face is not selected and
- * render after the selected face.
- * So, to avoid sorting edges by state we just render selected edges
- * on top. A bit overkill but it's simple. */
- GPU_blend(true);
- GPU_batch_uniform_4fv(edges, "edgeColor", transparent);
- GPU_batch_uniform_4fv(edges, "selectColor", col2);
- GPU_batch_draw(edges);
- GPU_blend(false);
- }
- glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
- break;
- }
- }
- if (sima->flag & SI_SMOOTH_UV) {
- GPU_line_smooth(false);
- GPU_blend(false);
- }
- }
- if (verts || facedots) {
- float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
- UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
- if (verts) {
- float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
- UI_GetThemeColor4fv(TH_VERTEX, col1);
- GPU_blend(true);
- GPU_enable_program_point_size();
-
- GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
- GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
- GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2);
- GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
- GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
- GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
- GPU_batch_draw(verts);
-
- if (do_elem_order_fix) {
- /* We have problem in this mode when face order make some verts
- * appear unselected because an adjacent face is not selected and
- * render after the selected face.
- * So, to avoid sorting verts by state we just render selected verts
- * on top. A bit overkill but it's simple. */
- GPU_batch_uniform_4fv(verts, "vertColor", transparent);
- GPU_batch_uniform_4fv(verts, "selectColor", col2);
- GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
- GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
- GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
- GPU_batch_draw(verts);
- }
-
- GPU_blend(false);
- GPU_disable_program_point_size();
- }
- if (facedots) {
- GPU_point_size(pointsize);
-
- UI_GetThemeColor4fv(TH_WIRE, col1);
- GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
- GPU_batch_uniform_4fv(facedots, "vertColor", col1);
- GPU_batch_uniform_4fv(facedots, "selectColor", col2);
- GPU_batch_draw(facedots);
- }
- }
+ GPUBatch *faces, *edges, *verts, *facedots;
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
+ const ToolSettings *ts = scene->toolsettings;
+ float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if (sima->flag & SI_DRAWSHADOW) {
+ bool is_cage_like_final_meshes = false;
+ Mesh *me = (Mesh *)eval_ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ is_cage_like_final_meshes = embm && embm->mesh_eval_final &&
+ embm->mesh_eval_final->runtime.is_original;
+
+ /* When sync selection is enabled, all faces are drawn (except for hidden)
+ * so if cage is the same as the final, there is no point in drawing this. */
+ if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
+ draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ }
+ }
+
+ uvedit_get_batches(eval_ob, sima, ts, &faces, &edges, &verts, &facedots);
+
+ bool interpedges;
+ bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+ bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0);
+ bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0;
+ }
+ else {
+ interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX);
+ }
+
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ if (faces) {
+ GPU_batch_program_set_builtin(faces,
+ (draw_stretch) ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) ?
+ GPU_SHADER_2D_UV_FACES_STRETCH_AREA :
+ GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE :
+ GPU_SHADER_2D_UV_FACES);
+
+ if (!draw_stretch) {
+ GPU_blend(true);
+
+ UI_GetThemeColor4fv(TH_FACE, col1);
+ UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
+ UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
+ col3[3] *= 0.2; /* Simulate dithering */
+ GPU_batch_uniform_4fv(faces, "faceColor", col1);
+ GPU_batch_uniform_4fv(faces, "selectColor", col2);
+ GPU_batch_uniform_4fv(faces, "activeColor", col3);
+ }
+ else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) {
+ float asp[2];
+ ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
+ GPU_batch_uniform_2fv(faces, "aspect", asp);
+ }
+
+ GPU_batch_draw(faces);
+
+ if (!draw_stretch) {
+ GPU_blend(false);
+ }
+ }
+ if (edges) {
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ }
+ switch (sima->dt_uv) {
+ case SI_UVDT_DASH: {
+ float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
+ GPU_batch_uniform_2f(
+ edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
+ GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
+ GPU_batch_draw(edges);
+ break;
+ }
+ case SI_UVDT_BLACK:
+ case SI_UVDT_WHITE: {
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
+ if (sima->dt_uv == SI_UVDT_WHITE) {
+ GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ else {
+ GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+ GPU_batch_draw(edges);
+ break;
+ }
+ case SI_UVDT_OUTLINE: {
+ GPU_line_width(3.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_draw(edges);
+
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
+
+ /* We could modify the vbo's data filling
+ * instead of modifying the provoking vert. */
+ glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
+
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(
+ edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
+ GPU_batch_uniform_4fv(edges, "edgeColor", col1);
+ GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1);
+ GPU_batch_draw(edges);
+
+ if (do_elem_order_fix && do_selected_edges) {
+ /* We have problem in this mode when face order make some edges
+ * appear unselected because an adjacent face is not selected and
+ * render after the selected face.
+ * So, to avoid sorting edges by state we just render selected edges
+ * on top. A bit overkill but it's simple. */
+ GPU_blend(true);
+ GPU_batch_uniform_4fv(edges, "edgeColor", transparent);
+ GPU_batch_uniform_4fv(edges, "selectColor", col2);
+ GPU_batch_draw(edges);
+ GPU_blend(false);
+ }
+ glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
+ break;
+ }
+ }
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+ }
+ if (verts || facedots) {
+ float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
+ if (verts) {
+ float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
+ UI_GetThemeColor4fv(TH_VERTEX, col1);
+ GPU_blend(true);
+ GPU_enable_program_point_size();
+
+ GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
+ GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
+ GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2);
+ GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(verts);
+
+ if (do_elem_order_fix) {
+ /* We have problem in this mode when face order make some verts
+ * appear unselected because an adjacent face is not selected and
+ * render after the selected face.
+ * So, to avoid sorting verts by state we just render selected verts
+ * on top. A bit overkill but it's simple. */
+ GPU_batch_uniform_4fv(verts, "vertColor", transparent);
+ GPU_batch_uniform_4fv(verts, "selectColor", col2);
+ GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(verts);
+ }
+
+ GPU_blend(false);
+ GPU_disable_program_point_size();
+ }
+ if (facedots) {
+ GPU_point_size(pointsize);
+
+ UI_GetThemeColor4fv(TH_WIRE, col1);
+ GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
+ GPU_batch_uniform_4fv(facedots, "vertColor", col1);
+ GPU_batch_uniform_4fv(facedots, "selectColor", col2);
+ GPU_batch_draw(facedots);
+ }
+ }
}
static void draw_uv_shadows_get(
- SpaceImage *sima, Object *ob, Object *obedit,
- bool *show_shadow, bool *show_texpaint)
+ SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint)
{
- *show_shadow = *show_texpaint = false;
+ *show_shadow = *show_texpaint = false;
- if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT))
- return;
+ if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT))
+ return;
- if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
- struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
+ struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- *show_shadow = EDBM_uv_check(em);
- }
+ *show_shadow = EDBM_uv_check(em);
+ }
- *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
+ *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
}
-void ED_uvedit_draw_main(
- SpaceImage *sima,
- ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph)
+void ED_uvedit_draw_main(SpaceImage *sima,
+ ARegion *ar,
+ Scene *scene,
+ ViewLayer *view_layer,
+ Object *obedit,
+ Object *obact,
+ Depsgraph *depsgraph)
{
- ToolSettings *toolsettings = scene->toolsettings;
- bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
-
- show_uvedit = ED_space_image_show_uvedit(sima, obedit);
- draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
-
- if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
- if (show_uvshadow) {
- draw_uvs_shadow(sima, scene, obedit, depsgraph);
- }
- else if (show_uvedit) {
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob_iter = objects[ob_index];
- draw_uvs(sima, scene, ob_iter, depsgraph);
- }
- MEM_freeN(objects);
- }
- else {
- draw_uvs_texpaint(scene, obact, depsgraph);
- }
-
- if (show_uvedit && !(toolsettings->use_uv_sculpt))
- ED_image_draw_cursor(ar, sima->cursor);
- }
+ ToolSettings *toolsettings = scene->toolsettings;
+ bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
+
+ show_uvedit = ED_space_image_show_uvedit(sima, obedit);
+ draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
+
+ if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
+ if (show_uvshadow) {
+ draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ }
+ else if (show_uvedit) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ draw_uvs(sima, scene, ob_iter, depsgraph);
+ }
+ MEM_freeN(objects);
+ }
+ else {
+ draw_uvs_texpaint(scene, obact, depsgraph);
+ }
+
+ if (show_uvedit && !(toolsettings->use_uv_sculpt))
+ ED_image_draw_cursor(ar, sima->cursor);
+ }
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 5510549ba0e..3f544ad90d1 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -21,7 +21,6 @@
* \ingroup eduv
*/
-
#ifndef __UVEDIT_INTERN_H__
#define __UVEDIT_INTERN_H__
@@ -35,50 +34,72 @@ struct SpaceImage;
struct wmOperatorType;
/* geometric utilities */
-void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
-void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset);
+void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
+void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset);
/* find nearest */
typedef struct UvNearestHit {
- /** Only for `*_multi(..)` versions of functions. */
- struct Object *ob;
- /** Always set if we have a hit. */
- struct BMFace *efa;
- struct BMLoop *l;
- struct MLoopUV *luv, *luv_next;
- /** Index of loop within face. */
- int lindex;
- /** Needs to be set before calling nearest functions. */
- float dist_sq;
+ /** Only for `*_multi(..)` versions of functions. */
+ struct Object *ob;
+ /** Always set if we have a hit. */
+ struct BMFace *efa;
+ struct BMLoop *l;
+ struct MLoopUV *luv, *luv_next;
+ /** Index of loop within face. */
+ int lindex;
+ /** Needs to be set before calling nearest functions. */
+ float dist_sq;
} UvNearestHit;
-#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, }
-
-bool uv_find_nearest_vert(
- struct Scene *scene, struct Image *ima, struct Object *obedit,
- const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
-bool uv_find_nearest_vert_multi(
- struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
- const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
-
-bool uv_find_nearest_edge(
- struct Scene *scene, struct Image *ima, struct Object *obedit,
- const float co[2], struct UvNearestHit *hit_final);
-bool uv_find_nearest_edge_multi(
- struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
- const float co[2], struct UvNearestHit *hit_final);
-
-bool uv_find_nearest_face(
- struct Scene *scene, struct Image *ima, struct Object *obedit,
- const float co[2], struct UvNearestHit *hit_final);
-bool uv_find_nearest_face_multi(
- struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
- const float co[2], struct UvNearestHit *hit_final);
+#define UV_NEAREST_HIT_INIT \
+ { \
+ .dist_sq = FLT_MAX, \
+ }
+
+bool uv_find_nearest_vert(struct Scene *scene,
+ struct Image *ima,
+ struct Object *obedit,
+ const float co[2],
+ const float penalty_dist,
+ struct UvNearestHit *hit_final);
+bool uv_find_nearest_vert_multi(struct Scene *scene,
+ struct Image *ima,
+ struct Object **objects,
+ const uint objects_len,
+ const float co[2],
+ const float penalty_dist,
+ struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_edge(struct Scene *scene,
+ struct Image *ima,
+ struct Object *obedit,
+ const float co[2],
+ struct UvNearestHit *hit_final);
+bool uv_find_nearest_edge_multi(struct Scene *scene,
+ struct Image *ima,
+ struct Object **objects,
+ const uint objects_len,
+ const float co[2],
+ struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_face(struct Scene *scene,
+ struct Image *ima,
+ struct Object *obedit,
+ const float co[2],
+ struct UvNearestHit *hit_final);
+bool uv_find_nearest_face_multi(struct Scene *scene,
+ struct Image *ima,
+ struct Object **objects,
+ const uint objects_len,
+ const float co[2],
+ struct UvNearestHit *hit_final);
/* utility tool functions */
-void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
+void uvedit_live_unwrap_update(struct SpaceImage *sima,
+ struct Scene *scene,
+ struct Object *obedit);
/* operators */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 1bcf60077ff..291dbdf6942 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -21,7 +21,6 @@
* \ingroup eduv
*/
-
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -87,12 +86,24 @@
#include "uvedit_intern.h"
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
-static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len);
+static bool uv_select_is_any_selected_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len);
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
-static void uv_select_all_perform_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
-static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
-static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit);
+static void uv_select_all_perform_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit);
/* -------------------------------------------------------------------- */
/** \name State Testing
@@ -100,42 +111,42 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSett
bool ED_uvedit_test(Object *obedit)
{
- BMEditMesh *em;
- int ret;
+ BMEditMesh *em;
+ int ret;
- if (!obedit)
- return 0;
+ if (!obedit)
+ return 0;
- if (obedit->type != OB_MESH)
- return 0;
+ if (obedit->type != OB_MESH)
+ return 0;
- em = BKE_editmesh_from_object(obedit);
- ret = EDBM_uv_check(em);
+ em = BKE_editmesh_from_object(obedit);
+ ret = EDBM_uv_check(em);
- return ret;
+ return ret;
}
static bool ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- Object *obedit = CTX_data_edit_object(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ Object *obedit = CTX_data_edit_object(C);
- return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
+ return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
}
-static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
+static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if (ob && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ if (ob && ob->type == OB_MESH) {
+ Mesh *me = ob->data;
- if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
- return 1;
- }
+ if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
+ return 1;
+ }
- return 0;
+ return 0;
}
/** \} */
@@ -146,52 +157,62 @@ static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
static bool is_image_texture_node(bNode *node)
{
- return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
-}
-
-bool ED_object_get_active_image(
- Object *ob, int mat_nr,
- Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
-{
- Material *ma = give_current_material(ob, mat_nr);
- bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
- bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
-
- if (node && is_image_texture_node(node)) {
- if (r_ima) *r_ima = (Image *)node->id;
- if (r_iuser) {
- if (node->type == SH_NODE_TEX_IMAGE) {
- *r_iuser = &((NodeTexImage *)node->storage)->iuser;
- }
- else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
- *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser;
- }
- else {
- *r_iuser = NULL;
- }
- }
- if (r_node) *r_node = node;
- if (r_ntree) *r_ntree = ntree;
- return true;
- }
-
- if (r_ima) *r_ima = NULL;
- if (r_iuser) *r_iuser = NULL;
- if (r_node) *r_node = node;
- if (r_ntree) *r_ntree = ntree;
-
- return false;
+ return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
+}
+
+bool ED_object_get_active_image(Object *ob,
+ int mat_nr,
+ Image **r_ima,
+ ImageUser **r_iuser,
+ bNode **r_node,
+ bNodeTree **r_ntree)
+{
+ Material *ma = give_current_material(ob, mat_nr);
+ bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
+ bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
+
+ if (node && is_image_texture_node(node)) {
+ if (r_ima)
+ *r_ima = (Image *)node->id;
+ if (r_iuser) {
+ if (node->type == SH_NODE_TEX_IMAGE) {
+ *r_iuser = &((NodeTexImage *)node->storage)->iuser;
+ }
+ else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
+ *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser;
+ }
+ else {
+ *r_iuser = NULL;
+ }
+ }
+ if (r_node)
+ *r_node = node;
+ if (r_ntree)
+ *r_ntree = ntree;
+ return true;
+ }
+
+ if (r_ima)
+ *r_ima = NULL;
+ if (r_iuser)
+ *r_iuser = NULL;
+ if (r_node)
+ *r_node = node;
+ if (r_ntree)
+ *r_ntree = ntree;
+
+ return false;
}
void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
{
- Material *ma = give_current_material(ob, mat_nr);
- bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
+ Material *ma = give_current_material(ob, mat_nr);
+ bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
- if (node && is_image_texture_node(node)) {
- node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
- }
+ if (node && is_image_texture_node(node)) {
+ node->id = &ima->id;
+ ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
+ }
}
/** \} */
@@ -202,18 +223,18 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
{
- int width, height;
+ int width, height;
- if (sima) {
- ED_space_image_get_size(sima, &width, &height);
- }
- else {
- width = IMG_SIZE_FALLBACK;
- height = IMG_SIZE_FALLBACK;
- }
+ if (sima) {
+ ED_space_image_get_size(sima, &width, &height);
+ }
+ else {
+ width = IMG_SIZE_FALLBACK;
+ height = IMG_SIZE_FALLBACK;
+ }
- dist[0] = pixeldist / width;
- dist[1] = pixeldist / height;
+ dist[0] = pixeldist / width;
+ dist[1] = pixeldist / height;
}
/** \} */
@@ -222,313 +243,316 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
/** \name Visibility and Selection Utilities
* \{ */
-static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset)
+static void uvedit_vertex_select_tagged(BMEditMesh *em,
+ Scene *scene,
+ bool select,
+ int cd_loop_uv_offset)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
}
bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
{
- if (ts->uv_flag & UV_SYNC_SELECTION)
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
- else
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ if (ts->uv_flag & UV_SYNC_SELECTION)
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
+ else
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
}
bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
{
- return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
+ return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
}
bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
{
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
- Image *face_image;
- ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
- return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
- }
- else {
- return uvedit_face_visible_nolocal_ex(ts, efa);
- }
+ if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
+ Image *face_image;
+ ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
+ return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
+ }
+ else {
+ return uvedit_face_visible_nolocal_ex(ts, efa);
+ }
}
bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa)
{
- return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
+ return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
}
-bool uvedit_face_select_test_ex(
- const ToolSettings *ts, BMFace *efa,
- const int cd_loop_uv_offset)
+bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!(luv->flag & MLOOPUV_VERTSEL))
- return false;
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (!(luv->flag & MLOOPUV_VERTSEL))
+ return false;
+ }
- return true;
- }
+ return true;
+ }
}
bool uvedit_face_select_test(Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
{
- return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
+ return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
}
-bool uvedit_face_select_set(
- struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+bool uvedit_face_select_set(struct Scene *scene,
+ struct BMEditMesh *em,
+ struct BMFace *efa,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- if (select) {
- return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
- }
- else {
- return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
+ if (select) {
+ return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
+ }
+ else {
+ return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
}
bool uvedit_face_select_enable(
- Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
- const int cd_loop_uv_offset)
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, true);
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)efa);
- }
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_face_select_disable(
- Scene *scene, BMEditMesh *em, BMFace *efa,
- const int cd_loop_uv_offset)
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, false);
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_edge_select_test_ex(
- const ToolSettings *ts, BMLoop *l,
- const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
- }
- else if (ts->selectmode == SCE_SELECT_EDGE) {
- return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
- BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
- }
+ Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int cd_loop_uv_offset)
+{
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, true);
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)efa);
+ }
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_face_select_disable(Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
+ }
+ else if (ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
+ }
}
bool uvedit_edge_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
- return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+ return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
}
-void uvedit_edge_select_set(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+void uvedit_edge_select_set(BMEditMesh *em,
+ Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- if (select) {
- uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
- }
+ if (select) {
+ uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
}
void uvedit_edge_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE)
- BM_face_select_set(em->bm, l->f, true);
- else if (ts->selectmode & SCE_SELECT_EDGE)
- BM_edge_select_set(em->bm, l->e, true);
- else {
- BM_vert_select_set(em->bm, l->e->v1, true);
- BM_vert_select_set(em->bm, l->e->v2, true);
- }
-
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->e);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag |= MLOOPUV_VERTSEL;
- luv2->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_edge_select_disable(
- BMEditMesh *em, Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
-
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE)
- BM_face_select_set(em->bm, l->f, false);
- else if (ts->selectmode & SCE_SELECT_EDGE)
- BM_edge_select_set(em->bm, l->e, false);
- else {
- BM_vert_select_set(em->bm, l->e->v1, false);
- BM_vert_select_set(em->bm, l->e->v2, false);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag &= ~MLOOPUV_VERTSEL;
- luv2->flag &= ~MLOOPUV_VERTSEL;
- }
-}
-
-bool uvedit_uv_select_test_ex(
- const ToolSettings *ts, BMLoop *l,
- const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE)
- return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
- else
- return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return (luv->flag & MLOOPUV_VERTSEL) != 0;
- }
+ BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
+
+{
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE)
+ BM_face_select_set(em->bm, l->f, true);
+ else if (ts->selectmode & SCE_SELECT_EDGE)
+ BM_edge_select_set(em->bm, l->e, true);
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, true);
+ BM_vert_select_set(em->bm, l->e->v2, true);
+ }
+
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)l->e);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag |= MLOOPUV_VERTSEL;
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_edge_select_disable(BMEditMesh *em,
+ Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
+
+{
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE)
+ BM_face_select_set(em->bm, l->f, false);
+ else if (ts->selectmode & SCE_SELECT_EDGE)
+ BM_edge_select_set(em->bm, l->e, false);
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, false);
+ BM_vert_select_set(em->bm, l->e->v2, false);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag &= ~MLOOPUV_VERTSEL;
+ luv2->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE)
+ return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
+ else
+ return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return (luv->flag & MLOOPUV_VERTSEL) != 0;
+ }
}
bool uvedit_uv_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
- return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+ return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
}
-void uvedit_uv_select_set(
- BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
- const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_set(BMEditMesh *em,
+ Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
{
- if (select) {
- uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
- }
+ if (select) {
+ uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
}
void uvedit_uv_select_enable(
- BMEditMesh *em, Scene *scene, BMLoop *l,
- const bool do_history, const int cd_loop_uv_offset)
+ BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = scene->toolsettings;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE)
- BM_face_select_set(em->bm, l->f, true);
- else
- BM_vert_select_set(em->bm, l->v, true);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE)
+ BM_face_select_set(em->bm, l->f, true);
+ else
+ BM_vert_select_set(em->bm, l->v, true);
- if (do_history) {
- BM_select_history_remove(em->bm, (BMElem *)l->v);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
+ if (do_history) {
+ BM_select_history_remove(em->bm, (BMElem *)l->v);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
-void uvedit_uv_select_disable(
- BMEditMesh *em, Scene *scene, BMLoop *l,
- const int cd_loop_uv_offset)
+void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
- ToolSettings *ts = scene->toolsettings;
+ ToolSettings *ts = scene->toolsettings;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE)
- BM_face_select_set(em->bm, l->f, false);
- else
- BM_vert_select_set(em->bm, l->v, false);
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE)
+ BM_face_select_set(em->bm, l->f, false);
+ else
+ BM_vert_select_set(em->bm, l->v, false);
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
/** \} */
@@ -539,11 +563,11 @@ void uvedit_uv_select_disable(
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
{
- if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
- ED_uvedit_live_unwrap_begin(scene, obedit);
- ED_uvedit_live_unwrap_re_solve();
- ED_uvedit_live_unwrap_end(0);
- }
+ if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
+ ED_uvedit_live_unwrap_begin(scene, obedit);
+ ED_uvedit_live_unwrap_re_solve();
+ ED_uvedit_live_unwrap_end(0);
+ }
}
/** \} */
@@ -554,149 +578,157 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
{
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
- zero_v2(r_cent);
+ zero_v2(r_cent);
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(r_cent, luv->uv);
- }
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(r_cent, luv->uv);
+ }
- mul_v2_fl(r_cent, 1.0f / (float)f->len);
+ mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
{
- int i;
- for (i = 0; i < len; i++) {
- uv[i][0] = uv_orig[i][0] * aspx;
- uv[i][1] = uv_orig[i][1] * aspy;
- }
+ int i;
+ for (i = 0; i < len; i++) {
+ uv[i][0] = uv_orig[i][0] * aspx;
+ uv[i][1] = uv_orig[i][1] * aspy;
+ }
}
-bool ED_uvedit_minmax_multi(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len,
- float r_min[2], float r_max[2])
+bool ED_uvedit_minmax_multi(Scene *scene,
+ Image *ima,
+ Object **objects_edit,
+ uint objects_len,
+ float r_min[2],
+ float r_max[2])
{
- bool changed = false;
- INIT_MINMAX2(r_min, r_max);
+ bool changed = false;
+ INIT_MINMAX2(r_min, r_max);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects_edit[ob_index];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects_edit[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(r_min, r_max, luv->uv);
- changed = true;
- }
- }
- }
- }
- return changed;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(r_min, r_max, luv->uv);
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
}
bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
{
- return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
+ return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
}
/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
- }
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
}
-static bool ED_uvedit_median_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+static bool ED_uvedit_median_multi(
+ Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
{
- unsigned int sel = 0;
- zero_v2(co);
+ unsigned int sel = 0;
+ zero_v2(co);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects_edit[ob_index];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects_edit[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- add_v2_v2(co, luv->uv);
- sel++;
- }
- }
- }
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ add_v2_v2(co, luv->uv);
+ sel++;
+ }
+ }
+ }
+ }
- mul_v2_fl(co, 1.0f / (float)sel);
+ mul_v2_fl(co, 1.0f / (float)sel);
- return (sel != 0);
+ return (sel != 0);
}
-static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene, Image *ima, Object *obedit, float co[2])
+static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene,
+ Image *ima,
+ Object *obedit,
+ float co[2])
{
- return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
+ return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
}
-bool ED_uvedit_center_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
+bool ED_uvedit_center_multi(
+ Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
{
- bool changed = false;
+ bool changed = false;
- if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
- float min[2], max[2];
- if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
- mid_v2_v2v2(cent, min, max);
- changed = true;
- }
- }
- else {
- if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
- changed = true;
- }
- }
+ if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
+ float min[2], max[2];
+ if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
+ mid_v2_v2v2(cent, min, max);
+ changed = true;
+ }
+ }
+ else {
+ if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
+ changed = true;
+ }
+ }
- return changed;
+ return changed;
}
bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
{
- return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
+ return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
}
/** \} */
@@ -706,264 +738,278 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c
* \{ */
bool uv_find_nearest_edge(
- Scene *scene, Image *ima, Object *obedit, const float co[2],
- UvNearestHit *hit)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv, *luv_next;
- int i;
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
-
- if (dist_test_sq < hit->dist_sq) {
- hit->efa = efa;
-
- hit->l = l;
- hit->luv = luv;
- hit->luv_next = luv_next;
- hit->lindex = i;
-
- hit->dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- return found;
-}
-
-bool uv_find_nearest_edge_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len,
- const float co[2], UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
+ Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv, *luv_next;
+ int i;
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+
+ if (dist_test_sq < hit->dist_sq) {
+ hit->efa = efa;
+
+ hit->l = l;
+ hit->luv = luv;
+ hit->luv_next = luv_next;
+ hit->lindex = i;
+
+ hit->dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_edge_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
}
bool uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, const float co[2],
- UvNearestHit *hit_final)
+ Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMIter iter;
- BMFace *efa;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- const float dist_test_sq = len_squared_v2v2(co, cent);
-
- if (dist_test_sq < hit.dist_sq) {
- hit.efa = efa;
- hit.dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- if (found) {
- *hit_final = hit;
- }
- return found;
-}
-
-bool uv_find_nearest_face_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len,
- const float co[2], UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-static bool uv_nearest_between(
- const BMLoop *l, const float co[2],
- const int cd_loop_uv_offset)
-{
- const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
- const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
- const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
-
- return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
- (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
-}
-
-bool uv_find_nearest_vert(
- Scene *scene, Image *ima, Object *obedit,
- float const co[2], const float penalty_dist, UvNearestHit *hit_final)
-{
- bool found = false;
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
-
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BMIter liter;
- BMLoop *l;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- float dist_test_sq;
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
- dist_test_sq = SQUARE(dist_test_sq);
- }
- else {
- dist_test_sq = len_squared_v2v2(co, luv->uv);
- }
-
- if (dist_test_sq <= hit.dist_sq) {
- if (dist_test_sq == hit.dist_sq) {
- if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
- continue;
- }
- }
-
- hit.dist_sq = dist_test_sq;
-
- hit.l = l;
- hit.luv = luv;
- hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit.efa = efa;
- hit.lindex = i;
- found = true;
- }
- }
- }
- }
-
- if (found) {
- *hit_final = hit;
- }
-
- return found;
-}
-
-bool uv_find_nearest_vert_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len,
- float const co[2], const float penalty_dist, UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ const float dist_test_sq = len_squared_v2v2(co, cent);
+
+ if (dist_test_sq < hit.dist_sq) {
+ hit.efa = efa;
+ hit.dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ *hit_final = hit;
+ }
+ return found;
+}
+
+bool uv_find_nearest_face_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
+{
+ const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
+ const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
+ const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
+
+ return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
+ (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
+}
+
+bool uv_find_nearest_vert(Scene *scene,
+ Image *ima,
+ Object *obedit,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ int i;
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ float dist_test_sq;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+ dist_test_sq = SQUARE(dist_test_sq);
+ }
+ else {
+ dist_test_sq = len_squared_v2v2(co, luv->uv);
+ }
+
+ if (dist_test_sq <= hit.dist_sq) {
+ if (dist_test_sq == hit.dist_sq) {
+ if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+ continue;
+ }
+ }
+
+ hit.dist_sq = dist_test_sq;
+
+ hit.l = l;
+ hit.luv = luv;
+ hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ hit.efa = efa;
+ hit.lindex = i;
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (found) {
+ *hit_final = hit;
+ }
+
+ return found;
+}
+
+bool uv_find_nearest_vert_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
}
bool ED_uvedit_nearest_uv(
- Scene *scene, Object *obedit, Image *ima, const float co[2],
- float *dist_sq, float r_uv[2])
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMFace *efa;
- const float *uv_best = NULL;
- float dist_best = *dist_sq;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
- if (dist_best > dist_test) {
- dist_best = dist_test;
- uv_best = uv;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- if (uv_best != NULL) {
- copy_v2_v2(r_uv, uv_best);
- *dist_sq = dist_best;
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_uvedit_nearest_uv_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, const float co[2],
- float *dist_sq, float r_uv[2])
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
- found = true;
- }
- }
- return found;
+ Scene *scene, Object *obedit, Image *ima, const float co[2], float *dist_sq, float r_uv[2])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMFace *efa;
+ const float *uv_best = NULL;
+ float dist_best = *dist_sq;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
+ const float dist_test = len_squared_v2v2(co, uv);
+ if (dist_best > dist_test) {
+ dist_best = dist_test;
+ uv_best = uv;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ if (uv_best != NULL) {
+ copy_v2_v2(r_uv, uv_best);
+ *dist_sq = dist_best;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_uvedit_nearest_uv_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
+ found = true;
+ }
+ }
+ return found;
}
/** \} */
@@ -974,185 +1020,192 @@ bool ED_uvedit_nearest_uv_multi(
static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
{
- UvMapVert *iterv;
- int count = 0;
+ UvMapVert *iterv;
+ int count = 0;
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate && iterv != first)
- break;
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate && iterv != first)
+ break;
- count++;
- }
+ count++;
+ }
- if (count < 5)
- first->flag = 1;
+ if (count < 5)
+ first->flag = 1;
}
static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
{
- UvMapVert *iterv, *first;
- first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate)
- first = iterv;
- if (iterv->poly_index == BM_elem_index_get(efa))
- return first;
- }
-
- return NULL;
-}
-
-static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
+ UvMapVert *iterv, *first;
+ first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate)
+ first = iterv;
+ if (iterv->poly_index == BM_elem_index_get(efa))
+ return first;
+ }
+
+ return NULL;
+}
+
+static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
+ UvMapVert *first1,
+ UvMapVert *first2,
+ int *totface)
{
- UvMapVert *iterv1, *iterv2;
- BMFace *efa;
- int tot = 0;
-
- /* count number of faces this edge has */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1)
- break;
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2)
- break;
-
- if (iterv1->poly_index == iterv2->poly_index) {
- /* if face already tagged, don't do this edge */
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- if (BM_elem_flag_test(efa, BM_ELEM_TAG))
- return false;
-
- tot++;
- break;
- }
- }
- }
-
- if (*totface == 0) /* start edge */
- *totface = tot;
- else if (tot != *totface) /* check for same number of faces as start edge */
- return false;
-
- /* tag the faces */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1)
- break;
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2)
- break;
-
- if (iterv1->poly_index == iterv2->poly_index) {
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- return true;
-}
-
-static int uv_select_edgeloop(
- Scene *scene, Image *ima, Object *obedit, UvNearestHit *hit,
- const float limit[2], const bool extend)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter, liter;
- BMLoop *l;
- UvVertMap *vmap;
- UvMapVert *iterv_curr;
- UvMapVert *iterv_next;
- int starttotf;
- bool looking, select;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* setup */
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
-
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* set flags for first face and verts */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
-
- starttotf = 0;
- uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
-
- /* sorry, first edge isn't even ok */
- looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
-
- /* iterate */
- while (looking) {
- looking = false;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- /* check face not hidden and not tagged */
- if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l)))
- continue;
- if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next)))
- continue;
-
- /* check if vertex is tagged and has right valence */
- if (iterv_curr->flag || iterv_next->flag) {
- if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
- looking = true;
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
- break;
- }
- }
- }
- }
- }
- }
-
- /* do the actual select/deselect */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- iterv_curr->flag = 1;
- iterv_next->flag = 1;
-
- if (extend) {
- select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
- }
- else {
- select = true;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
-
- if (iterv_curr->flag) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- /* cleanup */
- BM_uv_vert_map_free(vmap);
-
- return (select) ? 1 : -1;
+ UvMapVert *iterv1, *iterv2;
+ BMFace *efa;
+ int tot = 0;
+
+ /* count number of faces this edge has */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1)
+ break;
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2)
+ break;
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ /* if face already tagged, don't do this edge */
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG))
+ return false;
+
+ tot++;
+ break;
+ }
+ }
+ }
+
+ if (*totface == 0) /* start edge */
+ *totface = tot;
+ else if (tot != *totface) /* check for same number of faces as start edge */
+ return false;
+
+ /* tag the faces */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1)
+ break;
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2)
+ break;
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int uv_select_edgeloop(Scene *scene,
+ Image *ima,
+ Object *obedit,
+ UvNearestHit *hit,
+ const float limit[2],
+ const bool extend)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+ UvVertMap *vmap;
+ UvMapVert *iterv_curr;
+ UvMapVert *iterv_next;
+ int starttotf;
+ bool looking, select;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* setup */
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+
+ if (!extend) {
+ uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
+ }
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* set flags for first face and verts */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+
+ starttotf = 0;
+ uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
+
+ /* sorry, first edge isn't even ok */
+ looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
+
+ /* iterate */
+ while (looking) {
+ looking = false;
+
+ /* find correct valence edges which are not tagged yet, but connect to tagged one */
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
+ uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ /* check face not hidden and not tagged */
+ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l)))
+ continue;
+ if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next)))
+ continue;
+
+ /* check if vertex is tagged and has right valence */
+ if (iterv_curr->flag || iterv_next->flag) {
+ if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
+ looking = true;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* do the actual select/deselect */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ iterv_curr->flag = 1;
+ iterv_next->flag = 1;
+
+ if (extend) {
+ select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
+ }
+ else {
+ select = true;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
+
+ if (iterv_curr->flag) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ /* cleanup */
+ BM_uv_vert_map_free(vmap);
+
+ return (select) ? 1 : -1;
}
/** \} */
@@ -1161,203 +1214,212 @@ static int uv_select_edgeloop(
/** \name Select Linked
* \{ */
-static void uv_select_linked_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2],
- UvNearestHit *hit_final, bool extend, bool deselect, bool toggle, bool select_faces)
-{
- /* loop over objects, or just use hit_final->ob */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (hit_final && ob_index != 0) {
- break;
- }
- Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvVertMap *vmap;
- UvMapVert *vlist, *iterv, *startv;
- int i, stacksize = 0, *stack;
- unsigned int a;
- char *flag;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
-
- /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
- * this made *every* projection split the island into front/back islands.
- * Keep 'use_winding' to false, see: T50970.
- *
- * Better solve this by having a delimit option for select-linked operator,
- * keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
-
- if (vmap == NULL)
- return;
-
- stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
- flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
-
- if (hit_final == NULL) {
- /* Use existing selection */
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
-
- break;
- }
- }
- }
- }
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit_final->efa) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- break;
- }
- }
- }
-
- while (stacksize > 0) {
-
- stacksize--;
- a = stack[stacksize];
-
- efa = BM_face_at_index(em->bm, a);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-
- /* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- startv = vlist;
-
- for (iterv = vlist; iterv; iterv = iterv->next) {
- if (iterv->separate)
- startv = iterv;
- if (iterv->poly_index == a)
- break;
- }
-
- for (iterv = startv; iterv; iterv = iterv->next) {
- if ((startv != iterv) && (iterv->separate))
- break;
- else if (!flag[iterv->poly_index]) {
- flag[iterv->poly_index] = 1;
- stack[stacksize] = iterv->poly_index;
- stacksize++;
- }
-
- }
- }
- }
-
- /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
- if ((toggle == true) && (extend == false) && (deselect == false)) {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- bool found_selected = false;
- if (!flag[a]) {
- continue;
- }
-
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- found_selected = true;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- found_selected = true;
- }
- }
-
- if (found_selected) {
- deselect = true;
- break;
- }
- }
- }
- }
+static void uv_select_linked_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len,
+ const float limit[2],
+ UvNearestHit *hit_final,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool select_faces)
+{
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ int i, stacksize = 0, *stack;
+ unsigned int a;
+ char *flag;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
+
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
+
+ if (vmap == NULL)
+ return;
+
+ stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
+ flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
+
+ if (hit_final == NULL) {
+ /* Use existing selection */
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (efa == hit_final->efa) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
+ }
+ }
+
+ while (stacksize > 0) {
+
+ stacksize--;
+ a = stack[stacksize];
+
+ efa = BM_face_at_index(em->bm, a);
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+
+ /* make_uv_vert_map_EM sets verts tmp.l to the indices */
+ vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ startv = vlist;
+
+ for (iterv = vlist; iterv; iterv = iterv->next) {
+ if (iterv->separate)
+ startv = iterv;
+ if (iterv->poly_index == a)
+ break;
+ }
+
+ for (iterv = startv; iterv; iterv = iterv->next) {
+ if ((startv != iterv) && (iterv->separate))
+ break;
+ else if (!flag[iterv->poly_index]) {
+ flag[iterv->poly_index] = 1;
+ stack[stacksize] = iterv->poly_index;
+ stacksize++;
+ }
+ }
+ }
+ }
+
+ /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
+ if ((toggle == true) && (extend == false) && (deselect == false)) {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ bool found_selected = false;
+ if (!flag[a]) {
+ continue;
+ }
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ found_selected = true;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ found_selected = true;
+ }
+ }
+
+ if (found_selected) {
+ deselect = true;
+ break;
+ }
+ }
+ }
+ }
#define SET_SELECTION(value) \
- if (select_faces) { \
- BM_face_select_set(em->bm, efa, value); \
- } \
- else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
- } \
- } (void)0
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (!flag[a]) {
- if (!extend && !deselect && !toggle) {
- SET_SELECTION(false);
- }
- continue;
- }
-
- if (!deselect) {
- SET_SELECTION(true);
- }
- else {
- SET_SELECTION(false);
- }
- }
+ if (select_faces) { \
+ BM_face_select_set(em->bm, efa, value); \
+ } \
+ else { \
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
+ luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ } \
+ } \
+ (void)0
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (!flag[a]) {
+ if (!extend && !deselect && !toggle) {
+ SET_SELECTION(false);
+ }
+ continue;
+ }
+
+ if (!deselect) {
+ SET_SELECTION(true);
+ }
+ else {
+ SET_SELECTION(false);
+ }
+ }
#undef SET_SELECTION
- MEM_freeN(stack);
- MEM_freeN(flag);
- BM_uv_vert_map_free(vmap);
- }
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ BM_uv_vert_map_free(vmap);
+ }
}
/* WATCH IT: this returns first selected UV,
* not ideal in many cases since there could be multiple */
-static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
+static float *uv_sel_co_from_eve(
+ Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
{
- BMIter liter;
- BMLoop *l;
+ BMIter liter;
+ BMLoop *l;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
- continue;
+ BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
+ continue;
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return luv->uv;
- }
- }
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return luv->uv;
+ }
+ }
- return NULL;
+ return NULL;
}
/** \} */
@@ -1368,149 +1430,149 @@ static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEdi
static int uv_select_more_less(bContext *C, const bool select)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- ToolSettings *ts = scene->toolsettings;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ ToolSettings *ts = scene->toolsettings;
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool changed = false;
+ bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select) {
- EDBM_select_more(em, true);
- }
- else {
- EDBM_select_less(em, true);
- }
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select) {
+ EDBM_select_more(em, true);
+ }
+ else {
+ EDBM_select_less(em, true);
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- continue;
- }
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ continue;
+ }
- if (ts->uv_selectmode == UV_SELECT_FACE) {
+ if (ts->uv_selectmode == UV_SELECT_FACE) {
- /* clear tags */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ /* clear tags */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
-#define IS_SEL 1
+#define IS_SEL 1
#define IS_UNSEL 2
- int sel_state = 0;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- sel_state |= IS_SEL;
- }
- else {
- sel_state |= IS_UNSEL;
- }
-
- /* if we have a mixed selection, tag to grow it */
- if (sel_state == (IS_SEL | IS_UNSEL)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- break;
- }
- }
+ int sel_state = 0;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ sel_state |= IS_SEL;
+ }
+ else {
+ sel_state |= IS_UNSEL;
+ }
+
+ /* if we have a mixed selection, tag to grow it */
+ if (sel_state == (IS_SEL | IS_UNSEL)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ break;
+ }
+ }
#undef IS_SEL
#undef IS_UNSEL
-
- }
- }
- }
- else {
-
- /* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_TAG);
- }
- }
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
-
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
- BM_elem_flag_enable(l->next, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
- }
- }
-
- if (changed) {
- /* Select tagged loops. */
- uv_select_flush_from_tag_loop(sima, scene, obedit, select);
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ }
+ }
+ }
+ else {
+
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
+ }
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
+ BM_elem_flag_enable(l->next, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* Select tagged loops. */
+ uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
- return uv_select_more_less(C, true);
+ return uv_select_more_less(C, true);
}
static void UV_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select More";
- ot->description = "Select more UV vertices connected to initial selection";
- ot->idname = "UV_OT_select_more";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Select More";
+ ot->description = "Select more UV vertices connected to initial selection";
+ ot->idname = "UV_OT_select_more";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_more_exec;
- ot->poll = ED_operator_uvedit_space_image;
+ /* api callbacks */
+ ot->exec = uv_select_more_exec;
+ ot->poll = ED_operator_uvedit_space_image;
}
static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
- return uv_select_more_less(C, false);
+ return uv_select_more_less(C, false);
}
static void UV_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Less";
- ot->description = "Deselect UV vertices at the boundary of each selection region";
- ot->idname = "UV_OT_select_less";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->description = "Deselect UV vertices at the boundary of each selection region";
+ ot->idname = "UV_OT_select_less";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_less_exec;
- ot->poll = ED_operator_uvedit_space_image;
+ /* api callbacks */
+ ot->exec = uv_select_less_exec;
+ ot->poll = ED_operator_uvedit_space_image;
}
/** \} */
@@ -1520,297 +1582,308 @@ static void UV_OT_select_less(wmOperatorType *ot)
* \{ */
typedef enum eUVWeldAlign {
- UV_STRAIGHTEN,
- UV_STRAIGHTEN_X,
- UV_STRAIGHTEN_Y,
- UV_ALIGN_AUTO,
- UV_ALIGN_X,
- UV_ALIGN_Y,
- UV_WELD,
+ UV_STRAIGHTEN,
+ UV_STRAIGHTEN_X,
+ UV_STRAIGHTEN_Y,
+ UV_ALIGN_AUTO,
+ UV_ALIGN_X,
+ UV_ALIGN_Y,
+ UV_WELD,
} eUVWeldAlign;
static void uv_weld_align(bContext *C, eUVWeldAlign tool)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- float cent[2], min[2], max[2];
-
- INIT_MINMAX2(min, max);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- if (tool == UV_ALIGN_AUTO) {
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(min, max, luv->uv);
- }
- }
- }
- }
- tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
- }
-
- ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool changed = false;
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = cent[0];
- changed = true;
- }
-
- }
- }
- }
-
- if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = cent[1];
- changed = true;
- }
-
- }
- }
- }
-
- if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
- BMEdge *eed;
- BMLoop *l;
- BMVert *eve;
- BMVert *eve_start;
- BMIter iter, liter, eiter;
-
- /* clear tag */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- /* tag verts with a selected UV */
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
- continue;
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- BM_elem_flag_enable(eve, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- /* flush vertex tags to edges */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- eed, BM_ELEM_TAG,
- (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
- BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
- }
-
- /* find a vertex with only one tagged edge */
- eve_start = NULL;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- int tot_eed_tag = 0;
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- tot_eed_tag++;
- }
- }
-
- if (tot_eed_tag == 1) {
- eve_start = eve;
- break;
- }
- }
-
- if (eve_start) {
- BMVert **eve_line = NULL;
- BMVert *eve_next = NULL;
- BLI_array_declare(eve_line);
- int i;
-
- eve = eve_start;
-
- /* walk over edges, building an array of verts in a line */
- while (eve) {
- BLI_array_append(eve_line, eve);
- /* don't touch again */
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
-
- eve_next = NULL;
-
- /* find next eve */
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- BMVert *eve_other = BM_edge_other_vert(eed, eve);
- if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
- /* this is a tagged vert we didn't walk over yet, step onto it */
- eve_next = eve_other;
- break;
- }
- }
- }
-
- eve = eve_next;
- }
-
- /* now we have all verts, make into a line */
- if (BLI_array_len(eve_line) > 2) {
-
- /* we know the returns from these must be valid */
- const float *uv_start = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[0]);
- const float *uv_end = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
- /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
- float a = 0.0f;
- eUVWeldAlign tool_local = tool;
-
- if (tool_local == UV_STRAIGHTEN_X) {
- if (uv_start[1] == uv_end[1])
- tool_local = UV_STRAIGHTEN;
- else
- a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
- }
- else if (tool_local == UV_STRAIGHTEN_Y) {
- if (uv_start[0] == uv_end[0])
- tool_local = UV_STRAIGHTEN;
- else
- a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
- }
-
- /* go over all verts except for endpoints */
- for (i = 0; i < BLI_array_len(eve_line); i++) {
- BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
- continue;
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
- * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
- * Maybe this should be a BLI func? Or is it already existing?
- * Could use interp_v2_v2v2, but not sure it's worth it here...*/
- if (tool_local == UV_STRAIGHTEN_X)
- luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
- else if (tool_local == UV_STRAIGHTEN_Y)
- luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
- else
- closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
- changed = true;
- }
- }
- }
- }
- else {
- /* error - not a line, needs 3+ points */
- }
-
- if (eve_line) {
- MEM_freeN(eve_line);
- }
- }
- else {
- /* error - cant find an endpoint */
- }
- }
-
- if (changed) {
- uvedit_live_unwrap_update(sima, scene, obedit);
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- }
-
- MEM_freeN(objects);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ float cent[2], min[2], max[2];
+
+ INIT_MINMAX2(min, max);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (tool == UV_ALIGN_AUTO) {
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(min, max, luv->uv);
+ }
+ }
+ }
+ }
+ tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
+ }
+
+ ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = cent[0];
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[1] = cent[1];
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
+ BMEdge *eed;
+ BMLoop *l;
+ BMVert *eve;
+ BMVert *eve_start;
+ BMIter iter, liter, eiter;
+
+ /* clear tag */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ /* tag verts with a selected UV */
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
+ continue;
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ /* flush vertex tags to edges */
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(
+ eed,
+ BM_ELEM_TAG,
+ (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
+ }
+
+ /* find a vertex with only one tagged edge */
+ eve_start = NULL;
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ int tot_eed_tag = 0;
+ BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
+ tot_eed_tag++;
+ }
+ }
+
+ if (tot_eed_tag == 1) {
+ eve_start = eve;
+ break;
+ }
+ }
+
+ if (eve_start) {
+ BMVert **eve_line = NULL;
+ BMVert *eve_next = NULL;
+ BLI_array_declare(eve_line);
+ int i;
+
+ eve = eve_start;
+
+ /* walk over edges, building an array of verts in a line */
+ while (eve) {
+ BLI_array_append(eve_line, eve);
+ /* don't touch again */
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+
+ eve_next = NULL;
+
+ /* find next eve */
+ BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
+ BMVert *eve_other = BM_edge_other_vert(eed, eve);
+ if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
+ /* this is a tagged vert we didn't walk over yet, step onto it */
+ eve_next = eve_other;
+ break;
+ }
+ }
+ }
+
+ eve = eve_next;
+ }
+
+ /* now we have all verts, make into a line */
+ if (BLI_array_len(eve_line) > 2) {
+
+ /* we know the returns from these must be valid */
+ const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]);
+ const float *uv_end = uv_sel_co_from_eve(
+ scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
+ /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
+ float a = 0.0f;
+ eUVWeldAlign tool_local = tool;
+
+ if (tool_local == UV_STRAIGHTEN_X) {
+ if (uv_start[1] == uv_end[1])
+ tool_local = UV_STRAIGHTEN;
+ else
+ a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ if (uv_start[0] == uv_end[0])
+ tool_local = UV_STRAIGHTEN;
+ else
+ a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
+ }
+
+ /* go over all verts except for endpoints */
+ for (i = 0; i < BLI_array_len(eve_line); i++) {
+ BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
+ continue;
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
+ * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
+ * Maybe this should be a BLI func? Or is it already existing?
+ * Could use interp_v2_v2v2, but not sure it's worth it here...*/
+ if (tool_local == UV_STRAIGHTEN_X)
+ luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
+ else if (tool_local == UV_STRAIGHTEN_Y)
+ luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
+ else
+ closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
+ changed = true;
+ }
+ }
+ }
+ }
+ else {
+ /* error - not a line, needs 3+ points */
+ }
+
+ if (eve_line) {
+ MEM_freeN(eve_line);
+ }
+ }
+ else {
+ /* error - cant find an endpoint */
+ }
+ }
+
+ if (changed) {
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+
+ MEM_freeN(objects);
}
static int uv_align_exec(bContext *C, wmOperator *op)
{
- uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
+ uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void UV_OT_align(wmOperatorType *ot)
{
- static const EnumPropertyItem axis_items[] = {
- {UV_STRAIGHTEN, "ALIGN_S", 0, "Straighten",
- "Align UVs along the line defined by the endpoints"},
- {UV_STRAIGHTEN_X, "ALIGN_T", 0, "Straighten X",
- "Align UVs along the line defined by the endpoints along the X axis"},
- {UV_STRAIGHTEN_Y, "ALIGN_U", 0, "Straighten Y",
- "Align UVs along the line defined by the endpoints along the Y axis"},
- {UV_ALIGN_AUTO, "ALIGN_AUTO", 0, "Align Auto",
- "Automatically choose the axis on which there is most alignment already"},
- {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
- {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Align";
- ot->description = "Align selected UV vertices to an axis";
- ot->idname = "UV_OT_align";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_align_exec;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_enum(ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
+ static const EnumPropertyItem axis_items[] = {
+ {UV_STRAIGHTEN,
+ "ALIGN_S",
+ 0,
+ "Straighten",
+ "Align UVs along the line defined by the endpoints"},
+ {UV_STRAIGHTEN_X,
+ "ALIGN_T",
+ 0,
+ "Straighten X",
+ "Align UVs along the line defined by the endpoints along the X axis"},
+ {UV_STRAIGHTEN_Y,
+ "ALIGN_U",
+ 0,
+ "Straighten Y",
+ "Align UVs along the line defined by the endpoints along the Y axis"},
+ {UV_ALIGN_AUTO,
+ "ALIGN_AUTO",
+ 0,
+ "Align Auto",
+ "Automatically choose the axis on which there is most alignment already"},
+ {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
+ {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Align";
+ ot->description = "Align selected UV vertices to an axis";
+ ot->idname = "UV_OT_align";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_align_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_enum(
+ ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
}
/** \} */
@@ -1821,282 +1894,293 @@ static void UV_OT_align(wmOperatorType *ot)
static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
-
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
-
- /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
- * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
- uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
- "uv_remove_doubles_selected.ob_mloopuv_max_idx");
-
- /* Calculate max possible number of kdtree nodes. */
- int uv_maxlen = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- uv_maxlen += em->bm->totloop;
- }
-
- KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
-
- int *duplicates = NULL;
- BLI_array_declare(duplicates);
-
- MLoopUV **mloopuv_arr = NULL;
- BLI_array_declare(mloopuv_arr);
-
- int mloopuv_count = 0; /* Also used for *duplicates count. */
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
- BLI_array_append(duplicates, -1);
- BLI_array_append(mloopuv_arr, luv);
- mloopuv_count++;
- }
- }
- }
-
- ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
- }
-
- BLI_kdtree_2d_balance(tree);
- int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates);
-
- if (found_duplicates > 0) {
- /* Calculate average uv for duplicates. */
- int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
- "uv_remove_doubles_selected.uv_duplicate_count");
- for (int i = 0; i < mloopuv_count; i++) {
- if (duplicates[i] == -1) { /* If doesn't reference another */
- uv_duplicate_count[i]++; /* self */
- continue;
- }
-
- if (duplicates[i] != i) {
- /* If not self then accumulate uv for averaging.
- * Self uv is already present in accumulator */
- add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
- }
- uv_duplicate_count[duplicates[i]]++;
- }
-
- for (int i = 0; i < mloopuv_count; i++) {
- if (uv_duplicate_count[i] < 2) {
- continue;
- }
-
- mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
- }
- MEM_freeN(uv_duplicate_count);
-
- /* Update duplicated uvs. */
- uint ob_index = 0;
- for (int i = 0; i < mloopuv_count; i++) {
- /* Make sure we know which object owns the MLoopUV at this index.
- * Remember that in some cases the object will have no loop uv,
- * thus we need the while loop, and not simply an if check. */
- while (ob_mloopuv_max_idx[ob_index] < i) {
- ob_index++;
- }
-
- if (duplicates[i] == -1) {
- continue;
- }
-
- copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
- changed[ob_index] = true;
- }
-
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- if (changed[ob_index]) {
- Object *obedit = objects[ob_index];
- uvedit_live_unwrap_update(sima, scene, obedit);
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- }
- }
-
- BLI_kdtree_2d_free(tree);
- BLI_array_free(mloopuv_arr);
- BLI_array_free(duplicates);
- MEM_freeN(changed);
- MEM_freeN(objects);
- MEM_freeN(ob_mloopuv_max_idx);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
+
+ /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
+ * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
+ uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
+ "uv_remove_doubles_selected.ob_mloopuv_max_idx");
+
+ /* Calculate max possible number of kdtree nodes. */
+ int uv_maxlen = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ uv_maxlen += em->bm->totloop;
+ }
+
+ KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
+
+ int *duplicates = NULL;
+ BLI_array_declare(duplicates);
+
+ MLoopUV **mloopuv_arr = NULL;
+ BLI_array_declare(mloopuv_arr);
+
+ int mloopuv_count = 0; /* Also used for *duplicates count. */
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
+ BLI_array_append(duplicates, -1);
+ BLI_array_append(mloopuv_arr, luv);
+ mloopuv_count++;
+ }
+ }
+ }
+
+ ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
+ }
+
+ BLI_kdtree_2d_balance(tree);
+ int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates);
+
+ if (found_duplicates > 0) {
+ /* Calculate average uv for duplicates. */
+ int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
+ "uv_remove_doubles_selected.uv_duplicate_count");
+ for (int i = 0; i < mloopuv_count; i++) {
+ if (duplicates[i] == -1) { /* If doesn't reference another */
+ uv_duplicate_count[i]++; /* self */
+ continue;
+ }
+
+ if (duplicates[i] != i) {
+ /* If not self then accumulate uv for averaging.
+ * Self uv is already present in accumulator */
+ add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
+ }
+ uv_duplicate_count[duplicates[i]]++;
+ }
+
+ for (int i = 0; i < mloopuv_count; i++) {
+ if (uv_duplicate_count[i] < 2) {
+ continue;
+ }
+
+ mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
+ }
+ MEM_freeN(uv_duplicate_count);
+
+ /* Update duplicated uvs. */
+ uint ob_index = 0;
+ for (int i = 0; i < mloopuv_count; i++) {
+ /* Make sure we know which object owns the MLoopUV at this index.
+ * Remember that in some cases the object will have no loop uv,
+ * thus we need the while loop, and not simply an if check. */
+ while (ob_mloopuv_max_idx[ob_index] < i) {
+ ob_index++;
+ }
+
+ if (duplicates[i] == -1) {
+ continue;
+ }
+
+ copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
+ changed[ob_index] = true;
+ }
+
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (changed[ob_index]) {
+ Object *obedit = objects[ob_index];
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+ }
+
+ BLI_kdtree_2d_free(tree);
+ BLI_array_free(mloopuv_arr);
+ BLI_array_free(duplicates);
+ MEM_freeN(changed);
+ MEM_freeN(objects);
+ MEM_freeN(ob_mloopuv_max_idx);
+
+ return OPERATOR_FINISHED;
}
static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
-
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- /* Calculate max possible number of kdtree nodes. */
- int uv_maxlen = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- uv_maxlen += em->bm->totloop;
- }
-
- KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
-
- MLoopUV **mloopuv_arr = NULL;
- BLI_array_declare(mloopuv_arr);
-
- int mloopuv_count = 0;
-
- /* Add visible non-selected uvs to tree */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
- BLI_array_append(mloopuv_arr, luv);
- mloopuv_count++;
- }
- }
- }
- }
-
- BLI_kdtree_2d_balance(tree);
-
- /* For each selected uv, find duplicate non selected uv. */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
- bool changed = false;
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- KDTreeNearest_2d nearest;
- const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest);
-
- if (i != -1 && nearest.dist < threshold) {
- copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
- changed = true;
- }
- }
- }
- }
-
- if (changed) {
- uvedit_live_unwrap_update(sima, scene, obedit);
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- }
-
- BLI_kdtree_2d_free(tree);
- BLI_array_free(mloopuv_arr);
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ /* Calculate max possible number of kdtree nodes. */
+ int uv_maxlen = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ uv_maxlen += em->bm->totloop;
+ }
+
+ KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
+
+ MLoopUV **mloopuv_arr = NULL;
+ BLI_array_declare(mloopuv_arr);
+
+ int mloopuv_count = 0;
+
+ /* Add visible non-selected uvs to tree */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
+ BLI_array_append(mloopuv_arr, luv);
+ mloopuv_count++;
+ }
+ }
+ }
+ }
+
+ BLI_kdtree_2d_balance(tree);
+
+ /* For each selected uv, find duplicate non selected uv. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ bool changed = false;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ KDTreeNearest_2d nearest;
+ const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest);
+
+ if (i != -1 && nearest.dist < threshold) {
+ copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+
+ BLI_kdtree_2d_free(tree);
+ BLI_array_free(mloopuv_arr);
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
{
- if (RNA_boolean_get(op->ptr, "use_unselected")) {
- return uv_remove_doubles_to_unselected(C, op);
- }
- else {
- return uv_remove_doubles_to_selected(C, op);
- }
+ if (RNA_boolean_get(op->ptr, "use_unselected")) {
+ return uv_remove_doubles_to_unselected(C, op);
+ }
+ else {
+ return uv_remove_doubles_to_selected(C, op);
+ }
}
static void UV_OT_remove_doubles(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Doubles UV";
- ot->description = "Selected UV vertices that are within a radius of each other are welded together";
- ot->idname = "UV_OT_remove_doubles";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_remove_doubles_exec;
- ot->poll = ED_operator_uvedit;
-
- RNA_def_float(ot->srna, "threshold", 0.02f, 0.0f, 10.0f,
- "Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f);
- RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
+ /* identifiers */
+ ot->name = "Remove Doubles UV";
+ ot->description =
+ "Selected UV vertices that are within a radius of each other are welded together";
+ ot->idname = "UV_OT_remove_doubles";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_remove_doubles_exec;
+ ot->poll = ED_operator_uvedit;
+
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.02f,
+ 0.0f,
+ 10.0f,
+ "Merge Distance",
+ "Maximum distance between welded vertices",
+ 0.0f,
+ 1.0f);
+ RNA_def_boolean(
+ ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
}
/** \} */
@@ -2107,22 +2191,22 @@ static void UV_OT_remove_doubles(wmOperatorType *ot)
static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
{
- uv_weld_align(C, UV_WELD);
+ uv_weld_align(C, UV_WELD);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void UV_OT_weld(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Weld";
- ot->description = "Weld selected UV vertices together";
- ot->idname = "UV_OT_weld";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Weld";
+ ot->description = "Weld selected UV vertices together";
+ ot->idname = "UV_OT_weld";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_weld_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_weld_exec;
+ ot->poll = ED_operator_uvedit;
}
/** \} */
@@ -2133,153 +2217,158 @@ static void UV_OT_weld(wmOperatorType *ot)
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
{
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
- }
- else {
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_select_is_any_selected(scene, ima, obedit)) {
- found = true;
- break;
- }
- }
- return found;
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool uv_select_is_any_selected_multi(Scene *scene,
+ Image *ima,
+ Object **objects,
+ const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_select_is_any_selected(scene, ima, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
}
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
{
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
- }
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- switch (action) {
- case SEL_SELECT:
- luv->flag |= MLOOPUV_VERTSEL;
- break;
- case SEL_DESELECT:
- luv->flag &= ~MLOOPUV_VERTSEL;
- break;
- case SEL_INVERT:
- luv->flag ^= MLOOPUV_VERTSEL;
- break;
- }
- }
- }
- }
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ switch (action) {
+ case SEL_TOGGLE:
+ EDBM_select_toggle_all(em);
+ break;
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (action) {
+ case SEL_SELECT:
+ luv->flag |= MLOOPUV_VERTSEL;
+ break;
+ case SEL_DESELECT:
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ break;
+ case SEL_INVERT:
+ luv->flag ^= MLOOPUV_VERTSEL;
+ break;
+ }
+ }
+ }
+ }
}
static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
{
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : SEL_SELECT;
- }
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
+ SEL_SELECT;
+ }
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_all_perform(scene, ima, obedit, action);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, ima, obedit, action);
+ }
}
static int uv_select_all_exec(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- int action = RNA_enum_get(op->ptr, "action");
+ int action = RNA_enum_get(op->ptr, "action");
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
- MEM_freeN(objects);
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void UV_OT_select_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "(De)select All";
- ot->description = "Change selection of all UV vertices";
- ot->idname = "UV_OT_select_all";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->description = "Change selection of all UV vertices";
+ ot->idname = "UV_OT_select_all";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_all_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_select_all_exec;
+ ot->poll = ED_operator_uvedit;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
/** \} */
@@ -2288,352 +2377,370 @@ static void UV_OT_select_all(wmOperatorType *ot)
/** \name Mouse Select Operator
* \{ */
-static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
+static bool uv_sticky_select(
+ float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
{
- int i;
+ int i;
- /* this function test if some vertex needs to selected
- * in addition to the existing ones due to sticky select */
- if (sticky == SI_STICKY_DISABLE)
- return false;
+ /* this function test if some vertex needs to selected
+ * in addition to the existing ones due to sticky select */
+ if (sticky == SI_STICKY_DISABLE)
+ return false;
- for (i = 0; i < hitlen; i++) {
- if (hitv[i] == v) {
- if (sticky == SI_STICKY_LOC) {
- if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1])
- return true;
- }
- else if (sticky == SI_STICKY_VERTEX)
- return true;
- }
- }
+ for (i = 0; i < hitlen; i++) {
+ if (hitv[i] == v) {
+ if (sticky == SI_STICKY_LOC) {
+ if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1])
+ return true;
+ }
+ else if (sticky == SI_STICKY_VERTEX)
+ return true;
+ }
+ }
- return false;
+ return false;
}
static int uv_mouse_select_multi(
- bContext *C, Object **objects, uint objects_len,
- const float co[2], bool extend, bool loop)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- int i, selectmode, sticky, sync, *hitv = NULL;
- bool select = true;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
- int flush = 0;
- int hitlen = 0;
- float limit[2], **hituv = NULL;
-
- /* notice 'limit' is the same no matter the zoom level, since this is like
- * remove doubles and could annoying if it joined points when zoomed out.
- * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
- * shift-selecting can consider an adjacent point close enough to add to
- * the selection rather than de-selecting the closest. */
-
- float penalty_dist;
- {
- float penalty[2];
- uvedit_pixel_to_float(sima, limit, 0.05f);
- uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
- penalty_dist = len_v2(penalty);
- }
-
- /* retrieve operation mode */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- sync = 1;
-
- if (ts->selectmode & SCE_SELECT_FACE)
- selectmode = UV_SELECT_FACE;
- else if (ts->selectmode & SCE_SELECT_EDGE)
- selectmode = UV_SELECT_EDGE;
- else
- selectmode = UV_SELECT_VERTEX;
-
- sticky = SI_STICKY_DISABLE;
- }
- else {
- sync = 0;
- selectmode = ts->uv_selectmode;
- sticky = (sima) ? sima->sticky : 1;
- }
-
- /* find nearest element */
- if (loop) {
- /* find edge */
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- return OPERATOR_CANCELLED;
- }
-
- hitlen = 0;
- }
- else if (selectmode == UV_SELECT_VERTEX) {
- /* find vertex */
- if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) {
- return OPERATOR_CANCELLED;
- }
-
- /* mark 1 vertex as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hituv[hit.lindex] = hit.luv->uv;
-
- hitlen = hit.efa->len;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* find edge */
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- return OPERATOR_CANCELLED;
- }
-
- /* mark 2 edge vertices as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
- hituv[hit.lindex] = hit.luv->uv;
- hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
-
- hitlen = hit.efa->len;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* find face */
- if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) {
- return OPERATOR_CANCELLED;
- }
-
- BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* make active */
- BM_mesh_active_face_set(em->bm, hit.efa);
-
- /* mark all face vertices as being hit */
-
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- hituv[i] = luv->uv;
- hitv[i] = BM_elem_index_get(l->v);
- }
-
- hitlen = hit.efa->len;
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- return OPERATOR_CANCELLED;
- }
-
- hitlen = 0;
- }
- else {
- hitlen = 0;
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (loop) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
- }
- else if (extend) {
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
- }
-
- /* de-selecting an edge may deselect a face too - validate */
- if (sync) {
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
-
- flush = select ? 1 : -1;
- }
- }
- else {
- /* deselect all */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
- }
-
- /* select sticky uvs */
- if (sticky != SI_STICKY_DISABLE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (sticky == SI_STICKY_DISABLE) continue;
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
-
- flush = 1;
- }
- }
- }
- }
-
- if (sync) {
- /* flush for mesh selection */
-
- /* before bmesh */
+ bContext *C, Object **objects, uint objects_len, const float co[2], bool extend, bool loop)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ int i, selectmode, sticky, sync, *hitv = NULL;
+ bool select = true;
+ /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ int flush = 0;
+ int hitlen = 0;
+ float limit[2], **hituv = NULL;
+
+ /* notice 'limit' is the same no matter the zoom level, since this is like
+ * remove doubles and could annoying if it joined points when zoomed out.
+ * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
+ * shift-selecting can consider an adjacent point close enough to add to
+ * the selection rather than de-selecting the closest. */
+
+ float penalty_dist;
+ {
+ float penalty[2];
+ uvedit_pixel_to_float(sima, limit, 0.05f);
+ uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
+ penalty_dist = len_v2(penalty);
+ }
+
+ /* retrieve operation mode */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ sync = 1;
+
+ if (ts->selectmode & SCE_SELECT_FACE)
+ selectmode = UV_SELECT_FACE;
+ else if (ts->selectmode & SCE_SELECT_EDGE)
+ selectmode = UV_SELECT_EDGE;
+ else
+ selectmode = UV_SELECT_VERTEX;
+
+ sticky = SI_STICKY_DISABLE;
+ }
+ else {
+ sync = 0;
+ selectmode = ts->uv_selectmode;
+ sticky = (sima) ? sima->sticky : 1;
+ }
+
+ /* find nearest element */
+ if (loop) {
+ /* find edge */
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ hitlen = 0;
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ /* find vertex */
+ if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* mark 1 vertex as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hituv[hit.lindex] = hit.luv->uv;
+
+ hitlen = hit.efa->len;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* find edge */
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* mark 2 edge vertices as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
+ hituv[hit.lindex] = hit.luv->uv;
+ hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
+
+ hitlen = hit.efa->len;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* find face */
+ if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* make active */
+ BM_mesh_active_face_set(em->bm, hit.efa);
+
+ /* mark all face vertices as being hit */
+
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ BM_ITER_ELEM_INDEX(l, &liter, hit.efa, BM_LOOPS_OF_FACE, i)
+ {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ hituv[i] = luv->uv;
+ hitv[i] = BM_elem_index_get(l->v);
+ }
+
+ hitlen = hit.efa->len;
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ hitlen = 0;
+ }
+ else {
+ hitlen = 0;
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (loop) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
+ }
+ else if (extend) {
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* (de)select uv vertex */
+ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* (de)select edge */
+ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
+ uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* (de)select face */
+ select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
+ uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
+ flush = -1;
+ }
+
+ /* de-selecting an edge may deselect a face too - validate */
+ if (sync) {
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+
+ /* (de)select sticky uv nodes */
+ if (sticky != SI_STICKY_DISABLE) {
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+
+ flush = select ? 1 : -1;
+ }
+ }
+ else {
+ /* deselect all */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* select vertex */
+ uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* select edge */
+ uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* select face */
+ uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
+ }
+
+ /* select sticky uvs */
+ if (sticky != SI_STICKY_DISABLE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (sticky == SI_STICKY_DISABLE)
+ continue;
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+
+ flush = 1;
+ }
+ }
+ }
+ }
+
+ if (sync) {
+ /* flush for mesh selection */
+
+ /* before bmesh */
#if 0
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (flush == 1) EDBM_select_flush(em);
- else if (flush == -1) EDBM_deselect_flush(em);
- }
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (flush == 1) EDBM_select_flush(em);
+ else if (flush == -1) EDBM_deselect_flush(em);
+ }
#else
- if (flush != 0) {
- if (loop) {
- /* push vertex -> edge selection */
- if (select) {
- EDBM_select_flush(em);
- }
- else {
- EDBM_deselect_flush(em);
- }
- }
- else {
- EDBM_selectmode_flush(em);
- }
- }
+ if (flush != 0) {
+ if (loop) {
+ /* push vertex -> edge selection */
+ if (select) {
+ EDBM_select_flush(em);
+ }
+ else {
+ EDBM_deselect_flush(em);
+ }
+ }
+ else {
+ EDBM_selectmode_flush(em);
+ }
+ }
#endif
- }
+ }
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obiter = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ }
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop);
- MEM_freeN(objects);
- return ret;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop);
+ MEM_freeN(objects);
+ return ret;
}
static int uv_select_exec(bContext *C, wmOperator *op)
{
- float co[2];
- bool extend, loop;
+ float co[2];
+ bool extend, loop;
- RNA_float_get_array(op->ptr, "location", co);
- extend = RNA_boolean_get(op->ptr, "extend");
- loop = false;
+ RNA_float_get_array(op->ptr, "location", co);
+ extend = RNA_boolean_get(op->ptr, "extend");
+ loop = false;
- return uv_mouse_select(C, co, extend, loop);
+ return uv_mouse_select(C, co, extend, loop);
}
static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ARegion *ar = CTX_wm_region(C);
- float co[2];
+ ARegion *ar = CTX_wm_region(C);
+ float co[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
- return uv_select_exec(C, op);
+ return uv_select_exec(C, op);
}
static void UV_OT_select(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select";
- ot->description = "Select UV vertices";
- ot->idname = "UV_OT_select";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_exec;
- ot->invoke = uv_select_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0,
- "Extend", "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
- "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select UV vertices";
+ ot->idname = "UV_OT_select";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_exec;
+ ot->invoke = uv_select_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
}
/** \} */
@@ -2644,45 +2751,57 @@ static void UV_OT_select(wmOperatorType *ot)
static int uv_select_loop_exec(bContext *C, wmOperator *op)
{
- float co[2];
- bool extend, loop;
+ float co[2];
+ bool extend, loop;
- RNA_float_get_array(op->ptr, "location", co);
- extend = RNA_boolean_get(op->ptr, "extend");
- loop = true;
+ RNA_float_get_array(op->ptr, "location", co);
+ extend = RNA_boolean_get(op->ptr, "extend");
+ loop = true;
- return uv_mouse_select(C, co, extend, loop);
+ return uv_mouse_select(C, co, extend, loop);
}
static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ARegion *ar = CTX_wm_region(C);
- float co[2];
+ ARegion *ar = CTX_wm_region(C);
+ float co[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
- return uv_select_loop_exec(C, op);
+ return uv_select_loop_exec(C, op);
}
static void UV_OT_select_loop(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Loop Select";
- ot->description = "Select a loop of connected UV vertices";
- ot->idname = "UV_OT_select_loop";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_loop_exec;
- ot->invoke = uv_select_loop_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0,
- "Extend", "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
- "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
+ /* identifiers */
+ ot->name = "Loop Select";
+ ot->description = "Select a loop of connected UV vertices";
+ ot->idname = "UV_OT_select_loop";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_loop_exec;
+ ot->invoke = uv_select_loop_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
}
/** \} */
@@ -2693,95 +2812,105 @@ static void UV_OT_select_loop(wmOperatorType *ot)
static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- float limit[2];
- bool extend = true;
- bool deselect = false;
- bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
-
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
- BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- if (pick) {
- extend = RNA_boolean_get(op->ptr, "extend");
- deselect = RNA_boolean_get(op->ptr, "deselect");
- }
- uvedit_pixel_to_float(sima, limit, 0.05f);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- if (pick) {
- float co[2];
-
- if (event) {
- /* invoke */
- ARegion *ar = CTX_wm_region(C);
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
- }
- else {
- /* exec */
- RNA_float_get_array(op->ptr, "location", co);
- }
-
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
- }
-
- if (!extend) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, pick ? &hit : NULL,
- extend, deselect, false, select_faces);
-
- /* weak!, but works */
- Object **objects_free = objects;
- if (pick) {
- objects = &hit.ob;
- objects_len = 1;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
-
- MEM_SAFE_FREE(objects_free);
-
- return OPERATOR_FINISHED;
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ float limit[2];
+ bool extend = true;
+ bool deselect = false;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Select linked only works in face select mode when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (pick) {
+ extend = RNA_boolean_get(op->ptr, "extend");
+ deselect = RNA_boolean_get(op->ptr, "deselect");
+ }
+ uvedit_pixel_to_float(sima, limit, 0.05f);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (pick) {
+ float co[2];
+
+ if (event) {
+ /* invoke */
+ ARegion *ar = CTX_wm_region(C);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+ }
+ else {
+ /* exec */
+ RNA_float_get_array(op->ptr, "location", co);
+ }
+
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!extend) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ uv_select_linked_multi(scene,
+ ima,
+ objects,
+ objects_len,
+ limit,
+ pick ? &hit : NULL,
+ extend,
+ deselect,
+ false,
+ select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
+
+ return OPERATOR_FINISHED;
}
static int uv_select_linked_exec(bContext *C, wmOperator *op)
{
- return uv_select_linked_internal(C, op, NULL, 0);
+ return uv_select_linked_internal(C, op, NULL, 0);
}
static void UV_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Linked";
- ot->description = "Select all UV vertices linked to the active UV map";
- ot->idname = "UV_OT_select_linked";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->description = "Select all UV vertices linked to the active UV map";
+ ot->idname = "UV_OT_select_linked";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_linked_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
+ /* api callbacks */
+ ot->exec = uv_select_linked_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
}
/** \} */
@@ -2792,33 +2921,49 @@ static void UV_OT_select_linked(wmOperatorType *ot)
static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- return uv_select_linked_internal(C, op, event, 1);
+ return uv_select_linked_internal(C, op, event, 1);
}
static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
{
- return uv_select_linked_internal(C, op, NULL, 1);
+ return uv_select_linked_internal(C, op, NULL, 1);
}
static void UV_OT_select_linked_pick(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Linked Pick";
- ot->description = "Select all UV vertices linked under the mouse";
- ot->idname = "UV_OT_select_linked_pick";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = uv_select_linked_pick_invoke;
- ot->exec = uv_select_linked_pick_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0,
- "Extend", "Extend selection rather than clearing the existing selection");
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked UV vertices rather than selecting them");
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
- "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
+ /* identifiers */
+ ot->name = "Select Linked Pick";
+ ot->description = "Select all UV vertices linked under the mouse";
+ ot->idname = "UV_OT_select_linked_pick";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = uv_select_linked_pick_invoke;
+ ot->exec = uv_select_linked_pick_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_boolean(ot->srna,
+ "deselect",
+ 0,
+ "Deselect",
+ "Deselect linked UV vertices rather than selecting them");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
}
/** \} */
@@ -2835,124 +2980,126 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot)
*/
static int uv_select_split_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
+ Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
- bool changed_multi = false;
+ bool changed_multi = false;
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
- bool changed = false;
+ bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- bool is_sel = false;
- bool is_unsel = false;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ bool is_sel = false;
+ bool is_unsel = false;
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
- /* are we all selected? */
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ /* are we all selected? */
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- is_sel = true;
- }
- else {
- is_unsel = true;
- }
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ is_sel = true;
+ }
+ else {
+ is_unsel = true;
+ }
- /* we have mixed selection, bail out */
- if (is_sel && is_unsel) {
- break;
- }
- }
+ /* we have mixed selection, bail out */
+ if (is_sel && is_unsel) {
+ break;
+ }
+ }
- if (is_sel && is_unsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
+ if (is_sel && is_unsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
- changed = true;
- }
- }
+ changed = true;
+ }
+ }
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- }
- }
- MEM_freeN(objects);
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ }
+ }
+ MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-
static void UV_OT_select_split(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Split";
- ot->description = "Select only entirely selected faces";
- ot->idname = "UV_OT_select_split";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Select Split";
+ ot->description = "Select only entirely selected faces";
+ ot->idname = "UV_OT_select_split";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_split_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
+ /* api callbacks */
+ ot->exec = uv_select_split_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
}
static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
{
- /* bmesh API handles flushing but not on de-select */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (select == false) {
- EDBM_deselect_flush(em);
- }
- else {
- EDBM_select_flush(em);
- }
- }
-
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-}
-
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
- else {
- Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
- /* Only for region redraw. */
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
+ /* bmesh API handles flushing but not on de-select */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (select == false) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ EDBM_select_flush(em);
+ }
+ }
+
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+}
+
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
}
/** \} */
@@ -2966,45 +3113,49 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSett
/**
* helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
*/
-static void uv_select_flush_from_tag_sticky_loc_internal(
- Scene *scene, BMEditMesh *em, UvVertMap *vmap,
- const unsigned int efa_index, BMLoop *l,
- const bool select, const int cd_loop_uv_offset)
+static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
+ BMEditMesh *em,
+ UvVertMap *vmap,
+ const unsigned int efa_index,
+ BMLoop *l,
+ const bool select,
+ const int cd_loop_uv_offset)
{
- UvMapVert *start_vlist = NULL, *vlist_iter;
- BMFace *efa_vlist;
+ UvMapVert *start_vlist = NULL, *vlist_iter;
+ BMFace *efa_vlist;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+ vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
- while (vlist_iter) {
- if (vlist_iter->separate)
- start_vlist = vlist_iter;
+ while (vlist_iter) {
+ if (vlist_iter->separate)
+ start_vlist = vlist_iter;
- if (efa_index == vlist_iter->poly_index)
- break;
+ if (efa_index == vlist_iter->poly_index)
+ break;
- vlist_iter = vlist_iter->next;
- }
+ vlist_iter = vlist_iter->next;
+ }
- vlist_iter = start_vlist;
- while (vlist_iter) {
+ vlist_iter = start_vlist;
+ while (vlist_iter) {
- if (vlist_iter != start_vlist && vlist_iter->separate)
- break;
+ if (vlist_iter != start_vlist && vlist_iter->separate)
+ break;
- if (efa_index != vlist_iter->poly_index) {
- BMLoop *l_other;
- efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
- /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
+ if (efa_index != vlist_iter->poly_index) {
+ BMLoop *l_other;
+ efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
+ /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
- l_other = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
+ l_other = BM_iter_at_index(
+ em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
- uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
- }
- vlist_iter = vlist_iter->next;
- }
+ uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
+ }
+ vlist_iter = vlist_iter->next;
+ }
}
/**
@@ -3015,83 +3166,82 @@ static void uv_select_flush_from_tag_sticky_loc_internal(
*
* \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing.
*/
-static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
-{
- /* Selecting UV Faces with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l,
- select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
-
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
- }
- }
- }
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Faces with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ unsigned int efa_index;
+
+ uvedit_pixel_to_float(sima, limit, 0.05);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
}
-
-
/**
* Flush the selection from loop tags based on sticky and selection modes.
*
@@ -3100,83 +3250,83 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
*
* \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing.
*/
-static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
-{
- /* Selecting UV Loops with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l,
- select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
-
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Loops with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ unsigned int efa_index;
+
+ uvedit_pixel_to_float(sima, limit, 0.05);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
}
/** \} */
@@ -3187,144 +3337,144 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
static int uv_box_select_exec(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *ar = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- rctf rectf;
- bool pinned;
- const bool use_face_center = (
- (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get rectangle from operator */
- WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
-
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const bool select = (sel_op != SEL_OP_SUB);
-
- pinned = RNA_boolean_get(op->ptr, "pinned");
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do actual selection */
- if (use_face_center && !pinned) {
- /* handle face selection mode */
- float cent[2];
-
- changed = false;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
-
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (BLI_rctf_isect_pt_v(&rectf, cent)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- /* other selection modes */
- changed = true;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
-
- /* UV_SYNC_SELECTION - can't do pinned selection */
- if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- else if (pinned) {
- if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
-
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ ARegion *ar = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ rctf rectf;
+ bool pinned;
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &rectf);
+ UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
+
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const bool select = (sel_op != SEL_OP_SUB);
+
+ pinned = RNA_boolean_get(op->ptr, "pinned");
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do actual selection */
+ if (use_face_center && !pinned) {
+ /* handle face selection mode */
+ float cent[2];
+
+ changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* assume not touched */
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (BLI_rctf_isect_pt_v(&rectf, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else {
+ /* other selection modes */
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
+
+ /* UV_SYNC_SELECTION - can't do pinned selection */
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ else if (pinned) {
+ if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_select_box(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Box Select";
- ot->description = "Select UV vertices using box selection";
- ot->idname = "UV_OT_select_box";
+ /* identifiers */
+ ot->name = "Box Select";
+ ot->description = "Select UV vertices using box selection";
+ ot->idname = "UV_OT_select_box";
- /* api callbacks */
- ot->invoke = WM_gesture_box_invoke;
- ot->exec = uv_box_select_exec;
- ot->modal = WM_gesture_box_modal;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_box_cancel;
+ /* api callbacks */
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = uv_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_box_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
- /* properties */
- RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
+ /* properties */
+ RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
- WM_operator_properties_gesture_box(ot);
- WM_operator_properties_select_operation_simple(ot);
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -3335,142 +3485,142 @@ static void UV_OT_select_box(wmOperatorType *ot)
static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
{
- /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
- float x, y;
- x = (uv[0] - offset[0]) * ellipse[0];
- y = (uv[1] - offset[1]) * ellipse[1];
- return ((x * x + y * y) < 1.0f);
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ float x, y;
+ x = (uv[0] - offset[0]) * ellipse[0];
+ y = (uv[1] - offset[1]) * ellipse[1];
+ return ((x * x + y * y) < 1.0f);
}
static int uv_circle_select_exec(bContext *C, wmOperator *op)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
- ARegion *ar = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int x, y, radius, width, height;
- float zoomx, zoomy, offset[2], ellipse[2];
-
- const bool use_face_center = (
- (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get operator properties */
- x = RNA_int_get(op->ptr, "x");
- y = RNA_int_get(op->ptr, "y");
- radius = RNA_int_get(op->ptr, "radius");
-
- /* compute ellipse size and location, not a circle since we deal
- * with non square image. ellipse is normalized, r = 1.0. */
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
-
- ellipse[0] = width * zoomx / radius;
- ellipse[1] = height * zoomy / radius;
-
- UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- const eSelectOp sel_op = ED_select_op_modal(
- RNA_enum_get(op->ptr, "mode"), WM_gesture_is_modal_first(op->customdata));
- const bool select = (sel_op != SEL_OP_SUB);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- changed_multi = true;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (use_face_center) {
- changed = false;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (uv_inside_circle(cent, offset, ellipse)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- changed = true;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
+ ARegion *ar = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int x, y, radius, width, height;
+ float zoomx, zoomy, offset[2], ellipse[2];
+
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+
+ /* get operator properties */
+ x = RNA_int_get(op->ptr, "x");
+ y = RNA_int_get(op->ptr, "y");
+ radius = RNA_int_get(op->ptr, "radius");
+
+ /* compute ellipse size and location, not a circle since we deal
+ * with non square image. ellipse is normalized, r = 1.0. */
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
+
+ ellipse[0] = width * zoomx / radius;
+ ellipse[1] = height * zoomy / radius;
+
+ UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
+ WM_gesture_is_modal_first(op->customdata));
+ const bool select = (sel_op != SEL_OP_SUB);
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ changed_multi = true;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (use_face_center) {
+ changed = false;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (uv_inside_circle(cent, offset, ellipse)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_inside_circle(luv->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_select_circle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Circle Select";
- ot->description = "Select UV vertices using circle selection";
- ot->idname = "UV_OT_select_circle";
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select UV vertices using circle selection";
+ ot->idname = "UV_OT_select_circle";
- /* api callbacks */
- ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
- ot->exec = uv_circle_select_exec;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_circle_cancel;
+ /* api callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = uv_circle_select_exec;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_circle_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
- /* properties */
- WM_operator_properties_gesture_circle(ot);
- WM_operator_properties_select_operation_simple(ot);
+ /* properties */
+ WM_operator_properties_gesture_circle(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -3479,148 +3629,148 @@ static void UV_OT_select_circle(wmOperatorType *ot)
/** \name Lasso Select Operator
* \{ */
-static bool do_lasso_select_mesh_uv(
- bContext *C, const int mcords[][2], short moves,
- const eSelectOp sel_op)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool use_face_center = (
- (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
- const bool select = (sel_op != SEL_OP_SUB);
-
- BMIter iter, liter;
-
- BMFace *efa;
- BMLoop *l;
- int screen_uv[2];
- bool changed_multi = false;
- rcti rect;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
-
- bool changed = false;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (use_face_center) { /* Face Center Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else { /* Vert Sel */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(
- &ar->v2d,
- luv->uv[0], luv->uv[1],
- &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- changed = true;
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi;
+static bool do_lasso_select_mesh_uv(bContext *C,
+ const int mcords[][2],
+ short moves,
+ const eSelectOp sel_op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool select = (sel_op != SEL_OP_SUB);
+
+ BMIter iter, liter;
+
+ BMFace *efa;
+ BMLoop *l;
+ int screen_uv[2];
+ bool changed_multi = false;
+ rcti rect;
+
+ BLI_lasso_boundbox(&rect, mcords, moves);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_face_center) { /* Face Center Sel */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ if (UI_view2d_view_to_region_clip(
+ &ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
+ BLI_rcti_isect_pt_v(&rect, screen_uv) &&
+ BLI_lasso_is_point_inside(
+ mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UI_view2d_view_to_region_clip(
+ &ar->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) &&
+ BLI_rcti_isect_pt_v(&rect, screen_uv) &&
+ BLI_lasso_is_point_inside(
+ mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi;
}
static int uv_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcords_tot;
+ const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
- if (mcords) {
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
- MEM_freeN((void *)mcords);
+ if (mcords) {
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
+ MEM_freeN((void *)mcords);
- return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
- }
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
- return OPERATOR_PASS_THROUGH;
+ return OPERATOR_PASS_THROUGH;
}
static void UV_OT_select_lasso(wmOperatorType *ot)
{
- ot->name = "Lasso Select UV";
- ot->description = "Select UVs using lasso selection";
- ot->idname = "UV_OT_select_lasso";
+ ot->name = "Lasso Select UV";
+ ot->description = "Select UVs using lasso selection";
+ ot->idname = "UV_OT_select_lasso";
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_uvedit_space_image;
- ot->cancel = WM_gesture_lasso_cancel;
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = uv_lasso_select_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+ ot->cancel = WM_gesture_lasso_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
- WM_operator_properties_select_operation_simple(ot);
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -3631,78 +3781,78 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
static void uv_snap_to_pixel(float uvco[2], float w, float h)
{
- uvco[0] = roundf(uvco[0] * w) / w;
- uvco[1] = roundf(uvco[1] * h) / h;
+ uvco[0] = roundf(uvco[0] * w) / w;
+ uvco[1] = roundf(uvco[1] * h) / h;
}
static void uv_snap_cursor_to_pixels(SpaceImage *sima)
{
- int width = 0, height = 0;
+ int width = 0, height = 0;
- ED_space_image_get_size(sima, &width, &height);
- uv_snap_to_pixel(sima->cursor, width, height);
+ ED_space_image_get_size(sima, &width, &height);
+ uv_snap_to_pixel(sima->cursor, width, height);
}
static bool uv_snap_cursor_to_selection(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
+ Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
{
- return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
+ return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
- bool changed = false;
+ bool changed = false;
- switch (RNA_enum_get(op->ptr, "target")) {
- case 0:
- uv_snap_cursor_to_pixels(sima);
- changed = true;
- break;
- case 1:
- {
- Scene *scene = CTX_data_scene(C);
- Image *ima = CTX_data_edit_image(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ switch (RNA_enum_get(op->ptr, "target")) {
+ case 0:
+ uv_snap_cursor_to_pixels(sima);
+ changed = true;
+ break;
+ case 1: {
+ Scene *scene = CTX_data_scene(C);
+ Image *ima = CTX_data_edit_image(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
- changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
- MEM_freeN(objects);
- break;
- }
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
+ MEM_freeN(objects);
+ break;
+ }
+ }
- if (!changed)
- return OPERATOR_CANCELLED;
+ if (!changed)
+ return OPERATOR_CANCELLED;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void UV_OT_snap_cursor(wmOperatorType *ot)
{
- static const EnumPropertyItem target_items[] = {
- {0, "PIXELS", 0, "Pixels", ""},
- {1, "SELECTED", 0, "Selected", ""},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem target_items[] = {
+ {0, "PIXELS", 0, "Pixels", ""},
+ {1, "SELECTED", 0, "Selected", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Snap Cursor";
- ot->description = "Snap cursor to target type";
- ot->idname = "UV_OT_snap_cursor";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Snap Cursor";
+ ot->description = "Snap cursor to target type";
+ ot->idname = "UV_OT_snap_cursor";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_snap_cursor_exec;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ /* api callbacks */
+ ot->exec = uv_snap_cursor_exec;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- /* properties */
- RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
+ /* properties */
+ RNA_def_enum(
+ ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
}
/** \} */
@@ -3713,230 +3863,232 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- bool changed = false;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(luv->uv, cursor);
- changed = true;
- }
- }
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, cursor);
+ changed = true;
+ }
+ }
+ }
- return changed;
+ return changed;
}
static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2])
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- bool changed = false;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(luv->uv, offset);
- changed = true;
- }
- }
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(luv->uv, offset);
+ changed = true;
+ }
+ }
+ }
- return changed;
+ return changed;
}
static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMLoop *l, *lsub;
- BMIter iter, liter, lsubiter;
- MLoopUV *luv;
- bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- /* index every vert that has a selected UV using it, but only once so as to
- * get unique indices and to count how much to malloc */
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, f)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
- }
- }
- else {
- BM_elem_flag_disable(f, BM_ELEM_TAG);
- }
- }
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/
- float uv[2] = {0.0f, 0.0f};
- int uv_tot = 0;
-
- BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
- if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */
- !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */
- {
- luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset);
- add_v2_v2(uv, luv->uv);
- uv_tot++;
- }
- }
-
- if (uv_tot) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
- changed = true;
- }
- }
- }
- }
- }
-
- return changed;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *lsub;
+ BMIter iter, liter, lsubiter;
+ MLoopUV *luv;
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ /* index every vert that has a selected UV using it, but only once so as to
+ * get unique indices and to count how much to malloc */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, f)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
+ }
+ }
+ else {
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+ }
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/
+ float uv[2] = {0.0f, 0.0f};
+ int uv_tot = 0;
+
+ BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */
+ !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */
+ {
+ luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ uv_tot++;
+ }
+ }
+
+ if (uv_tot) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
}
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Image *ima = sima->image;
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int width = 0, height = 0;
- float w, h;
- bool changed = false;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ Image *ima = sima->image;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int width = 0, height = 0;
+ float w, h;
+ bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- ED_space_image_get_size(sima, &width, &height);
- w = (float)width;
- h = (float)height;
+ ED_space_image_get_size(sima, &width, &height);
+ w = (float)width;
+ h = (float)height;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uv_snap_to_pixel(luv->uv, w, h);
- }
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ uv_snap_to_pixel(luv->uv, w, h);
+ }
+ }
- changed = true;
- }
+ changed = true;
+ }
- return changed;
+ return changed;
}
static int uv_snap_selection_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- const int target = RNA_enum_get(op->ptr, "target");
- float offset[2] = {0};
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- if (target == 2) {
- float center[2];
- if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
- sub_v2_v2v2(offset, sima->cursor, center);
- }
-
- bool changed_multi = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- bool changed = false;
- switch (target) {
- case 0:
- changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
- break;
- case 1:
- changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
- break;
- case 2:
- changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
- break;
- case 3:
- changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
- break;
- }
-
- if (changed) {
- changed_multi = true;
- uvedit_live_unwrap_update(sima, scene, obedit);
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ const int target = RNA_enum_get(op->ptr, "target");
+ float offset[2] = {0};
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (target == 2) {
+ float center[2];
+ if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+ sub_v2_v2v2(offset, sima->cursor, center);
+ }
+
+ bool changed_multi = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ bool changed = false;
+ switch (target) {
+ case 0:
+ changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
+ break;
+ case 1:
+ changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
+ break;
+ case 2:
+ changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
+ break;
+ case 3:
+ changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+ break;
+ }
+
+ if (changed) {
+ changed_multi = true;
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_snap_selected(wmOperatorType *ot)
{
- static const EnumPropertyItem target_items[] = {
- {0, "PIXELS", 0, "Pixels", ""},
- {1, "CURSOR", 0, "Cursor", ""},
- {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""},
- {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
- {0, NULL, 0, NULL, NULL},
- };
+ static const EnumPropertyItem target_items[] = {
+ {0, "PIXELS", 0, "Pixels", ""},
+ {1, "CURSOR", 0, "Cursor", ""},
+ {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""},
+ {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
- /* identifiers */
- ot->name = "Snap Selection";
- ot->description = "Snap selected UV vertices to target type";
- ot->idname = "UV_OT_snap_selected";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Snap Selection";
+ ot->description = "Snap selected UV vertices to target type";
+ ot->idname = "UV_OT_snap_selected";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_snap_selection_exec;
- ot->poll = ED_operator_uvedit_space_image;
+ /* api callbacks */
+ ot->exec = uv_snap_selection_exec;
+ ot->poll = ED_operator_uvedit_space_image;
- /* properties */
- RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
+ /* properties */
+ RNA_def_enum(
+ ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
}
/** \} */
@@ -3947,75 +4099,78 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
static int uv_pin_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- ToolSettings *ts = scene->toolsettings;
- const bool clear = RNA_boolean_get(op->ptr, "clear");
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- changed = true;
- if (clear) {
- luv->flag &= ~MLOOPUV_PINNED;
- }
- else {
- luv->flag |= MLOOPUV_PINNED;
- }
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ ToolSettings *ts = scene->toolsettings;
+ const bool clear = RNA_boolean_get(op->ptr, "clear");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ changed = true;
+ if (clear) {
+ luv->flag &= ~MLOOPUV_PINNED;
+ }
+ else {
+ luv->flag |= MLOOPUV_PINNED;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
static void UV_OT_pin(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Pin";
- ot->description = "Set/clear selected UV vertices as anchored between multiple unwrap operations";
- ot->idname = "UV_OT_pin";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Pin";
+ ot->description =
+ "Set/clear selected UV vertices as anchored between multiple unwrap operations";
+ ot->idname = "UV_OT_pin";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_pin_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_pin_exec;
+ ot->poll = ED_operator_uvedit;
- /* properties */
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
}
/** \} */
@@ -4026,61 +4181,62 @@ static void UV_OT_pin(wmOperatorType *ot)
static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = CTX_data_edit_image(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ bool changed = false;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_PINNED) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- changed = true;
- }
- }
- }
+ if (luv->flag & MLOOPUV_PINNED) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ }
- if (changed) {
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void UV_OT_select_pinned(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Selected Pinned";
- ot->description = "Select all pinned UV vertices";
- ot->idname = "UV_OT_select_pinned";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Selected Pinned";
+ ot->description = "Select all pinned UV vertices";
+ ot->idname = "UV_OT_select_pinned";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_select_pinned_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_select_pinned_exec;
+ ot->poll = ED_operator_uvedit;
}
/** \} */
@@ -4091,137 +4247,138 @@ static void UV_OT_select_pinned(wmOperatorType *ot)
/* check if we are selected or unselected based on 'bool_test' arg,
* needed for select swap support */
-#define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
+#define UV_SEL_TEST(luv, bool_test) \
+ ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
/* is every UV vert selected or unselected depending on bool_test */
-static bool bm_face_is_all_uv_sel(
- BMFace *f, bool select_test,
- const int cd_loop_uv_offset)
+static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset)
{
- BMLoop *l_iter;
- BMLoop *l_first;
+ BMLoop *l_iter;
+ BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
- if (!UV_SEL_TEST(luv, select_test)) {
- return false;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ if (!UV_SEL_TEST(luv, select_test)) {
+ return false;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
- return true;
+ return true;
}
static int uv_hide_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- const bool swap = RNA_boolean_get(op->ptr, "unselected");
- Image *ima = sima ? sima->image : NULL;
- const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_hide(em, swap)) {
- EDBM_update_generic(em, true, false);
- }
- return OPERATOR_FINISHED;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- int hide = 0;
-
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (UV_SEL_TEST(luv, !swap)) {
- hide = 1;
- break;
- }
- }
-
- if (hide) {
- /* note, a special case for edges could be used,
- * for now edges act like verts and get flushed */
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- /* check that every UV is selected */
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_face_select_set(em->bm, efa, false);
- }
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
- else {
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
- }
- }
- }
- if (!swap) uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- /* check if a UV is de-selected */
- if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
- BM_face_select_set(em->bm, efa, false);
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
- if (!swap) luv->flag &= ~MLOOPUV_VERTSEL;
- }
- }
- }
- }
- }
-
- /* flush vertex selection changes */
- if (em->selectmode != SCE_SELECT_FACE)
- EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
-
- BM_select_history_validate(em->bm);
-
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ const bool swap = RNA_boolean_get(op->ptr, "unselected");
+ Image *ima = sima ? sima->image : NULL;
+ const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_hide(em, swap)) {
+ EDBM_update_generic(em, true, false);
+ }
+ return OPERATOR_FINISHED;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ int hide = 0;
+
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (UV_SEL_TEST(luv, !swap)) {
+ hide = 1;
+ break;
+ }
+ }
+
+ if (hide) {
+ /* note, a special case for edges could be used,
+ * for now edges act like verts and get flushed */
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
+ /* check that every UV is selected */
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+ else {
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
+ }
+ }
+ if (!swap)
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+ }
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ /* check if a UV is de-selected */
+ if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
+ BM_face_select_set(em->bm, efa, false);
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ if (!swap)
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+ }
+ }
+ }
+ }
+
+ /* flush vertex selection changes */
+ if (em->selectmode != SCE_SELECT_FACE)
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
+
+ BM_select_history_validate(em->bm);
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
}
#undef UV_SEL_TEST
static void UV_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->description = "Hide (un)selected UV vertices";
- ot->idname = "UV_OT_hide";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->description = "Hide (un)selected UV vertices";
+ ot->idname = "UV_OT_hide";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_hide_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_hide_exec;
+ ot->poll = ED_operator_uvedit;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
/** \} */
@@ -4232,136 +4389,136 @@ static void UV_OT_hide(wmOperatorType *ot)
static int uv_reveal_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
- const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- const bool select = RNA_boolean_get(op->ptr, "select");
-
- /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
- * confuse our checks on selected verts. */
-
- /* call the mesh function if we are in mesh sync sel */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(em, true, false);
- }
- return OPERATOR_FINISHED;
- }
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- }
- }
- else {
- /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
- if (!stickymode) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- int totsel = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
- }
-
- if (!totsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- }
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- }
- }
- }
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- }
- }
-
- /* re-select tagged faces */
- BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
-
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
+ const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ const bool select = RNA_boolean_get(op->ptr, "select");
+
+ /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
+ * confuse our checks on selected verts. */
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_reveal(em, select)) {
+ EDBM_update_generic(em, true, false);
+ }
+ return OPERATOR_FINISHED;
+ }
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ else {
+ /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
+ if (!stickymode) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ int totsel = 0;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ }
+
+ if (!totsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* re-select tagged faces */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
}
static void UV_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reveal Hidden";
- ot->description = "Reveal all hidden UV vertices";
- ot->idname = "UV_OT_reveal";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Reveal Hidden";
+ ot->description = "Reveal all hidden UV vertices";
+ ot->idname = "UV_OT_reveal";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_reveal_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_reveal_exec;
+ ot->poll = ED_operator_uvedit;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
/** \} */
@@ -4372,60 +4529,67 @@ static void UV_OT_reveal(wmOperatorType *ot)
static bool uv_set_2d_cursor_poll(bContext *C)
{
- return ED_operator_uvedit_space_image(C) ||
- ED_space_image_maskedit_poll(C) ||
- ED_space_image_paint_curve(C);
+ return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
}
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
- if (!sima)
- return OPERATOR_CANCELLED;
+ if (!sima)
+ return OPERATOR_CANCELLED;
- RNA_float_get_array(op->ptr, "location", sima->cursor);
+ RNA_float_get_array(op->ptr, "location", sima->cursor);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ARegion *ar = CTX_wm_region(C);
- float location[2];
+ ARegion *ar = CTX_wm_region(C);
+ float location[2];
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16) {
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima && ED_space_image_show_cache(sima)) {
- return OPERATOR_PASS_THROUGH;
- }
- }
- }
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (event->mval[1] <= 16) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima && ED_space_image_show_cache(sima)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
- RNA_float_set_array(op->ptr, "location", location);
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
+ RNA_float_set_array(op->ptr, "location", location);
- return uv_set_2d_cursor_exec(C, op);
+ return uv_set_2d_cursor_exec(C, op);
}
static void UV_OT_cursor_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set 2D Cursor";
- ot->description = "Set 2D cursor location";
- ot->idname = "UV_OT_cursor_set";
-
- /* api callbacks */
- ot->exec = uv_set_2d_cursor_exec;
- ot->invoke = uv_set_2d_cursor_invoke;
- ot->poll = uv_set_2d_cursor_poll;
-
- /* properties */
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
- "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
+ /* identifiers */
+ ot->name = "Set 2D Cursor";
+ ot->description = "Set 2D cursor location";
+ ot->idname = "UV_OT_cursor_set";
+
+ /* api callbacks */
+ ot->exec = uv_set_2d_cursor_exec;
+ ot->invoke = uv_set_2d_cursor_invoke;
+ ot->poll = uv_set_2d_cursor_poll;
+
+ /* properties */
+ RNA_def_float_vector(ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Cursor location in normalized (0.0-1.0) coordinates",
+ -10.0f,
+ 10.0f);
}
/** \} */
@@ -4436,136 +4600,136 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- int ret = OPERATOR_CANCELLED;
- const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
- const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
- const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *em = me->edit_mesh;
- BMesh *bm = em->bm;
-
- UvVertMap *vmap;
- BMEdge *editedge;
- BMIter iter;
-
- if (!EDBM_uv_check(em)) {
- continue;
- }
- ret = OPERATOR_FINISHED;
-
- /* This code sets editvert->tmp.l to the index. This will be useful later on. */
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, limit, false, false);
-
- BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
- /* flags to determine if we uv is separated from first editface match */
- char separated1 = 0, separated2;
- /* set to denote edge must be flagged as seam */
- char faces_separated = 0;
- /* flag to keep track if uv1 is disconnected from first editface match */
- char v1coincident = 1;
- /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
- int commonFaces = 0;
-
- BMFace *efa1, *efa2;
-
- UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
- /* mv2cache stores the first of the list of coincident uv's for later comparison
- * mv2sep holds the last separator and is copied to mv2cache
- * when a hit is first found */
- UvMapVert *mv2cache = NULL, *mv2sep = NULL;
-
- mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
- if (mark_seams)
- BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
-
- for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
- if (mv1->separate && commonFaces)
- v1coincident = 0;
-
- separated2 = 0;
- efa1 = BM_face_at_index(bm, mv1->poly_index);
- mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
-
- for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
- if (mv2->separate)
- mv2sep = mv2;
-
- efa2 = BM_face_at_index(bm, mv2->poly_index);
- if (efa1 == efa2) {
- /* if v1 is not coincident no point in comparing */
- if (v1coincident) {
- /* have we found previously anything? */
- if (mv2cache) {
- /* flag seam unless proved to be coincident with previous hit */
- separated2 = 1;
- for (mviter = mv2cache; mviter; mviter = mviter->next) {
- if (mviter->separate && mviter != mv2cache)
- break;
- /* coincident with previous hit, do not flag seam */
- if (mviter == mv2)
- separated2 = 0;
- }
- }
- /* First hit case, store the hit in the cache */
- else {
- mv2cache = mv2sep;
- commonFaces = 1;
- }
- }
- else
- separated1 = 1;
-
- if (separated1 || separated2) {
- faces_separated = 1;
- break;
- }
- }
- }
- }
-
- if (faces_separated) {
- if (mark_seams)
- BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
- if (mark_sharp)
- BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
- }
- }
-
- BM_uv_vert_map_free(vmap);
-
- DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
- }
- MEM_freeN(objects);
-
- return ret;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int ret = OPERATOR_CANCELLED;
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+ const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
+ const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ BMesh *bm = em->bm;
+
+ UvVertMap *vmap;
+ BMEdge *editedge;
+ BMIter iter;
+
+ if (!EDBM_uv_check(em)) {
+ continue;
+ }
+ ret = OPERATOR_FINISHED;
+
+ /* This code sets editvert->tmp.l to the index. This will be useful later on. */
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(bm, limit, false, false);
+
+ BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
+ /* flags to determine if we uv is separated from first editface match */
+ char separated1 = 0, separated2;
+ /* set to denote edge must be flagged as seam */
+ char faces_separated = 0;
+ /* flag to keep track if uv1 is disconnected from first editface match */
+ char v1coincident = 1;
+ /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
+ int commonFaces = 0;
+
+ BMFace *efa1, *efa2;
+
+ UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
+ /* mv2cache stores the first of the list of coincident uv's for later comparison
+ * mv2sep holds the last separator and is copied to mv2cache
+ * when a hit is first found */
+ UvMapVert *mv2cache = NULL, *mv2sep = NULL;
+
+ mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
+ if (mark_seams)
+ BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
+
+ for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
+ if (mv1->separate && commonFaces)
+ v1coincident = 0;
+
+ separated2 = 0;
+ efa1 = BM_face_at_index(bm, mv1->poly_index);
+ mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
+
+ for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
+ if (mv2->separate)
+ mv2sep = mv2;
+
+ efa2 = BM_face_at_index(bm, mv2->poly_index);
+ if (efa1 == efa2) {
+ /* if v1 is not coincident no point in comparing */
+ if (v1coincident) {
+ /* have we found previously anything? */
+ if (mv2cache) {
+ /* flag seam unless proved to be coincident with previous hit */
+ separated2 = 1;
+ for (mviter = mv2cache; mviter; mviter = mviter->next) {
+ if (mviter->separate && mviter != mv2cache)
+ break;
+ /* coincident with previous hit, do not flag seam */
+ if (mviter == mv2)
+ separated2 = 0;
+ }
+ }
+ /* First hit case, store the hit in the cache */
+ else {
+ mv2cache = mv2sep;
+ commonFaces = 1;
+ }
+ }
+ else
+ separated1 = 1;
+
+ if (separated1 || separated2) {
+ faces_separated = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (faces_separated) {
+ if (mark_seams)
+ BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
+ if (mark_sharp)
+ BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
+ }
+ }
+
+ BM_uv_vert_map_free(vmap);
+
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
+ MEM_freeN(objects);
+
+ return ret;
}
-
static void UV_OT_seams_from_islands(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Seams From Islands";
- ot->description = "Set mesh seams according to island setup in the UV editor";
- ot->idname = "UV_OT_seams_from_islands";
+ /* identifiers */
+ ot->name = "Seams From Islands";
+ ot->description = "Set mesh seams according to island setup in the UV editor";
+ ot->idname = "UV_OT_seams_from_islands";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_seams_from_islands_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_seams_from_islands_exec;
+ ot->poll = ED_operator_uvedit;
- RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
- RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
+ RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
+ RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
}
/** \} */
@@ -4576,95 +4740,106 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
- BMFace *efa;
- BMLoop *loop;
- BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *loop;
+ BMIter iter, liter;
- const bool flag_set = !RNA_boolean_get(op->ptr, "clear");
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ const bool flag_set = !RNA_boolean_get(op->ptr, "clear");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- bool changed = false;
+ bool changed = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *em = me->edit_mesh;
- BMesh *bm = em->bm;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ BMesh *bm = em->bm;
- if (synced_selection && (bm->totedgesel == 0)) {
- continue;
- }
+ if (synced_selection && (bm->totedgesel == 0)) {
+ continue;
+ }
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
- changed = true;
- }
- }
- }
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
+ BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
+ changed = true;
+ }
+ }
+ }
- if (changed) {
- DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
- }
- }
+ if (changed) {
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
+ }
- if (changed) {
- ED_uvedit_live_unwrap(scene, objects, objects_len);
- }
+ if (changed) {
+ ED_uvedit_live_unwrap(scene, objects, objects_len);
+ }
- MEM_freeN(objects);
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- uiPopupMenu *pup;
- uiLayout *layout;
+ uiPopupMenu *pup;
+ uiLayout *layout;
- if (RNA_struct_property_is_set(op->ptr, "clear")) {
- return uv_mark_seam_exec(C, op);
- }
+ if (RNA_struct_property_is_set(op->ptr, "clear")) {
+ return uv_mark_seam_exec(C, op);
+ }
- pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
+ pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
- uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), ICON_NONE, op->type->idname, "clear", false);
- uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), ICON_NONE, op->type->idname, "clear", true);
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+ uiItemBooleanO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"),
+ ICON_NONE,
+ op->type->idname,
+ "clear",
+ false);
+ uiItemBooleanO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"),
+ ICON_NONE,
+ op->type->idname,
+ "clear",
+ true);
- UI_popup_menu_end(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_INTERFACE;
+ return OPERATOR_INTERFACE;
}
static void UV_OT_mark_seam(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Mark Seam";
- ot->description = "Mark selected UV edges as seams";
- ot->idname = "UV_OT_mark_seam";
+ /* identifiers */
+ ot->name = "Mark Seam";
+ ot->description = "Mark selected UV edges as seams";
+ ot->idname = "UV_OT_mark_seam";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = uv_mark_seam_exec;
- ot->invoke = uv_mark_seam_invoke;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = uv_mark_seam_exec;
+ ot->invoke = uv_mark_seam_invoke;
+ ot->poll = ED_operator_uvedit;
- RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
+ RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
}
/** \} */
@@ -4675,54 +4850,54 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
void ED_operatortypes_uvedit(void)
{
- WM_operatortype_append(UV_OT_select_all);
- WM_operatortype_append(UV_OT_select);
- WM_operatortype_append(UV_OT_select_loop);
- WM_operatortype_append(UV_OT_select_linked);
- WM_operatortype_append(UV_OT_select_linked_pick);
- WM_operatortype_append(UV_OT_select_split);
- WM_operatortype_append(UV_OT_select_pinned);
- WM_operatortype_append(UV_OT_select_box);
- WM_operatortype_append(UV_OT_select_lasso);
- WM_operatortype_append(UV_OT_select_circle);
- WM_operatortype_append(UV_OT_select_more);
- WM_operatortype_append(UV_OT_select_less);
+ WM_operatortype_append(UV_OT_select_all);
+ WM_operatortype_append(UV_OT_select);
+ WM_operatortype_append(UV_OT_select_loop);
+ WM_operatortype_append(UV_OT_select_linked);
+ WM_operatortype_append(UV_OT_select_linked_pick);
+ WM_operatortype_append(UV_OT_select_split);
+ WM_operatortype_append(UV_OT_select_pinned);
+ WM_operatortype_append(UV_OT_select_box);
+ WM_operatortype_append(UV_OT_select_lasso);
+ WM_operatortype_append(UV_OT_select_circle);
+ WM_operatortype_append(UV_OT_select_more);
+ WM_operatortype_append(UV_OT_select_less);
- WM_operatortype_append(UV_OT_snap_cursor);
- WM_operatortype_append(UV_OT_snap_selected);
+ WM_operatortype_append(UV_OT_snap_cursor);
+ WM_operatortype_append(UV_OT_snap_selected);
- WM_operatortype_append(UV_OT_align);
+ WM_operatortype_append(UV_OT_align);
- WM_operatortype_append(UV_OT_stitch);
+ WM_operatortype_append(UV_OT_stitch);
- WM_operatortype_append(UV_OT_seams_from_islands);
- WM_operatortype_append(UV_OT_mark_seam);
- WM_operatortype_append(UV_OT_weld);
- WM_operatortype_append(UV_OT_remove_doubles);
- WM_operatortype_append(UV_OT_pin);
+ WM_operatortype_append(UV_OT_seams_from_islands);
+ WM_operatortype_append(UV_OT_mark_seam);
+ WM_operatortype_append(UV_OT_weld);
+ WM_operatortype_append(UV_OT_remove_doubles);
+ WM_operatortype_append(UV_OT_pin);
- WM_operatortype_append(UV_OT_average_islands_scale);
- WM_operatortype_append(UV_OT_cube_project);
- WM_operatortype_append(UV_OT_cylinder_project);
- WM_operatortype_append(UV_OT_project_from_view);
- WM_operatortype_append(UV_OT_minimize_stretch);
- WM_operatortype_append(UV_OT_pack_islands);
- WM_operatortype_append(UV_OT_reset);
- WM_operatortype_append(UV_OT_sphere_project);
- WM_operatortype_append(UV_OT_unwrap);
+ WM_operatortype_append(UV_OT_average_islands_scale);
+ WM_operatortype_append(UV_OT_cube_project);
+ WM_operatortype_append(UV_OT_cylinder_project);
+ WM_operatortype_append(UV_OT_project_from_view);
+ WM_operatortype_append(UV_OT_minimize_stretch);
+ WM_operatortype_append(UV_OT_pack_islands);
+ WM_operatortype_append(UV_OT_reset);
+ WM_operatortype_append(UV_OT_sphere_project);
+ WM_operatortype_append(UV_OT_unwrap);
- WM_operatortype_append(UV_OT_reveal);
- WM_operatortype_append(UV_OT_hide);
+ WM_operatortype_append(UV_OT_reveal);
+ WM_operatortype_append(UV_OT_hide);
- WM_operatortype_append(UV_OT_cursor_set);
+ WM_operatortype_append(UV_OT_cursor_set);
}
void ED_keymap_uvedit(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
+ wmKeyMap *keymap;
- keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0);
- keymap->poll = ED_operator_uvedit_can_uv_sculpt;
+ keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0);
+ keymap->poll = ED_operator_uvedit_can_uv_sculpt;
}
/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 1a4e040472e..69183d02ab9 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -37,7 +37,7 @@
#include <stdio.h>
#include <string.h>
-#include "BLI_sys_types.h" /* for intptr_t support */
+#include "BLI_sys_types.h" /* for intptr_t support */
#include "eigen_capi.h"
@@ -50,22 +50,25 @@
# define param_test_equals_int(condition)
#else
# define param_assert(condition) \
- if (!(condition)) \
- { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ } (void)0
+ if (!(condition)) { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ \
+ } \
+ (void)0
# define param_warning(message) \
- { /*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/ } (void)0
+ {/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0
# if 0
# define param_test_equals_ptr(str, a, b) \
- if (a != b) \
- { /*printf("Equals %s => %p != %p\n", str, a, b);*/ } (void)0
+ if (a != b) { /*printf("Equals %s => %p != %p\n", str, a, b);*/ \
+ } \
+ (void)0
# define param_test_equals_int(str, a, b) \
- if (a != b) \
- { /*printf("Equals %s => %d != %d\n", str, a, b);*/ } (void)0
+ if (a != b) { /*printf("Equals %s => %d != %d\n", str, a, b);*/ \
+ } \
+ (void)0
# endif
#endif
typedef enum PBool {
- P_TRUE = 1,
- P_FALSE = 0,
+ P_TRUE = 1,
+ P_FALSE = 0,
} PBool;
/* Special Purpose Hash */
@@ -73,18 +76,16 @@ typedef enum PBool {
typedef intptr_t PHashKey;
typedef struct PHashLink {
- struct PHashLink *next;
- PHashKey key;
+ struct PHashLink *next;
+ PHashKey key;
} PHashLink;
typedef struct PHash {
- PHashLink **list;
- PHashLink **buckets;
- int size, cursize, cursize_id;
+ PHashLink **list;
+ PHashLink **buckets;
+ int size, cursize, cursize_id;
} PHash;
-
-
struct PChart;
struct PEdge;
struct PFace;
@@ -94,142 +95,142 @@ struct PVert;
/* Simplices */
typedef struct PVert {
- struct PVert *nextlink;
+ struct PVert *nextlink;
- union PVertUnion {
- PHashKey key; /* construct */
- int id; /* abf/lscm matrix index */
- float distortion; /* area smoothing */
- HeapNode *heaplink; /* edge collapsing */
- } u;
+ union PVertUnion {
+ PHashKey key; /* construct */
+ int id; /* abf/lscm matrix index */
+ float distortion; /* area smoothing */
+ HeapNode *heaplink; /* edge collapsing */
+ } u;
- struct PEdge *edge;
- float co[3];
- float uv[2];
- unsigned char flag;
+ struct PEdge *edge;
+ float co[3];
+ float uv[2];
+ unsigned char flag;
} PVert;
typedef struct PEdge {
- struct PEdge *nextlink;
-
- union PEdgeUnion {
- PHashKey key; /* construct */
- int id; /* abf matrix index */
- HeapNode *heaplink; /* fill holes */
- struct PEdge *nextcollapse; /* simplification */
- } u;
-
- struct PVert *vert;
- struct PEdge *pair;
- struct PEdge *next;
- struct PFace *face;
- float *orig_uv, old_uv[2];
- unsigned short flag;
+ struct PEdge *nextlink;
+
+ union PEdgeUnion {
+ PHashKey key; /* construct */
+ int id; /* abf matrix index */
+ HeapNode *heaplink; /* fill holes */
+ struct PEdge *nextcollapse; /* simplification */
+ } u;
+
+ struct PVert *vert;
+ struct PEdge *pair;
+ struct PEdge *next;
+ struct PFace *face;
+ float *orig_uv, old_uv[2];
+ unsigned short flag;
} PEdge;
typedef struct PFace {
- struct PFace *nextlink;
+ struct PFace *nextlink;
- union PFaceUnion {
- PHashKey key; /* construct */
- int chart; /* construct splitting*/
- float area3d; /* stretch */
- int id; /* abf matrix index */
- } u;
+ union PFaceUnion {
+ PHashKey key; /* construct */
+ int chart; /* construct splitting*/
+ float area3d; /* stretch */
+ int id; /* abf matrix index */
+ } u;
- struct PEdge *edge;
- unsigned char flag;
+ struct PEdge *edge;
+ unsigned char flag;
} PFace;
enum PVertFlag {
- PVERT_PIN = 1,
- PVERT_SELECT = 2,
- PVERT_INTERIOR = 4,
- PVERT_COLLAPSE = 8,
- PVERT_SPLIT = 16,
+ PVERT_PIN = 1,
+ PVERT_SELECT = 2,
+ PVERT_INTERIOR = 4,
+ PVERT_COLLAPSE = 8,
+ PVERT_SPLIT = 16,
};
enum PEdgeFlag {
- PEDGE_SEAM = 1,
- PEDGE_VERTEX_SPLIT = 2,
- PEDGE_PIN = 4,
- PEDGE_SELECT = 8,
- PEDGE_DONE = 16,
- PEDGE_FILLED = 32,
- PEDGE_COLLAPSE = 64,
- PEDGE_COLLAPSE_EDGE = 128,
- PEDGE_COLLAPSE_PAIR = 256,
+ PEDGE_SEAM = 1,
+ PEDGE_VERTEX_SPLIT = 2,
+ PEDGE_PIN = 4,
+ PEDGE_SELECT = 8,
+ PEDGE_DONE = 16,
+ PEDGE_FILLED = 32,
+ PEDGE_COLLAPSE = 64,
+ PEDGE_COLLAPSE_EDGE = 128,
+ PEDGE_COLLAPSE_PAIR = 256,
};
/* for flipping faces */
#define PEDGE_VERTEX_FLAGS (PEDGE_PIN)
enum PFaceFlag {
- PFACE_CONNECTED = 1,
- PFACE_FILLED = 2,
- PFACE_COLLAPSE = 4,
+ PFACE_CONNECTED = 1,
+ PFACE_FILLED = 2,
+ PFACE_COLLAPSE = 4,
};
/* Chart */
typedef struct PChart {
- PVert *verts;
- PEdge *edges;
- PFace *faces;
- int nverts, nedges, nfaces;
-
- PVert *collapsed_verts;
- PEdge *collapsed_edges;
- PFace *collapsed_faces;
-
- union PChartUnion {
- struct PChartLscm {
- LinearSolver *context;
- float *abf_alpha;
- PVert *pin1, *pin2;
- } lscm;
- struct PChartPack {
- float rescale, area;
- float size[2] /* , trans[2] */;
- } pack;
- } u;
-
- unsigned char flag;
- struct PHandle *handle;
+ PVert *verts;
+ PEdge *edges;
+ PFace *faces;
+ int nverts, nedges, nfaces;
+
+ PVert *collapsed_verts;
+ PEdge *collapsed_edges;
+ PFace *collapsed_faces;
+
+ union PChartUnion {
+ struct PChartLscm {
+ LinearSolver *context;
+ float *abf_alpha;
+ PVert *pin1, *pin2;
+ } lscm;
+ struct PChartPack {
+ float rescale, area;
+ float size[2] /* , trans[2] */;
+ } pack;
+ } u;
+
+ unsigned char flag;
+ struct PHandle *handle;
} PChart;
enum PChartFlag {
- PCHART_HAS_PINS = 1,
+ PCHART_HAS_PINS = 1,
};
enum PHandleState {
- PHANDLE_STATE_ALLOCATED,
- PHANDLE_STATE_CONSTRUCTED,
- PHANDLE_STATE_LSCM,
- PHANDLE_STATE_STRETCH,
+ PHANDLE_STATE_ALLOCATED,
+ PHANDLE_STATE_CONSTRUCTED,
+ PHANDLE_STATE_LSCM,
+ PHANDLE_STATE_STRETCH,
};
typedef struct PHandle {
- enum PHandleState state;
- MemArena *arena;
- MemArena *polyfill_arena;
- Heap *polyfill_heap;
+ enum PHandleState state;
+ MemArena *arena;
+ MemArena *polyfill_arena;
+ Heap *polyfill_heap;
- PChart *construction_chart;
- PHash *hash_verts;
- PHash *hash_edges;
- PHash *hash_faces;
+ PChart *construction_chart;
+ PHash *hash_verts;
+ PHash *hash_edges;
+ PHash *hash_faces;
- PChart **charts;
- int ncharts;
+ PChart **charts;
+ int ncharts;
- float aspx, aspy;
+ float aspx, aspy;
- RNG *rng;
- float blend;
- char do_aspect;
+ RNG *rng;
+ float blend;
+ char do_aspect;
} PHandle;
/* PHash
@@ -239,315 +240,319 @@ typedef struct PHandle {
*/
static int PHashSizes[] = {
- 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
- 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521,
+ 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309,
+ 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
};
-#define PHASH_hash(ph, item) (((uintptr_t) (item)) % ((unsigned int) (ph)->cursize))
-#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1) * 39) ^ ((v2) * 31) : ((v1) * 31) ^ ((v2) * 39))
+#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((unsigned int)(ph)->cursize))
+#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39))
static PHash *phash_new(PHashLink **list, int sizehint)
{
- PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash");
- ph->size = 0;
- ph->cursize_id = 0;
- ph->list = list;
+ PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash");
+ ph->size = 0;
+ ph->cursize_id = 0;
+ ph->list = list;
- while (PHashSizes[ph->cursize_id] < sizehint)
- ph->cursize_id++;
+ while (PHashSizes[ph->cursize_id] < sizehint)
+ ph->cursize_id++;
- ph->cursize = PHashSizes[ph->cursize_id];
- ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
+ ph->cursize = PHashSizes[ph->cursize_id];
+ ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
- return ph;
+ return ph;
}
static void phash_delete(PHash *ph)
{
- MEM_freeN(ph->buckets);
- MEM_freeN(ph);
+ MEM_freeN(ph->buckets);
+ MEM_freeN(ph);
}
static int phash_size(PHash *ph)
{
- return ph->size;
+ return ph->size;
}
static void phash_insert(PHash *ph, PHashLink *link)
{
- int size = ph->cursize;
- uintptr_t hash = PHASH_hash(ph, link->key);
- PHashLink *lookup = ph->buckets[hash];
+ int size = ph->cursize;
+ uintptr_t hash = PHASH_hash(ph, link->key);
+ PHashLink *lookup = ph->buckets[hash];
- if (lookup == NULL) {
- /* insert in front of the list */
- ph->buckets[hash] = link;
- link->next = *(ph->list);
- *(ph->list) = link;
- }
- else {
- /* insert after existing element */
- link->next = lookup->next;
- lookup->next = link;
- }
+ if (lookup == NULL) {
+ /* insert in front of the list */
+ ph->buckets[hash] = link;
+ link->next = *(ph->list);
+ *(ph->list) = link;
+ }
+ else {
+ /* insert after existing element */
+ link->next = lookup->next;
+ lookup->next = link;
+ }
- ph->size++;
+ ph->size++;
- if (ph->size > (size * 3)) {
- PHashLink *next = NULL, *first = *(ph->list);
+ if (ph->size > (size * 3)) {
+ PHashLink *next = NULL, *first = *(ph->list);
- ph->cursize = PHashSizes[++ph->cursize_id];
- MEM_freeN(ph->buckets);
- ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
- ph->size = 0;
- *(ph->list) = NULL;
+ ph->cursize = PHashSizes[++ph->cursize_id];
+ MEM_freeN(ph->buckets);
+ ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets");
+ ph->size = 0;
+ *(ph->list) = NULL;
- for (link = first; link; link = next) {
- next = link->next;
- phash_insert(ph, link);
- }
- }
+ for (link = first; link; link = next) {
+ next = link->next;
+ phash_insert(ph, link);
+ }
+ }
}
static PHashLink *phash_lookup(PHash *ph, PHashKey key)
{
- PHashLink *link;
- uintptr_t hash = PHASH_hash(ph, key);
+ PHashLink *link;
+ uintptr_t hash = PHASH_hash(ph, key);
- for (link = ph->buckets[hash]; link; link = link->next)
- if (link->key == key)
- return link;
- else if (PHASH_hash(ph, link->key) != hash)
- return NULL;
+ for (link = ph->buckets[hash]; link; link = link->next)
+ if (link->key == key)
+ return link;
+ else if (PHASH_hash(ph, link->key) != hash)
+ return NULL;
- return link;
+ return link;
}
static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
{
- uintptr_t hash = PHASH_hash(ph, key);
+ uintptr_t hash = PHASH_hash(ph, key);
- for (link = link->next; link; link = link->next)
- if (link->key == key)
- return link;
- else if (PHASH_hash(ph, link->key) != hash)
- return NULL;
+ for (link = link->next; link; link = link->next)
+ if (link->key == key)
+ return link;
+ else if (PHASH_hash(ph, link->key) != hash)
+ return NULL;
- return link;
+ return link;
}
/* Geometry */
static float p_vec_angle_cos(float *v1, float *v2, float *v3)
{
- float d1[3], d2[3];
+ float d1[3], d2[3];
- d1[0] = v1[0] - v2[0];
- d1[1] = v1[1] - v2[1];
- d1[2] = v1[2] - v2[2];
+ d1[0] = v1[0] - v2[0];
+ d1[1] = v1[1] - v2[1];
+ d1[2] = v1[2] - v2[2];
- d2[0] = v3[0] - v2[0];
- d2[1] = v3[1] - v2[1];
- d2[2] = v3[2] - v2[2];
+ d2[0] = v3[0] - v2[0];
+ d2[1] = v3[1] - v2[1];
+ d2[2] = v3[2] - v2[2];
- normalize_v3(d1);
- normalize_v3(d2);
+ normalize_v3(d1);
+ normalize_v3(d2);
- return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2];
+ return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2];
}
static float p_vec_angle(float *v1, float *v2, float *v3)
{
- float dot = p_vec_angle_cos(v1, v2, v3);
+ float dot = p_vec_angle_cos(v1, v2, v3);
- if (dot <= -1.0f)
- return (float)M_PI;
- else if (dot >= 1.0f)
- return 0.0f;
- else
- return acosf(dot);
+ if (dot <= -1.0f)
+ return (float)M_PI;
+ else if (dot >= 1.0f)
+ return 0.0f;
+ else
+ return acosf(dot);
}
static float p_vec2_angle(float *v1, float *v2, float *v3)
{
- float u1[3], u2[3], u3[3];
+ float u1[3], u2[3], u3[3];
- u1[0] = v1[0]; u1[1] = v1[1]; u1[2] = 0.0f;
- u2[0] = v2[0]; u2[1] = v2[1]; u2[2] = 0.0f;
- u3[0] = v3[0]; u3[1] = v3[1]; u3[2] = 0.0f;
+ u1[0] = v1[0];
+ u1[1] = v1[1];
+ u1[2] = 0.0f;
+ u2[0] = v2[0];
+ u2[1] = v2[1];
+ u2[2] = 0.0f;
+ u3[0] = v3[0];
+ u3[1] = v3[1];
+ u3[2] = 0.0f;
- return p_vec_angle(u1, u2, u3);
+ return p_vec_angle(u1, u2, u3);
}
static void p_triangle_angles(float *v1, float *v2, float *v3, float *a1, float *a2, float *a3)
{
- *a1 = p_vec_angle(v3, v1, v2);
- *a2 = p_vec_angle(v1, v2, v3);
- *a3 = (float)M_PI - *a2 - *a1;
+ *a1 = p_vec_angle(v3, v1, v2);
+ *a2 = p_vec_angle(v1, v2, v3);
+ *a3 = (float)M_PI - *a2 - *a1;
}
static void p_face_angles(PFace *f, float *a1, float *a2, float *a3)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3);
+ p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3);
}
static float p_face_area(PFace *f)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- return area_tri_v3(v1->co, v2->co, v3->co);
+ return area_tri_v3(v1->co, v2->co, v3->co);
}
static float p_area_signed(float *v1, float *v2, float *v3)
{
- return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) -
- ((v3[0] - v1[0]) * (v2[1] - v1[1])));
+ return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) - ((v3[0] - v1[0]) * (v2[1] - v1[1])));
}
static float p_face_uv_area_signed(PFace *f)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) -
- ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1])));
+ return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) -
+ ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1])));
}
static float p_edge_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
+ PVert *v1 = e->vert, *v2 = e->next->vert;
+ float d[3];
- d[0] = v2->co[0] - v1->co[0];
- d[1] = v2->co[1] - v1->co[1];
- d[2] = v2->co[2] - v1->co[2];
+ d[0] = v2->co[0] - v1->co[0];
+ d[1] = v2->co[1] - v1->co[1];
+ d[2] = v2->co[2] - v1->co[2];
- return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
}
static float p_edge_uv_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
+ PVert *v1 = e->vert, *v2 = e->next->vert;
+ float d[3];
- d[0] = v2->uv[0] - v1->uv[0];
- d[1] = v2->uv[1] - v1->uv[1];
+ d[0] = v2->uv[0] - v1->uv[0];
+ d[1] = v2->uv[1] - v1->uv[1];
- return sqrtf(d[0] * d[0] + d[1] * d[1]);
+ return sqrtf(d[0] * d[0] + d[1] * d[1]);
}
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
{
- PVert *v;
+ PVert *v;
- INIT_MINMAX2(minv, maxv);
+ INIT_MINMAX2(minv, maxv);
- for (v = chart->verts; v; v = v->nextlink) {
- minmax_v2v2_v2(minv, maxv, v->uv);
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ minmax_v2v2_v2(minv, maxv, v->uv);
+ }
}
static void p_chart_uv_scale(PChart *chart, float scale)
{
- PVert *v;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] *= scale;
- v->uv[1] *= scale;
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->uv[0] *= scale;
+ v->uv[1] *= scale;
+ }
}
static void p_chart_uv_scale_xy(PChart *chart, float x, float y)
{
- PVert *v;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] *= x;
- v->uv[1] *= y;
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->uv[0] *= x;
+ v->uv[1] *= y;
+ }
}
static void p_chart_uv_translate(PChart *chart, float trans[2])
{
- PVert *v;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] += trans[0];
- v->uv[1] += trans[1];
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->uv[0] += trans[0];
+ v->uv[1] += trans[1];
+ }
}
static void p_chart_uv_transform(PChart *chart, float mat[2][2])
{
- PVert *v;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- mul_m2v2(mat, v->uv);
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ mul_m2v2(mat, v->uv);
+ }
}
static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
{
- PVert *v;
- unsigned int i = 0;
+ PVert *v;
+ unsigned int i = 0;
- for (v = chart->verts; v; v = v->nextlink) {
- copy_v2_v2(points[i++], v->uv);
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ copy_v2_v2(points[i++], v->uv);
+ }
}
static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
{
- PVert *v;
- unsigned int i = 0;
+ PVert *v;
+ unsigned int i = 0;
- for (v = chart->verts; v; v = v->nextlink) {
- copy_v2_v2(v->uv, points[i++]);
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ copy_v2_v2(v->uv, points[i++]);
+ }
}
-
static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *dir2, float *isect)
{
- float lmbda, div;
+ float lmbda, div;
- div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
+ div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
- if (div == 0.0f)
- return P_FALSE;
+ if (div == 0.0f)
+ return P_FALSE;
- lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
- isect[0] = v1[0] + lmbda * dir2[0];
- isect[1] = v1[1] + lmbda * dir2[1];
+ lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
+ isect[0] = v1[0] + lmbda * dir2[0];
+ isect[1] = v1[1] + lmbda * dir2[1];
- return P_TRUE;
+ return P_TRUE;
}
#if 0
static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, float *isect)
{
- float dir1[2], dir2[2];
+ float dir1[2], dir2[2];
- dir1[0] = v4[0] - v3[0];
- dir1[1] = v4[1] - v3[1];
+ dir1[0] = v4[0] - v3[0];
+ dir1[1] = v4[1] - v3[1];
- dir2[0] = v2[0] - v1[0];
- dir2[1] = v2[1] - v1[1];
+ dir2[0] = v2[0] - v1[0];
+ dir2[1] = v2[1] - v1[1];
- if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
- /* parallel - should never happen in theory for polygon kernel, but
- * let's give a point nearby in case things go wrong */
- isect[0] = (v1[0] + v2[0]) * 0.5f;
- isect[1] = (v1[1] + v2[1]) * 0.5f;
- return P_FALSE;
- }
+ if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
+ /* parallel - should never happen in theory for polygon kernel, but
+ * let's give a point nearby in case things go wrong */
+ isect[0] = (v1[0] + v2[0]) * 0.5f;
+ isect[1] = (v1[1] + v2[1]) * 0.5f;
+ return P_FALSE;
+ }
- return P_TRUE;
+ return P_TRUE;
}
#endif
@@ -555,75 +560,75 @@ static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, flo
static PEdge *p_wheel_edge_next(PEdge *e)
{
- return e->next->next->pair;
+ return e->next->next->pair;
}
static PEdge *p_wheel_edge_prev(PEdge *e)
{
- return (e->pair) ? e->pair->next : NULL;
+ return (e->pair) ? e->pair->next : NULL;
}
static PEdge *p_boundary_edge_next(PEdge *e)
{
- return e->next->vert->edge;
+ return e->next->vert->edge;
}
static PEdge *p_boundary_edge_prev(PEdge *e)
{
- PEdge *we = e, *last;
+ PEdge *we = e, *last;
- do {
- last = we;
- we = p_wheel_edge_next(we);
- } while (we && (we != e));
+ do {
+ last = we;
+ we = p_wheel_edge_next(we);
+ } while (we && (we != e));
- return last->next->next;
+ return last->next->next;
}
static PBool p_vert_interior(PVert *v)
{
- return (v->edge->pair != NULL);
+ return (v->edge->pair != NULL);
}
static void p_face_flip(PFace *f)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag;
- float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag;
+ float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv;
- e1->vert = v2;
- e1->next = e3;
- e1->orig_uv = orig_uv2;
- e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS);
+ e1->vert = v2;
+ e1->next = e3;
+ e1->orig_uv = orig_uv2;
+ e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS);
- e2->vert = v3;
- e2->next = e1;
- e2->orig_uv = orig_uv3;
- e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS);
+ e2->vert = v3;
+ e2->next = e1;
+ e2->orig_uv = orig_uv3;
+ e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS);
- e3->vert = v1;
- e3->next = e2;
- e3->orig_uv = orig_uv1;
- e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS);
+ e3->vert = v1;
+ e3->next = e2;
+ e3->orig_uv = orig_uv1;
+ e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS);
}
#if 0
static void p_chart_topological_sanity_check(PChart *chart)
{
- PVert *v;
- PEdge *e;
+ PVert *v;
+ PEdge *e;
- for (v = chart->verts; v; v = v->nextlink)
- param_test_equals_ptr("v->edge->vert", v, v->edge->vert);
+ for (v = chart->verts; v; v = v->nextlink)
+ param_test_equals_ptr("v->edge->vert", v, v->edge->vert);
- for (e = chart->edges; e; e = e->nextlink) {
- if (e->pair) {
- param_test_equals_ptr("e->pair->pair", e, e->pair->pair);
- param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert);
- param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert);
- }
- }
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (e->pair) {
+ param_test_equals_ptr("e->pair->pair", e, e->pair->pair);
+ param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert);
+ param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert);
+ }
+ }
}
#endif
@@ -631,737 +636,748 @@ static void p_chart_topological_sanity_check(PChart *chart)
static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v)
{
- PEdge *e;
- int nedges = 0, npins = 0;
- float pinuv[2];
-
- v->uv[0] = v->uv[1] = 0.0f;
- pinuv[0] = pinuv[1] = 0.0f;
- e = v->edge;
- do {
- if (e->orig_uv) {
- if (e->flag & PEDGE_SELECT)
- v->flag |= PVERT_SELECT;
-
- if (e->flag & PEDGE_PIN) {
- pinuv[0] += e->orig_uv[0] * handle->aspx;
- pinuv[1] += e->orig_uv[1] * handle->aspy;
- npins++;
- }
- else {
- v->uv[0] += e->orig_uv[0] * handle->aspx;
- v->uv[1] += e->orig_uv[1] * handle->aspy;
- }
-
- nedges++;
- }
-
- e = p_wheel_edge_next(e);
- } while (e && e != (v->edge));
-
- if (npins > 0) {
- v->uv[0] = pinuv[0] / npins;
- v->uv[1] = pinuv[1] / npins;
- v->flag |= PVERT_PIN;
- }
- else if (nedges > 0) {
- v->uv[0] /= nedges;
- v->uv[1] /= nedges;
- }
+ PEdge *e;
+ int nedges = 0, npins = 0;
+ float pinuv[2];
+
+ v->uv[0] = v->uv[1] = 0.0f;
+ pinuv[0] = pinuv[1] = 0.0f;
+ e = v->edge;
+ do {
+ if (e->orig_uv) {
+ if (e->flag & PEDGE_SELECT)
+ v->flag |= PVERT_SELECT;
+
+ if (e->flag & PEDGE_PIN) {
+ pinuv[0] += e->orig_uv[0] * handle->aspx;
+ pinuv[1] += e->orig_uv[1] * handle->aspy;
+ npins++;
+ }
+ else {
+ v->uv[0] += e->orig_uv[0] * handle->aspx;
+ v->uv[1] += e->orig_uv[1] * handle->aspy;
+ }
+
+ nedges++;
+ }
+
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
+
+ if (npins > 0) {
+ v->uv[0] = pinuv[0] / npins;
+ v->uv[1] = pinuv[1] / npins;
+ v->flag |= PVERT_PIN;
+ }
+ else if (nedges > 0) {
+ v->uv[0] /= nedges;
+ v->uv[1] /= nedges;
+ }
}
static void p_flush_uvs(PHandle *handle, PChart *chart)
{
- PEdge *e;
+ PEdge *e;
- for (e = chart->edges; e; e = e->nextlink) {
- if (e->orig_uv) {
- e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
- e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
- }
- }
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (e->orig_uv) {
+ e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
+ e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
+ }
+ }
}
static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
{
- PEdge *e;
- float invblend = 1.0f - blend;
+ PEdge *e;
+ float invblend = 1.0f - blend;
- for (e = chart->edges; e; e = e->nextlink) {
- if (e->orig_uv) {
- e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx;
- e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy;
- }
- }
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (e->orig_uv) {
+ e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx;
+ e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy;
+ }
+ }
}
static void p_face_backup_uvs(PFace *f)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- if (e1->orig_uv) {
- e1->old_uv[0] = e1->orig_uv[0];
- e1->old_uv[1] = e1->orig_uv[1];
- }
- if (e2->orig_uv) {
- e2->old_uv[0] = e2->orig_uv[0];
- e2->old_uv[1] = e2->orig_uv[1];
- }
- if (e3->orig_uv) {
- e3->old_uv[0] = e3->orig_uv[0];
- e3->old_uv[1] = e3->orig_uv[1];
- }
+ if (e1->orig_uv) {
+ e1->old_uv[0] = e1->orig_uv[0];
+ e1->old_uv[1] = e1->orig_uv[1];
+ }
+ if (e2->orig_uv) {
+ e2->old_uv[0] = e2->orig_uv[0];
+ e2->old_uv[1] = e2->orig_uv[1];
+ }
+ if (e3->orig_uv) {
+ e3->old_uv[0] = e3->orig_uv[0];
+ e3->old_uv[1] = e3->orig_uv[1];
+ }
}
static void p_face_restore_uvs(PFace *f)
{
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- if (e1->orig_uv) {
- e1->orig_uv[0] = e1->old_uv[0];
- e1->orig_uv[1] = e1->old_uv[1];
- }
- if (e2->orig_uv) {
- e2->orig_uv[0] = e2->old_uv[0];
- e2->orig_uv[1] = e2->old_uv[1];
- }
- if (e3->orig_uv) {
- e3->orig_uv[0] = e3->old_uv[0];
- e3->orig_uv[1] = e3->old_uv[1];
- }
+ if (e1->orig_uv) {
+ e1->orig_uv[0] = e1->old_uv[0];
+ e1->orig_uv[1] = e1->old_uv[1];
+ }
+ if (e2->orig_uv) {
+ e2->orig_uv[0] = e2->old_uv[0];
+ e2->orig_uv[1] = e2->old_uv[1];
+ }
+ if (e3->orig_uv) {
+ e3->orig_uv[0] = e3->old_uv[0];
+ e3->orig_uv[1] = e3->old_uv[1];
+ }
}
/* Construction (use only during construction, relies on u.key being set */
static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
- PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
- copy_v3_v3(v->co, co);
+ PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v));
+ copy_v3_v3(v->co, co);
- /* Sanity check, a single nan/inf point causes the entire result to be invalid.
- * Note that values within the calculation may _become_ non-finite,
- * so the rest of the code still needs to take this possibility into account. */
- for (int i = 0; i < 3; i++) {
- if (UNLIKELY(!isfinite(v->co[i]))) {
- v->co[i] = 0.0f;
- }
- }
+ /* Sanity check, a single nan/inf point causes the entire result to be invalid.
+ * Note that values within the calculation may _become_ non-finite,
+ * so the rest of the code still needs to take this possibility into account. */
+ for (int i = 0; i < 3; i++) {
+ if (UNLIKELY(!isfinite(v->co[i]))) {
+ v->co[i] = 0.0f;
+ }
+ }
- v->u.key = key;
- v->edge = e;
- v->flag = 0;
+ v->u.key = key;
+ v->edge = e;
+ v->flag = 0;
- phash_insert(handle->hash_verts, (PHashLink *)v);
+ phash_insert(handle->hash_verts, (PHashLink *)v);
- return v;
+ return v;
}
static PVert *p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e)
{
- PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
+ PVert *v = (PVert *)phash_lookup(handle->hash_verts, key);
- if (v)
- return v;
- else
- return p_vert_add(handle, key, co, e);
+ if (v)
+ return v;
+ else
+ return p_vert_add(handle, key, co, e);
}
static PVert *p_vert_copy(PChart *chart, PVert *v)
{
- PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv));
+ PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv));
- copy_v3_v3(nv->co, v->co);
- nv->uv[0] = v->uv[0];
- nv->uv[1] = v->uv[1];
- nv->u.key = v->u.key;
- nv->edge = v->edge;
- nv->flag = v->flag;
+ copy_v3_v3(nv->co, v->co);
+ nv->uv[0] = v->uv[0];
+ nv->uv[1] = v->uv[1];
+ nv->u.key = v->u.key;
+ nv->edge = v->edge;
+ nv->flag = v->flag;
- return nv;
+ return nv;
}
static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys)
{
- PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
- PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
+ PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
+ PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
- while (e) {
- if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1]))
- return e;
- else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0]))
- return e;
+ while (e) {
+ if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1]))
+ return e;
+ else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0]))
+ return e;
- e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
- }
+ e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
+ }
- return NULL;
+ return NULL;
}
static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3)
{
- PHandle *handle = (PHandle *)phandle;
- PHashKey *vkeys = (PHashKey *)pvkeys;
- PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
- PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
+ PHandle *handle = (PHandle *)phandle;
+ PHashKey *vkeys = (PHashKey *)pvkeys;
+ PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
+ PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key);
- while (e) {
- if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
- if (e->next->next->vert->u.key == vkeys[i3])
- return P_TRUE;
- }
- else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
- if (e->next->next->vert->u.key == vkeys[i3])
- return P_TRUE;
- }
+ while (e) {
+ if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
+ if (e->next->next->vert->u.key == vkeys[i3])
+ return P_TRUE;
+ }
+ else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
+ if (e->next->next->vert->u.key == vkeys[i3])
+ return P_TRUE;
+ }
- e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
- }
+ e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
+ }
- return P_FALSE;
+ return P_FALSE;
}
static PChart *p_chart_new(PHandle *handle)
{
- PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
- chart->handle = handle;
+ PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart");
+ chart->handle = handle;
- return chart;
+ return chart;
}
static void p_chart_delete(PChart *chart)
{
- /* the actual links are free by memarena */
- MEM_freeN(chart);
+ /* the actual links are free by memarena */
+ MEM_freeN(chart);
}
static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
{
- float *uv1, *uv2, *uvp1, *uvp2;
- float limit[2];
+ float *uv1, *uv2, *uvp1, *uvp2;
+ float limit[2];
- limit[0] = 0.00001;
- limit[1] = 0.00001;
+ limit[0] = 0.00001;
+ limit[1] = 0.00001;
- uv1 = e->orig_uv;
- uv2 = e->next->orig_uv;
+ uv1 = e->orig_uv;
+ uv2 = e->next->orig_uv;
- if (e->vert->u.key == ep->vert->u.key) {
- uvp1 = ep->orig_uv;
- uvp2 = ep->next->orig_uv;
- }
- else {
- uvp1 = ep->next->orig_uv;
- uvp2 = ep->orig_uv;
- }
+ if (e->vert->u.key == ep->vert->u.key) {
+ uvp1 = ep->orig_uv;
+ uvp2 = ep->next->orig_uv;
+ }
+ else {
+ uvp1 = ep->next->orig_uv;
+ uvp2 = ep->orig_uv;
+ }
- if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
- e->flag |= PEDGE_SEAM;
- ep->flag |= PEDGE_SEAM;
- return P_TRUE;
- }
- if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
- e->flag |= PEDGE_SEAM;
- ep->flag |= PEDGE_SEAM;
- return P_TRUE;
- }
+ if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
+ e->flag |= PEDGE_SEAM;
+ ep->flag |= PEDGE_SEAM;
+ return P_TRUE;
+ }
+ if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
+ e->flag |= PEDGE_SEAM;
+ ep->flag |= PEDGE_SEAM;
+ return P_TRUE;
+ }
- return P_FALSE;
+ return P_FALSE;
}
static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PEdge **pair, PBool impl)
{
- PHashKey key;
- PEdge *pe;
- PVert *v1, *v2;
- PHashKey key1 = e->vert->u.key;
- PHashKey key2 = e->next->vert->u.key;
+ PHashKey key;
+ PEdge *pe;
+ PVert *v1, *v2;
+ PHashKey key1 = e->vert->u.key;
+ PHashKey key2 = e->next->vert->u.key;
- if (e->flag & PEDGE_SEAM)
- return P_FALSE;
+ if (e->flag & PEDGE_SEAM)
+ return P_FALSE;
- key = PHASH_edge(key1, key2);
- pe = (PEdge *)phash_lookup(handle->hash_edges, key);
- *pair = NULL;
+ key = PHASH_edge(key1, key2);
+ pe = (PEdge *)phash_lookup(handle->hash_edges, key);
+ *pair = NULL;
- while (pe) {
- if (pe != e) {
- v1 = pe->vert;
- v2 = pe->next->vert;
+ while (pe) {
+ if (pe != e) {
+ v1 = pe->vert;
+ v2 = pe->next->vert;
- if (((v1->u.key == key1) && (v2->u.key == key2)) ||
- ((v1->u.key == key2) && (v2->u.key == key1)))
- {
+ if (((v1->u.key == key1) && (v2->u.key == key2)) ||
+ ((v1->u.key == key2) && (v2->u.key == key1))) {
- /* don't connect seams and t-junctions */
- if ((pe->flag & PEDGE_SEAM) || *pair ||
- (impl && p_edge_implicit_seam(e, pe)))
- {
- *pair = NULL;
- return P_FALSE;
- }
+ /* don't connect seams and t-junctions */
+ if ((pe->flag & PEDGE_SEAM) || *pair || (impl && p_edge_implicit_seam(e, pe))) {
+ *pair = NULL;
+ return P_FALSE;
+ }
- *pair = pe;
- }
- }
+ *pair = pe;
+ }
+ }
- pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe);
- }
+ pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe);
+ }
- if (*pair && (e->vert == (*pair)->vert)) {
- if ((*pair)->next->pair || (*pair)->next->next->pair) {
- /* non unfoldable, maybe mobius ring or klein bottle */
- *pair = NULL;
- return P_FALSE;
- }
- }
+ if (*pair && (e->vert == (*pair)->vert)) {
+ if ((*pair)->next->pair || (*pair)->next->next->pair) {
+ /* non unfoldable, maybe mobius ring or klein bottle */
+ *pair = NULL;
+ return P_FALSE;
+ }
+ }
- return (*pair != NULL);
+ return (*pair != NULL);
}
static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PEdge ***stack, PBool impl)
{
- PEdge *pair = NULL;
+ PEdge *pair = NULL;
- if (!e->pair && p_edge_has_pair(handle, e, &pair, impl)) {
- if (e->vert == pair->vert)
- p_face_flip(pair->face);
+ if (!e->pair && p_edge_has_pair(handle, e, &pair, impl)) {
+ if (e->vert == pair->vert)
+ p_face_flip(pair->face);
- e->pair = pair;
- pair->pair = e;
+ e->pair = pair;
+ pair->pair = e;
- if (!(pair->face->flag & PFACE_CONNECTED)) {
- **stack = pair;
- (*stack)++;
- }
- }
+ if (!(pair->face->flag & PFACE_CONNECTED)) {
+ **stack = pair;
+ (*stack)++;
+ }
+ }
- return (e->pair != NULL);
+ return (e->pair != NULL);
}
static int p_connect_pairs(PHandle *handle, PBool impl)
{
- PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), "Pstackbase");
- PEdge **stack = stackbase;
- PFace *f, *first;
- PEdge *e, *e1, *e2;
- PChart *chart = handle->construction_chart;
- int ncharts = 0;
+ PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
+ "Pstackbase");
+ PEdge **stack = stackbase;
+ PFace *f, *first;
+ PEdge *e, *e1, *e2;
+ PChart *chart = handle->construction_chart;
+ int ncharts = 0;
- /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */
- for (first = chart->faces; first; first = first->nextlink) {
- if (first->flag & PFACE_CONNECTED)
- continue;
+ /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */
+ for (first = chart->faces; first; first = first->nextlink) {
+ if (first->flag & PFACE_CONNECTED)
+ continue;
- *stack = first->edge;
- stack++;
+ *stack = first->edge;
+ stack++;
- while (stack != stackbase) {
- stack--;
- e = *stack;
- e1 = e->next;
- e2 = e1->next;
+ while (stack != stackbase) {
+ stack--;
+ e = *stack;
+ e1 = e->next;
+ e2 = e1->next;
- f = e->face;
- f->flag |= PFACE_CONNECTED;
+ f = e->face;
+ f->flag |= PFACE_CONNECTED;
- /* assign verts to charts so we can sort them later */
- f->u.chart = ncharts;
+ /* assign verts to charts so we can sort them later */
+ f->u.chart = ncharts;
- if (!p_edge_connect_pair(handle, e, &stack, impl))
- e->vert->edge = e;
- if (!p_edge_connect_pair(handle, e1, &stack, impl))
- e1->vert->edge = e1;
- if (!p_edge_connect_pair(handle, e2, &stack, impl))
- e2->vert->edge = e2;
- }
+ if (!p_edge_connect_pair(handle, e, &stack, impl))
+ e->vert->edge = e;
+ if (!p_edge_connect_pair(handle, e1, &stack, impl))
+ e1->vert->edge = e1;
+ if (!p_edge_connect_pair(handle, e2, &stack, impl))
+ e2->vert->edge = e2;
+ }
- ncharts++;
- }
+ ncharts++;
+ }
- MEM_freeN(stackbase);
+ MEM_freeN(stackbase);
- return ncharts;
+ return ncharts;
}
static void p_split_vert(PChart *chart, PEdge *e)
{
- PEdge *we, *lastwe = NULL;
- PVert *v = e->vert;
- PBool copy = P_TRUE;
+ PEdge *we, *lastwe = NULL;
+ PVert *v = e->vert;
+ PBool copy = P_TRUE;
- if (e->flag & PEDGE_PIN) {
- chart->flag |= PCHART_HAS_PINS;
- }
+ if (e->flag & PEDGE_PIN) {
+ chart->flag |= PCHART_HAS_PINS;
+ }
- if (e->flag & PEDGE_VERTEX_SPLIT)
- return;
+ if (e->flag & PEDGE_VERTEX_SPLIT)
+ return;
- /* rewind to start */
- lastwe = e;
- for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we))
- lastwe = we;
+ /* rewind to start */
+ lastwe = e;
+ for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we))
+ lastwe = we;
- /* go over all edges in wheel */
- for (we = lastwe; we; we = p_wheel_edge_next(we)) {
- if (we->flag & PEDGE_VERTEX_SPLIT)
- break;
+ /* go over all edges in wheel */
+ for (we = lastwe; we; we = p_wheel_edge_next(we)) {
+ if (we->flag & PEDGE_VERTEX_SPLIT)
+ break;
- we->flag |= PEDGE_VERTEX_SPLIT;
+ we->flag |= PEDGE_VERTEX_SPLIT;
- if (we == v->edge) {
- /* found it, no need to copy */
- copy = P_FALSE;
- v->nextlink = chart->verts;
- chart->verts = v;
- chart->nverts++;
- }
- }
+ if (we == v->edge) {
+ /* found it, no need to copy */
+ copy = P_FALSE;
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
+ }
- if (copy) {
- /* not found, copying */
- v->flag |= PVERT_SPLIT;
- v = p_vert_copy(chart, v);
- v->flag |= PVERT_SPLIT;
+ if (copy) {
+ /* not found, copying */
+ v->flag |= PVERT_SPLIT;
+ v = p_vert_copy(chart, v);
+ v->flag |= PVERT_SPLIT;
- v->nextlink = chart->verts;
- chart->verts = v;
- chart->nverts++;
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
- v->edge = lastwe;
+ v->edge = lastwe;
- we = lastwe;
- do {
- we->vert = v;
- we = p_wheel_edge_next(we);
- } while (we && (we != lastwe));
- }
+ we = lastwe;
+ do {
+ we->vert = v;
+ we = p_wheel_edge_next(we);
+ } while (we && (we != lastwe));
+ }
}
static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
{
- PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart;
- PFace *f, *nextf;
- int i;
+ PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart;
+ PFace *f, *nextf;
+ int i;
- for (i = 0; i < ncharts; i++)
- charts[i] = p_chart_new(handle);
+ for (i = 0; i < ncharts; i++)
+ charts[i] = p_chart_new(handle);
- f = chart->faces;
- while (f) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- nextf = f->nextlink;
+ f = chart->faces;
+ while (f) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ nextf = f->nextlink;
- nchart = charts[f->u.chart];
+ nchart = charts[f->u.chart];
- f->nextlink = nchart->faces;
- nchart->faces = f;
- e1->nextlink = nchart->edges;
- nchart->edges = e1;
- e2->nextlink = nchart->edges;
- nchart->edges = e2;
- e3->nextlink = nchart->edges;
- nchart->edges = e3;
+ f->nextlink = nchart->faces;
+ nchart->faces = f;
+ e1->nextlink = nchart->edges;
+ nchart->edges = e1;
+ e2->nextlink = nchart->edges;
+ nchart->edges = e2;
+ e3->nextlink = nchart->edges;
+ nchart->edges = e3;
- nchart->nfaces++;
- nchart->nedges += 3;
+ nchart->nfaces++;
+ nchart->nedges += 3;
- p_split_vert(nchart, e1);
- p_split_vert(nchart, e2);
- p_split_vert(nchart, e3);
+ p_split_vert(nchart, e1);
+ p_split_vert(nchart, e2);
+ p_split_vert(nchart, e3);
- f = nextf;
- }
+ f = nextf;
+ }
- return charts;
+ return charts;
}
static PFace *p_face_add(PHandle *handle)
{
- PFace *f;
- PEdge *e1, *e2, *e3;
+ PFace *f;
+ PEdge *e1, *e2, *e3;
- /* allocate */
- f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f));
- f->flag = 0; /* init ! */
+ /* allocate */
+ f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f));
+ f->flag = 0; /* init ! */
- e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1));
- e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2));
- e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3));
+ e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1));
+ e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2));
+ e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3));
- /* set up edges */
- f->edge = e1;
- e1->face = e2->face = e3->face = f;
+ /* set up edges */
+ f->edge = e1;
+ e1->face = e2->face = e3->face = f;
- e1->next = e2;
- e2->next = e3;
- e3->next = e1;
+ e1->next = e2;
+ e2->next = e3;
+ e3->next = e1;
- e1->pair = NULL;
- e2->pair = NULL;
- e3->pair = NULL;
+ e1->pair = NULL;
+ e2->pair = NULL;
+ e3->pair = NULL;
- e1->flag = 0;
- e2->flag = 0;
- e3->flag = 0;
+ e1->flag = 0;
+ e2->flag = 0;
+ e3->flag = 0;
- return f;
+ return f;
}
-static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkeys,
- float *co[4], float *uv[4], int i1, int i2, int i3,
- ParamBool *pin, ParamBool *select)
+static PFace *p_face_add_construct(PHandle *handle,
+ ParamKey key,
+ ParamKey *vkeys,
+ float *co[4],
+ float *uv[4],
+ int i1,
+ int i2,
+ int i3,
+ ParamBool *pin,
+ ParamBool *select)
{
- PFace *f = p_face_add(handle);
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PFace *f = p_face_add(handle);
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1);
- e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2);
- e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3);
+ e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1);
+ e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2);
+ e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3);
- e1->orig_uv = uv[i1];
- e2->orig_uv = uv[i2];
- e3->orig_uv = uv[i3];
+ e1->orig_uv = uv[i1];
+ e2->orig_uv = uv[i2];
+ e3->orig_uv = uv[i3];
- if (pin) {
- if (pin[i1]) e1->flag |= PEDGE_PIN;
- if (pin[i2]) e2->flag |= PEDGE_PIN;
- if (pin[i3]) e3->flag |= PEDGE_PIN;
- }
+ if (pin) {
+ if (pin[i1])
+ e1->flag |= PEDGE_PIN;
+ if (pin[i2])
+ e2->flag |= PEDGE_PIN;
+ if (pin[i3])
+ e3->flag |= PEDGE_PIN;
+ }
- if (select) {
- if (select[i1]) e1->flag |= PEDGE_SELECT;
- if (select[i2]) e2->flag |= PEDGE_SELECT;
- if (select[i3]) e3->flag |= PEDGE_SELECT;
- }
+ if (select) {
+ if (select[i1])
+ e1->flag |= PEDGE_SELECT;
+ if (select[i2])
+ e2->flag |= PEDGE_SELECT;
+ if (select[i3])
+ e3->flag |= PEDGE_SELECT;
+ }
- /* insert into hash */
- f->u.key = key;
- phash_insert(handle->hash_faces, (PHashLink *)f);
+ /* insert into hash */
+ f->u.key = key;
+ phash_insert(handle->hash_faces, (PHashLink *)f);
- e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]);
- e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]);
- e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]);
+ e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]);
+ e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]);
+ e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]);
- phash_insert(handle->hash_edges, (PHashLink *)e1);
- phash_insert(handle->hash_edges, (PHashLink *)e2);
- phash_insert(handle->hash_edges, (PHashLink *)e3);
+ phash_insert(handle->hash_edges, (PHashLink *)e1);
+ phash_insert(handle->hash_edges, (PHashLink *)e2);
+ phash_insert(handle->hash_edges, (PHashLink *)e3);
- return f;
+ return f;
}
static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
{
- PFace *f = p_face_add(chart->handle);
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PFace *f = p_face_add(chart->handle);
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- e1->vert = v1;
- e2->vert = v2;
- e3->vert = v3;
+ e1->vert = v1;
+ e2->vert = v2;
+ e3->vert = v3;
- e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL;
+ e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL;
- f->nextlink = chart->faces;
- chart->faces = f;
- e1->nextlink = chart->edges;
- chart->edges = e1;
- e2->nextlink = chart->edges;
- chart->edges = e2;
- e3->nextlink = chart->edges;
- chart->edges = e3;
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ e1->nextlink = chart->edges;
+ chart->edges = e1;
+ e2->nextlink = chart->edges;
+ chart->edges = e2;
+ e3->nextlink = chart->edges;
+ chart->edges = e3;
- chart->nfaces++;
- chart->nedges += 3;
+ chart->nfaces++;
+ chart->nedges += 3;
- return f;
+ return f;
}
static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
{
- /* slight bias to prefer one edge over the other in case they are equal, so
- * that in symmetric models we choose the same split direction instead of
- * depending on floating point errors to decide */
- float bias = 1.0f + 1e-6f;
- float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]);
- PBool dir = (fac <= 0.0f);
-
- /* the face exists check is there because of a special case: when
- * two quads share three vertices, they can each be split into two
- * triangles, resulting in two identical triangles. for example in
- * suzanne's nose. */
- if (dir) {
- if (p_face_exists(handle, vkeys, 0, 1, 2) || p_face_exists(handle, vkeys, 0, 2, 3))
- return !dir;
- }
- else {
- if (p_face_exists(handle, vkeys, 0, 1, 3) || p_face_exists(handle, vkeys, 1, 2, 3))
- return !dir;
- }
-
- return dir;
+ /* slight bias to prefer one edge over the other in case they are equal, so
+ * that in symmetric models we choose the same split direction instead of
+ * depending on floating point errors to decide */
+ float bias = 1.0f + 1e-6f;
+ float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]);
+ PBool dir = (fac <= 0.0f);
+
+ /* the face exists check is there because of a special case: when
+ * two quads share three vertices, they can each be split into two
+ * triangles, resulting in two identical triangles. for example in
+ * suzanne's nose. */
+ if (dir) {
+ if (p_face_exists(handle, vkeys, 0, 1, 2) || p_face_exists(handle, vkeys, 0, 2, 3))
+ return !dir;
+ }
+ else {
+ if (p_face_exists(handle, vkeys, 0, 1, 3) || p_face_exists(handle, vkeys, 1, 2, 3))
+ return !dir;
+ }
+
+ return dir;
}
/* Construction: boundary filling */
static void p_chart_boundaries(PChart *chart, int *nboundaries, PEdge **outer)
{
- PEdge *e, *be;
- float len, maxlen = -1.0;
+ PEdge *e, *be;
+ float len, maxlen = -1.0;
- if (nboundaries)
- *nboundaries = 0;
- if (outer)
- *outer = NULL;
+ if (nboundaries)
+ *nboundaries = 0;
+ if (outer)
+ *outer = NULL;
- for (e = chart->edges; e; e = e->nextlink) {
- if (e->pair || (e->flag & PEDGE_DONE))
- continue;
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (e->pair || (e->flag & PEDGE_DONE))
+ continue;
- if (nboundaries)
- (*nboundaries)++;
+ if (nboundaries)
+ (*nboundaries)++;
- len = 0.0f;
+ len = 0.0f;
- be = e;
- do {
- be->flag |= PEDGE_DONE;
- len += p_edge_length(be);
- be = be->next->vert->edge;
- } while (be != e);
+ be = e;
+ do {
+ be->flag |= PEDGE_DONE;
+ len += p_edge_length(be);
+ be = be->next->vert->edge;
+ } while (be != e);
- if (outer && (len > maxlen)) {
- *outer = e;
- maxlen = len;
- }
- }
+ if (outer && (len > maxlen)) {
+ *outer = e;
+ maxlen = len;
+ }
+ }
- for (e = chart->edges; e; e = e->nextlink)
- e->flag &= ~PEDGE_DONE;
+ for (e = chart->edges; e; e = e->nextlink)
+ e->flag &= ~PEDGE_DONE;
}
static float p_edge_boundary_angle(PEdge *e)
{
- PEdge *we;
- PVert *v, *v1, *v2;
- float angle;
- int n = 0;
+ PEdge *we;
+ PVert *v, *v1, *v2;
+ float angle;
+ int n = 0;
- v = e->vert;
+ v = e->vert;
- /* concave angle check -- could be better */
- angle = M_PI;
+ /* concave angle check -- could be better */
+ angle = M_PI;
- we = v->edge;
- do {
- v1 = we->next->vert;
- v2 = we->next->next->vert;
- angle -= p_vec_angle(v1->co, v->co, v2->co);
+ we = v->edge;
+ do {
+ v1 = we->next->vert;
+ v2 = we->next->next->vert;
+ angle -= p_vec_angle(v1->co, v->co, v2->co);
- we = we->next->next->pair;
- n++;
- } while (we && (we != v->edge));
+ we = we->next->next->pair;
+ n++;
+ } while (we && (we != v->edge));
- return angle;
+ return angle;
}
static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
{
- PEdge *e, *e1, *e2;
+ PEdge *e, *e1, *e2;
- PFace *f;
- struct Heap *heap = BLI_heap_new();
- float angle;
+ PFace *f;
+ struct Heap *heap = BLI_heap_new();
+ float angle;
- e = be;
- do {
- angle = p_edge_boundary_angle(e);
- e->u.heaplink = BLI_heap_insert(heap, angle, e);
+ e = be;
+ do {
+ angle = p_edge_boundary_angle(e);
+ e->u.heaplink = BLI_heap_insert(heap, angle, e);
- e = p_boundary_edge_next(e);
- } while (e != be);
+ e = p_boundary_edge_next(e);
+ } while (e != be);
- if (nedges == 2) {
- /* no real boundary, but an isolated seam */
- e = be->next->vert->edge;
- e->pair = be;
- be->pair = e;
+ if (nedges == 2) {
+ /* no real boundary, but an isolated seam */
+ e = be->next->vert->edge;
+ e->pair = be;
+ be->pair = e;
- BLI_heap_remove(heap, e->u.heaplink);
- BLI_heap_remove(heap, be->u.heaplink);
- }
- else {
- while (nedges > 2) {
- PEdge *ne, *ne1, *ne2;
+ BLI_heap_remove(heap, e->u.heaplink);
+ BLI_heap_remove(heap, be->u.heaplink);
+ }
+ else {
+ while (nedges > 2) {
+ PEdge *ne, *ne1, *ne2;
- e = (PEdge *)BLI_heap_pop_min(heap);
+ e = (PEdge *)BLI_heap_pop_min(heap);
- e1 = p_boundary_edge_prev(e);
- e2 = p_boundary_edge_next(e);
+ e1 = p_boundary_edge_prev(e);
+ e2 = p_boundary_edge_next(e);
- BLI_heap_remove(heap, e1->u.heaplink);
- BLI_heap_remove(heap, e2->u.heaplink);
- e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL;
+ BLI_heap_remove(heap, e1->u.heaplink);
+ BLI_heap_remove(heap, e2->u.heaplink);
+ e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL;
- e->flag |= PEDGE_FILLED;
- e1->flag |= PEDGE_FILLED;
+ e->flag |= PEDGE_FILLED;
+ e1->flag |= PEDGE_FILLED;
- f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert);
- f->flag |= PFACE_FILLED;
+ f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert);
+ f->flag |= PFACE_FILLED;
- ne = f->edge->next->next;
- ne1 = f->edge;
- ne2 = f->edge->next;
+ ne = f->edge->next->next;
+ ne1 = f->edge;
+ ne2 = f->edge->next;
- ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED;
+ ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED;
- e->pair = ne;
- ne->pair = e;
- e1->pair = ne1;
- ne1->pair = e1;
+ e->pair = ne;
+ ne->pair = e;
+ e1->pair = ne1;
+ ne1->pair = e1;
- ne->vert = e2->vert;
- ne1->vert = e->vert;
- ne2->vert = e1->vert;
+ ne->vert = e2->vert;
+ ne1->vert = e->vert;
+ ne2->vert = e1->vert;
- if (nedges == 3) {
- e2->pair = ne2;
- ne2->pair = e2;
- }
- else {
- ne2->vert->edge = ne2;
+ if (nedges == 3) {
+ e2->pair = ne2;
+ ne2->pair = e2;
+ }
+ else {
+ ne2->vert->edge = ne2;
- ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
- e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
- }
+ ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
+ e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
+ }
- nedges--;
- }
- }
+ nedges--;
+ }
+ }
- BLI_heap_free(heap, NULL);
+ BLI_heap_free(heap, NULL);
}
static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
{
- PEdge *e, *be; /* *enext - as yet unused */
- int nedges;
+ PEdge *e, *be; /* *enext - as yet unused */
+ int nedges;
- for (e = chart->edges; e; e = e->nextlink) {
- /* enext = e->nextlink; - as yet unused */
+ for (e = chart->edges; e; e = e->nextlink) {
+ /* enext = e->nextlink; - as yet unused */
- if (e->pair || (e->flag & PEDGE_FILLED))
- continue;
+ if (e->pair || (e->flag & PEDGE_FILLED))
+ continue;
- nedges = 0;
- be = e;
- do {
- be->flag |= PEDGE_FILLED;
- be = be->next->vert->edge;
- nedges++;
- } while (be != e);
+ nedges = 0;
+ be = e;
+ do {
+ be->flag |= PEDGE_FILLED;
+ be = be->next->vert->edge;
+ nedges++;
+ } while (be != e);
- if (e != outer)
- p_chart_fill_boundary(chart, e, nedges);
- }
+ if (e != outer)
+ p_chart_fill_boundary(chart, e, nedges);
+ }
}
#if 0
@@ -1369,116 +1385,116 @@ static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
static int p_polygon_point_in(float *cp1, float *cp2, float *p)
{
- if ((cp1[0] == p[0]) && (cp1[1] == p[1]))
- return 2;
- else if ((cp2[0] == p[0]) && (cp2[1] == p[1]))
- return 3;
- else
- return (p_area_signed(cp1, cp2, p) >= 0.0f);
+ if ((cp1[0] == p[0]) && (cp1[1] == p[1]))
+ return 2;
+ else if ((cp2[0] == p[0]) && (cp2[1] == p[1]))
+ return 3;
+ else
+ return (p_area_signed(cp1, cp2, p) >= 0.0f);
}
static void p_polygon_kernel_clip(float (*oldpoints)[2], int noldpoints, float (*newpoints)[2], int *nnewpoints, float *cp1, float *cp2)
{
- float *p2, *p1, isect[2];
- int i, p2in, p1in;
-
- p1 = oldpoints[noldpoints - 1];
- p1in = p_polygon_point_in(cp1, cp2, p1);
- *nnewpoints = 0;
-
- for (i = 0; i < noldpoints; i++) {
- p2 = oldpoints[i];
- p2in = p_polygon_point_in(cp1, cp2, p2);
-
- if ((p2in >= 2) || (p1in && p2in)) {
- newpoints[*nnewpoints][0] = p2[0];
- newpoints[*nnewpoints][1] = p2[1];
- (*nnewpoints)++;
- }
- else if (p1in && !p2in) {
- if (p1in != 3) {
- p_intersect_line_2d(p1, p2, cp1, cp2, isect);
- newpoints[*nnewpoints][0] = isect[0];
- newpoints[*nnewpoints][1] = isect[1];
- (*nnewpoints)++;
- }
- }
- else if (!p1in && p2in) {
- p_intersect_line_2d(p1, p2, cp1, cp2, isect);
- newpoints[*nnewpoints][0] = isect[0];
- newpoints[*nnewpoints][1] = isect[1];
- (*nnewpoints)++;
-
- newpoints[*nnewpoints][0] = p2[0];
- newpoints[*nnewpoints][1] = p2[1];
- (*nnewpoints)++;
- }
-
- p1in = p2in;
- p1 = p2;
- }
+ float *p2, *p1, isect[2];
+ int i, p2in, p1in;
+
+ p1 = oldpoints[noldpoints - 1];
+ p1in = p_polygon_point_in(cp1, cp2, p1);
+ *nnewpoints = 0;
+
+ for (i = 0; i < noldpoints; i++) {
+ p2 = oldpoints[i];
+ p2in = p_polygon_point_in(cp1, cp2, p2);
+
+ if ((p2in >= 2) || (p1in && p2in)) {
+ newpoints[*nnewpoints][0] = p2[0];
+ newpoints[*nnewpoints][1] = p2[1];
+ (*nnewpoints)++;
+ }
+ else if (p1in && !p2in) {
+ if (p1in != 3) {
+ p_intersect_line_2d(p1, p2, cp1, cp2, isect);
+ newpoints[*nnewpoints][0] = isect[0];
+ newpoints[*nnewpoints][1] = isect[1];
+ (*nnewpoints)++;
+ }
+ }
+ else if (!p1in && p2in) {
+ p_intersect_line_2d(p1, p2, cp1, cp2, isect);
+ newpoints[*nnewpoints][0] = isect[0];
+ newpoints[*nnewpoints][1] = isect[1];
+ (*nnewpoints)++;
+
+ newpoints[*nnewpoints][0] = p2[0];
+ newpoints[*nnewpoints][1] = p2[1];
+ (*nnewpoints)++;
+ }
+
+ p1in = p2in;
+ p1 = p2;
+ }
}
static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center)
{
- int i, size, nnewpoints = npoints;
- float (*oldpoints)[2], (*newpoints)[2], *p1, *p2;
-
- size = npoints * 3;
- oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonOldPoints");
- newpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonNewPoints");
-
- memcpy(oldpoints, points, sizeof(float) * 2 * npoints);
-
- for (i = 0; i < npoints; i++) {
- p1 = points[i];
- p2 = points[(i + 1) % npoints];
- p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2);
-
- if (nnewpoints == 0) {
- /* degenerate case, use center of original polygon */
- memcpy(oldpoints, points, sizeof(float) * 2 * npoints);
- nnewpoints = npoints;
- break;
- }
- else if (nnewpoints == 1) {
- /* degenerate case, use remaining point */
- center[0] = newpoints[0][0];
- center[1] = newpoints[0][1];
-
- MEM_freeN(oldpoints);
- MEM_freeN(newpoints);
-
- return;
- }
-
- if (nnewpoints * 2 > size) {
- size *= 2;
- MEM_freeN(oldpoints);
- oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "oldpoints");
- memcpy(oldpoints, newpoints, sizeof(float) * 2 * nnewpoints);
- MEM_freeN(newpoints);
- newpoints = MEM_mallocN(sizeof(float) * 2 * size, "newpoints");
- }
- else {
- float (*sw_points)[2] = oldpoints;
- oldpoints = newpoints;
- newpoints = sw_points;
- }
- }
-
- center[0] = center[1] = 0.0f;
-
- for (i = 0; i < nnewpoints; i++) {
- center[0] += oldpoints[i][0];
- center[1] += oldpoints[i][1];
- }
-
- center[0] /= nnewpoints;
- center[1] /= nnewpoints;
-
- MEM_freeN(oldpoints);
- MEM_freeN(newpoints);
+ int i, size, nnewpoints = npoints;
+ float (*oldpoints)[2], (*newpoints)[2], *p1, *p2;
+
+ size = npoints * 3;
+ oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonOldPoints");
+ newpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonNewPoints");
+
+ memcpy(oldpoints, points, sizeof(float) * 2 * npoints);
+
+ for (i = 0; i < npoints; i++) {
+ p1 = points[i];
+ p2 = points[(i + 1) % npoints];
+ p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2);
+
+ if (nnewpoints == 0) {
+ /* degenerate case, use center of original polygon */
+ memcpy(oldpoints, points, sizeof(float) * 2 * npoints);
+ nnewpoints = npoints;
+ break;
+ }
+ else if (nnewpoints == 1) {
+ /* degenerate case, use remaining point */
+ center[0] = newpoints[0][0];
+ center[1] = newpoints[0][1];
+
+ MEM_freeN(oldpoints);
+ MEM_freeN(newpoints);
+
+ return;
+ }
+
+ if (nnewpoints * 2 > size) {
+ size *= 2;
+ MEM_freeN(oldpoints);
+ oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "oldpoints");
+ memcpy(oldpoints, newpoints, sizeof(float) * 2 * nnewpoints);
+ MEM_freeN(newpoints);
+ newpoints = MEM_mallocN(sizeof(float) * 2 * size, "newpoints");
+ }
+ else {
+ float (*sw_points)[2] = oldpoints;
+ oldpoints = newpoints;
+ newpoints = sw_points;
+ }
+ }
+
+ center[0] = center[1] = 0.0f;
+
+ for (i = 0; i < nnewpoints; i++) {
+ center[0] += oldpoints[i][0];
+ center[1] += oldpoints[i][1];
+ }
+
+ center[0] /= nnewpoints;
+ center[1] /= nnewpoints;
+
+ MEM_freeN(oldpoints);
+ MEM_freeN(newpoints);
}
#endif
@@ -1490,809 +1506,809 @@ int NCOLLAPSEX = 0;
static float p_vert_cotan(float *v1, float *v2, float *v3)
{
- float a[3], b[3], c[3], clen;
+ float a[3], b[3], c[3], clen;
- sub_v3_v3v3(a, v2, v1);
- sub_v3_v3v3(b, v3, v1);
- cross_v3_v3v3(c, a, b);
+ sub_v3_v3v3(a, v2, v1);
+ sub_v3_v3v3(b, v3, v1);
+ cross_v3_v3v3(c, a, b);
- clen = len_v3(c);
+ clen = len_v3(c);
- if (clen == 0.0f)
- return 0.0f;
+ if (clen == 0.0f)
+ return 0.0f;
- return dot_v3v3(a, b) / clen;
+ return dot_v3v3(a, b) / clen;
}
static PBool p_vert_flipped_wheel_triangle(PVert *v)
{
- PEdge *e = v->edge;
+ PEdge *e = v->edge;
- do {
- if (p_face_uv_area_signed(e->face) < 0.0f)
- return P_TRUE;
+ do {
+ if (p_face_uv_area_signed(e->face) < 0.0f)
+ return P_TRUE;
- e = p_wheel_edge_next(e);
- } while (e && (e != v->edge));
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
- return P_FALSE;
+ return P_FALSE;
}
static PBool p_vert_map_harmonic_weights(PVert *v)
{
- float weightsum, positionsum[2], olduv[2];
+ float weightsum, positionsum[2], olduv[2];
- weightsum = 0.0f;
- positionsum[0] = positionsum[1] = 0.0f;
+ weightsum = 0.0f;
+ positionsum[0] = positionsum[1] = 0.0f;
- if (p_vert_interior(v)) {
- PEdge *e = v->edge;
+ if (p_vert_interior(v)) {
+ PEdge *e = v->edge;
- do {
- float t1, t2, weight;
- PVert *v1, *v2;
+ do {
+ float t1, t2, weight;
+ PVert *v1, *v2;
- v1 = e->next->vert;
- v2 = e->next->next->vert;
- t1 = p_vert_cotan(v2->co, e->vert->co, v1->co);
+ v1 = e->next->vert;
+ v2 = e->next->next->vert;
+ t1 = p_vert_cotan(v2->co, e->vert->co, v1->co);
- v1 = e->pair->next->vert;
- v2 = e->pair->next->next->vert;
- t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co);
+ v1 = e->pair->next->vert;
+ v2 = e->pair->next->next->vert;
+ t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co);
- weight = 0.5f * (t1 + t2);
- weightsum += weight;
- positionsum[0] += weight * e->pair->vert->uv[0];
- positionsum[1] += weight * e->pair->vert->uv[1];
+ weight = 0.5f * (t1 + t2);
+ weightsum += weight;
+ positionsum[0] += weight * e->pair->vert->uv[0];
+ positionsum[1] += weight * e->pair->vert->uv[1];
- e = p_wheel_edge_next(e);
- } while (e && (e != v->edge));
- }
- else {
- PEdge *e = v->edge;
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+ }
+ else {
+ PEdge *e = v->edge;
- do {
- float t1, t2;
- PVert *v1, *v2;
+ do {
+ float t1, t2;
+ PVert *v1, *v2;
- v2 = e->next->vert;
- v1 = e->next->next->vert;
+ v2 = e->next->vert;
+ v1 = e->next->next->vert;
- t1 = p_vert_cotan(v1->co, v->co, v2->co);
- t2 = p_vert_cotan(v2->co, v->co, v1->co);
+ t1 = p_vert_cotan(v1->co, v->co, v2->co);
+ t2 = p_vert_cotan(v2->co, v->co, v1->co);
- weightsum += t1 + t2;
- positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]);
- positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]);
+ weightsum += t1 + t2;
+ positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]);
+ positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]);
- e = p_wheel_edge_next(e);
- } while (e && (e != v->edge));
- }
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+ }
- if (weightsum != 0.0f) {
- weightsum = 1.0f / weightsum;
- positionsum[0] *= weightsum;
- positionsum[1] *= weightsum;
- }
+ if (weightsum != 0.0f) {
+ weightsum = 1.0f / weightsum;
+ positionsum[0] *= weightsum;
+ positionsum[1] *= weightsum;
+ }
- olduv[0] = v->uv[0];
- olduv[1] = v->uv[1];
- v->uv[0] = positionsum[0];
- v->uv[1] = positionsum[1];
+ olduv[0] = v->uv[0];
+ olduv[1] = v->uv[1];
+ v->uv[0] = positionsum[0];
+ v->uv[1] = positionsum[1];
- if (p_vert_flipped_wheel_triangle(v)) {
- v->uv[0] = olduv[0];
- v->uv[1] = olduv[1];
+ if (p_vert_flipped_wheel_triangle(v)) {
+ v->uv[0] = olduv[0];
+ v->uv[1] = olduv[1];
- return P_FALSE;
- }
+ return P_FALSE;
+ }
- return P_TRUE;
+ return P_TRUE;
}
static void p_vert_harmonic_insert(PVert *v)
{
- PEdge *e;
+ PEdge *e;
- if (!p_vert_map_harmonic_weights(v)) {
- /* do polygon kernel center insertion: this is quite slow, but should
- * only be needed for 0.01 % of verts or so, when insert with harmonic
- * weights fails */
+ if (!p_vert_map_harmonic_weights(v)) {
+ /* do polygon kernel center insertion: this is quite slow, but should
+ * only be needed for 0.01 % of verts or so, when insert with harmonic
+ * weights fails */
- int npoints = 0, i;
- float (*points)[2];
+ int npoints = 0, i;
+ float (*points)[2];
- e = v->edge;
- do {
- npoints++;
- e = p_wheel_edge_next(e);
- } while (e && (e != v->edge));
+ e = v->edge;
+ do {
+ npoints++;
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
- if (e == NULL)
- npoints++;
+ if (e == NULL)
+ npoints++;
- points = MEM_mallocN(sizeof(float) * 2 * npoints, "PHarmonicPoints");
+ points = MEM_mallocN(sizeof(float) * 2 * npoints, "PHarmonicPoints");
- e = v->edge;
- i = 0;
- do {
- PEdge *nexte = p_wheel_edge_next(e);
+ e = v->edge;
+ i = 0;
+ do {
+ PEdge *nexte = p_wheel_edge_next(e);
- points[i][0] = e->next->vert->uv[0];
- points[i][1] = e->next->vert->uv[1];
+ points[i][0] = e->next->vert->uv[0];
+ points[i][1] = e->next->vert->uv[1];
- if (nexte == NULL) {
- i++;
- points[i][0] = e->next->next->vert->uv[0];
- points[i][1] = e->next->next->vert->uv[1];
- break;
- }
+ if (nexte == NULL) {
+ i++;
+ points[i][0] = e->next->next->vert->uv[0];
+ points[i][1] = e->next->next->vert->uv[1];
+ break;
+ }
- e = nexte;
- i++;
- } while (e != v->edge);
+ e = nexte;
+ i++;
+ } while (e != v->edge);
- p_polygon_kernel_center(points, npoints, v->uv);
+ p_polygon_kernel_center(points, npoints, v->uv);
- MEM_freeN(points);
- }
+ MEM_freeN(points);
+ }
- e = v->edge;
- do {
- if (!(e->next->vert->flag & PVERT_PIN))
- p_vert_map_harmonic_weights(e->next->vert);
- e = p_wheel_edge_next(e);
- } while (e && (e != v->edge));
+ e = v->edge;
+ do {
+ if (!(e->next->vert->flag & PVERT_PIN))
+ p_vert_map_harmonic_weights(e->next->vert);
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
- p_vert_map_harmonic_weights(v);
+ p_vert_map_harmonic_weights(v);
}
static void p_vert_fix_edge_pointer(PVert *v)
{
- PEdge *start = v->edge;
+ PEdge *start = v->edge;
- /* set v->edge pointer to the edge with no pair, if there is one */
- while (v->edge->pair) {
- v->edge = p_wheel_edge_prev(v->edge);
+ /* set v->edge pointer to the edge with no pair, if there is one */
+ while (v->edge->pair) {
+ v->edge = p_wheel_edge_prev(v->edge);
- if (v->edge == start)
- break;
- }
+ if (v->edge == start)
+ break;
+ }
}
static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **newv, PVert **keepv)
{
- /* the two vertices that are involved in the collapse */
- if (edge) {
- *newv = edge->vert;
- *keepv = edge->next->vert;
- }
- else {
- *newv = pair->next->vert;
- *keepv = pair->vert;
- }
+ /* the two vertices that are involved in the collapse */
+ if (edge) {
+ *newv = edge->vert;
+ *keepv = edge->next->vert;
+ }
+ else {
+ *newv = pair->next->vert;
+ *keepv = pair->vert;
+ }
}
static void p_collapse_edge(PEdge *edge, PEdge *pair)
{
- PVert *oldv, *keepv;
- PEdge *e;
+ PVert *oldv, *keepv;
+ PEdge *e;
- p_collapsing_verts(edge, pair, &oldv, &keepv);
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
- /* change e->vert pointers from old vertex to the target vertex */
- e = oldv->edge;
- do {
- if ((e != edge) && !(pair && pair->next == e))
- e->vert = keepv;
+ /* change e->vert pointers from old vertex to the target vertex */
+ e = oldv->edge;
+ do {
+ if ((e != edge) && !(pair && pair->next == e))
+ e->vert = keepv;
- e = p_wheel_edge_next(e);
- } while (e && (e != oldv->edge));
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
- /* set keepv->edge pointer */
- if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) {
- if (edge && edge->next->pair)
- keepv->edge = edge->next->pair->next;
- else if (pair && pair->next->next->pair)
- keepv->edge = pair->next->next->pair;
- else if (edge && edge->next->next->pair)
- keepv->edge = edge->next->next->pair;
- else
- keepv->edge = pair->next->pair->next;
- }
+ /* set keepv->edge pointer */
+ if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) {
+ if (edge && edge->next->pair)
+ keepv->edge = edge->next->pair->next;
+ else if (pair && pair->next->next->pair)
+ keepv->edge = pair->next->next->pair;
+ else if (edge && edge->next->next->pair)
+ keepv->edge = edge->next->next->pair;
+ else
+ keepv->edge = pair->next->pair->next;
+ }
- /* update pairs and v->edge pointers */
- if (edge) {
- PEdge *e1 = edge->next, *e2 = e1->next;
+ /* update pairs and v->edge pointers */
+ if (edge) {
+ PEdge *e1 = edge->next, *e2 = e1->next;
- if (e1->pair)
- e1->pair->pair = e2->pair;
+ if (e1->pair)
+ e1->pair->pair = e2->pair;
- if (e2->pair) {
- e2->pair->pair = e1->pair;
- e2->vert->edge = p_wheel_edge_prev(e2);
- }
- else
- e2->vert->edge = p_wheel_edge_next(e2);
+ if (e2->pair) {
+ e2->pair->pair = e1->pair;
+ e2->vert->edge = p_wheel_edge_prev(e2);
+ }
+ else
+ e2->vert->edge = p_wheel_edge_next(e2);
- p_vert_fix_edge_pointer(e2->vert);
- }
+ p_vert_fix_edge_pointer(e2->vert);
+ }
- if (pair) {
- PEdge *e1 = pair->next, *e2 = e1->next;
+ if (pair) {
+ PEdge *e1 = pair->next, *e2 = e1->next;
- if (e1->pair)
- e1->pair->pair = e2->pair;
+ if (e1->pair)
+ e1->pair->pair = e2->pair;
- if (e2->pair) {
- e2->pair->pair = e1->pair;
- e2->vert->edge = p_wheel_edge_prev(e2);
- }
- else
- e2->vert->edge = p_wheel_edge_next(e2);
+ if (e2->pair) {
+ e2->pair->pair = e1->pair;
+ e2->vert->edge = p_wheel_edge_prev(e2);
+ }
+ else
+ e2->vert->edge = p_wheel_edge_next(e2);
- p_vert_fix_edge_pointer(e2->vert);
- }
+ p_vert_fix_edge_pointer(e2->vert);
+ }
- p_vert_fix_edge_pointer(keepv);
+ p_vert_fix_edge_pointer(keepv);
- /* mark for move to collapsed list later */
- oldv->flag |= PVERT_COLLAPSE;
+ /* mark for move to collapsed list later */
+ oldv->flag |= PVERT_COLLAPSE;
- if (edge) {
- PFace *f = edge->face;
- PEdge *e1 = edge->next, *e2 = e1->next;
+ if (edge) {
+ PFace *f = edge->face;
+ PEdge *e1 = edge->next, *e2 = e1->next;
- f->flag |= PFACE_COLLAPSE;
- edge->flag |= PEDGE_COLLAPSE;
- e1->flag |= PEDGE_COLLAPSE;
- e2->flag |= PEDGE_COLLAPSE;
- }
+ f->flag |= PFACE_COLLAPSE;
+ edge->flag |= PEDGE_COLLAPSE;
+ e1->flag |= PEDGE_COLLAPSE;
+ e2->flag |= PEDGE_COLLAPSE;
+ }
- if (pair) {
- PFace *f = pair->face;
- PEdge *e1 = pair->next, *e2 = e1->next;
+ if (pair) {
+ PFace *f = pair->face;
+ PEdge *e1 = pair->next, *e2 = e1->next;
- f->flag |= PFACE_COLLAPSE;
- pair->flag |= PEDGE_COLLAPSE;
- e1->flag |= PEDGE_COLLAPSE;
- e2->flag |= PEDGE_COLLAPSE;
- }
+ f->flag |= PFACE_COLLAPSE;
+ pair->flag |= PEDGE_COLLAPSE;
+ e1->flag |= PEDGE_COLLAPSE;
+ e2->flag |= PEDGE_COLLAPSE;
+ }
}
static void p_split_vertex(PEdge *edge, PEdge *pair)
{
- PVert *newv, *keepv;
- PEdge *e;
+ PVert *newv, *keepv;
+ PEdge *e;
- p_collapsing_verts(edge, pair, &newv, &keepv);
+ p_collapsing_verts(edge, pair, &newv, &keepv);
- /* update edge pairs */
- if (edge) {
- PEdge *e1 = edge->next, *e2 = e1->next;
+ /* update edge pairs */
+ if (edge) {
+ PEdge *e1 = edge->next, *e2 = e1->next;
- if (e1->pair)
- e1->pair->pair = e1;
- if (e2->pair)
- e2->pair->pair = e2;
+ if (e1->pair)
+ e1->pair->pair = e1;
+ if (e2->pair)
+ e2->pair->pair = e2;
- e2->vert->edge = e2;
- p_vert_fix_edge_pointer(e2->vert);
- keepv->edge = e1;
- }
+ e2->vert->edge = e2;
+ p_vert_fix_edge_pointer(e2->vert);
+ keepv->edge = e1;
+ }
- if (pair) {
- PEdge *e1 = pair->next, *e2 = e1->next;
+ if (pair) {
+ PEdge *e1 = pair->next, *e2 = e1->next;
- if (e1->pair)
- e1->pair->pair = e1;
- if (e2->pair)
- e2->pair->pair = e2;
+ if (e1->pair)
+ e1->pair->pair = e1;
+ if (e2->pair)
+ e2->pair->pair = e2;
- e2->vert->edge = e2;
- p_vert_fix_edge_pointer(e2->vert);
- keepv->edge = pair;
- }
+ e2->vert->edge = e2;
+ p_vert_fix_edge_pointer(e2->vert);
+ keepv->edge = pair;
+ }
- p_vert_fix_edge_pointer(keepv);
+ p_vert_fix_edge_pointer(keepv);
- /* set e->vert pointers to restored vertex */
- e = newv->edge;
- do {
- e->vert = newv;
- e = p_wheel_edge_next(e);
- } while (e && (e != newv->edge));
+ /* set e->vert pointers to restored vertex */
+ e = newv->edge;
+ do {
+ e->vert = newv;
+ e = p_wheel_edge_next(e);
+ } while (e && (e != newv->edge));
}
static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
{
- PVert *oldv, *keepv;
+ PVert *oldv, *keepv;
- p_collapsing_verts(edge, pair, &oldv, &keepv);
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
- /* boundary edges */
- if (!edge || !pair) {
- /* avoid collapsing chart into an edge */
- if (edge && !edge->next->pair && !edge->next->next->pair)
- return P_FALSE;
- else if (pair && !pair->next->pair && !pair->next->next->pair)
- return P_FALSE;
- }
- /* avoid merging two boundaries (oldv and keepv are on the 'other side' of
- * the chart) */
- else if (!p_vert_interior(oldv) && !p_vert_interior(keepv))
- return P_FALSE;
+ /* boundary edges */
+ if (!edge || !pair) {
+ /* avoid collapsing chart into an edge */
+ if (edge && !edge->next->pair && !edge->next->next->pair)
+ return P_FALSE;
+ else if (pair && !pair->next->pair && !pair->next->next->pair)
+ return P_FALSE;
+ }
+ /* avoid merging two boundaries (oldv and keepv are on the 'other side' of
+ * the chart) */
+ else if (!p_vert_interior(oldv) && !p_vert_interior(keepv))
+ return P_FALSE;
- return P_TRUE;
+ return P_TRUE;
}
static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
{
- float nold[3], nnew[3], sub1[3], sub2[3];
+ float nold[3], nnew[3], sub1[3], sub2[3];
- sub_v3_v3v3(sub1, vold, v1);
- sub_v3_v3v3(sub2, vold, v2);
- cross_v3_v3v3(nold, sub1, sub2);
+ sub_v3_v3v3(sub1, vold, v1);
+ sub_v3_v3v3(sub2, vold, v2);
+ cross_v3_v3v3(nold, sub1, sub2);
- sub_v3_v3v3(sub1, vnew, v1);
- sub_v3_v3v3(sub2, vnew, v2);
- cross_v3_v3v3(nnew, sub1, sub2);
+ sub_v3_v3v3(sub1, vnew, v1);
+ sub_v3_v3v3(sub2, vnew, v2);
+ cross_v3_v3v3(nnew, sub1, sub2);
- return (dot_v3v3(nold, nnew) <= 0.0f);
+ return (dot_v3v3(nold, nnew) <= 0.0f);
}
static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
{
- PVert *oldv, *keepv;
- PEdge *e;
- float angulardefect, angle;
+ PVert *oldv, *keepv;
+ PEdge *e;
+ float angulardefect, angle;
- p_collapsing_verts(edge, pair, &oldv, &keepv);
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
- angulardefect = 2 * M_PI;
+ angulardefect = 2 * M_PI;
- e = oldv->edge;
- do {
- float a[3], b[3], minangle, maxangle;
- PEdge *e1 = e->next, *e2 = e1->next;
- PVert *v1 = e1->vert, *v2 = e2->vert;
- int i;
+ e = oldv->edge;
+ do {
+ float a[3], b[3], minangle, maxangle;
+ PEdge *e1 = e->next, *e2 = e1->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert;
+ int i;
- angle = p_vec_angle(v1->co, oldv->co, v2->co);
- angulardefect -= angle;
+ angle = p_vec_angle(v1->co, oldv->co, v2->co);
+ angulardefect -= angle;
- /* skip collapsing faces */
- if (v1 == keepv || v2 == keepv) {
- e = p_wheel_edge_next(e);
- continue;
- }
+ /* skip collapsing faces */
+ if (v1 == keepv || v2 == keepv) {
+ e = p_wheel_edge_next(e);
+ continue;
+ }
- if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co))
- return P_FALSE;
+ if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co))
+ return P_FALSE;
- a[0] = angle;
- a[1] = p_vec_angle(v2->co, v1->co, oldv->co);
- a[2] = M_PI - a[0] - a[1];
+ a[0] = angle;
+ a[1] = p_vec_angle(v2->co, v1->co, oldv->co);
+ a[2] = M_PI - a[0] - a[1];
- b[0] = p_vec_angle(v1->co, keepv->co, v2->co);
- b[1] = p_vec_angle(v2->co, v1->co, keepv->co);
- b[2] = M_PI - b[0] - b[1];
+ b[0] = p_vec_angle(v1->co, keepv->co, v2->co);
+ b[1] = p_vec_angle(v2->co, v1->co, keepv->co);
+ b[2] = M_PI - b[0] - b[1];
- /* abf criterion 1: avoid sharp and obtuse angles */
- minangle = 15.0f * M_PI / 180.0f;
- maxangle = M_PI - minangle;
+ /* abf criterion 1: avoid sharp and obtuse angles */
+ minangle = 15.0f * M_PI / 180.0f;
+ maxangle = M_PI - minangle;
- for (i = 0; i < 3; i++) {
- if ((b[i] < a[i]) && (b[i] < minangle))
- return P_FALSE;
- else if ((b[i] > a[i]) && (b[i] > maxangle))
- return P_FALSE;
- }
+ for (i = 0; i < 3; i++) {
+ if ((b[i] < a[i]) && (b[i] < minangle))
+ return P_FALSE;
+ else if ((b[i] > a[i]) && (b[i] > maxangle))
+ return P_FALSE;
+ }
- e = p_wheel_edge_next(e);
- } while (e && (e != oldv->edge));
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
- if (p_vert_interior(oldv)) {
- /* hlscm criterion: angular defect smaller than threshold */
- if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0))
- return P_FALSE;
- }
- else {
- PVert *v1 = p_boundary_edge_next(oldv->edge)->vert;
- PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert;
+ if (p_vert_interior(oldv)) {
+ /* hlscm criterion: angular defect smaller than threshold */
+ if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0))
+ return P_FALSE;
+ }
+ else {
+ PVert *v1 = p_boundary_edge_next(oldv->edge)->vert;
+ PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert;
- /* abf++ criterion 2: avoid collapsing verts inwards */
- if (p_vert_interior(keepv))
- return P_FALSE;
+ /* abf++ criterion 2: avoid collapsing verts inwards */
+ if (p_vert_interior(keepv))
+ return P_FALSE;
- /* don't collapse significant boundary changes */
- angle = p_vec_angle(v1->co, oldv->co, v2->co);
- if (angle < (M_PI * 160.0 / 180.0))
- return P_FALSE;
- }
+ /* don't collapse significant boundary changes */
+ angle = p_vec_angle(v1->co, oldv->co, v2->co);
+ if (angle < (M_PI * 160.0 / 180.0))
+ return P_FALSE;
+ }
- return P_TRUE;
+ return P_TRUE;
}
static PBool p_collapse_allowed(PEdge *edge, PEdge *pair)
{
- PVert *oldv, *keepv;
+ PVert *oldv, *keepv;
- p_collapsing_verts(edge, pair, &oldv, &keepv);
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
- if (oldv->flag & PVERT_PIN)
- return P_FALSE;
+ if (oldv->flag & PVERT_PIN)
+ return P_FALSE;
- return (p_collapse_allowed_topologic(edge, pair) &&
- p_collapse_allowed_geometric(edge, pair));
+ return (p_collapse_allowed_topologic(edge, pair) &&
+ p_collapse_allowed_geometric(edge, pair));
}
static float p_collapse_cost(PEdge *edge, PEdge *pair)
{
- /* based on volume and boundary optimization from:
- * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */
+ /* based on volume and boundary optimization from:
+ * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */
- PVert *oldv, *keepv;
- PEdge *e;
- PFace *oldf1, *oldf2;
- float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen;
- float shapecost = 0.0f;
- float shapeold = 0.0f, shapenew = 0.0f;
- int nshapeold = 0, nshapenew = 0;
+ PVert *oldv, *keepv;
+ PEdge *e;
+ PFace *oldf1, *oldf2;
+ float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen;
+ float shapecost = 0.0f;
+ float shapeold = 0.0f, shapenew = 0.0f;
+ int nshapeold = 0, nshapenew = 0;
- p_collapsing_verts(edge, pair, &oldv, &keepv);
- oldf1 = (edge) ? edge->face : NULL;
- oldf2 = (pair) ? pair->face : NULL;
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+ oldf1 = (edge) ? edge->face : NULL;
+ oldf2 = (pair) ? pair->face : NULL;
- sub_v3_v3v3(edgevec, keepv->co, oldv->co);
+ sub_v3_v3v3(edgevec, keepv->co, oldv->co);
- e = oldv->edge;
- do {
- float a1, a2, a3;
- float *co1 = e->next->vert->co;
- float *co2 = e->next->next->vert->co;
+ e = oldv->edge;
+ do {
+ float a1, a2, a3;
+ float *co1 = e->next->vert->co;
+ float *co2 = e->next->next->vert->co;
- if ((e->face != oldf1) && (e->face != oldf2)) {
- float tetrav2[3], tetrav3[3], c[3];
+ if ((e->face != oldf1) && (e->face != oldf2)) {
+ float tetrav2[3], tetrav3[3], c[3];
- /* tetrahedron volume = (1/3!)*|a.(b x c)| */
- sub_v3_v3v3(tetrav2, co1, oldv->co);
- sub_v3_v3v3(tetrav3, co2, oldv->co);
- cross_v3_v3v3(c, tetrav2, tetrav3);
+ /* tetrahedron volume = (1/3!)*|a.(b x c)| */
+ sub_v3_v3v3(tetrav2, co1, oldv->co);
+ sub_v3_v3v3(tetrav3, co2, oldv->co);
+ cross_v3_v3v3(c, tetrav2, tetrav3);
- volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f);
-#if 0
- shapecost += dot_v3v3(co1, keepv->co);
+ volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f);
+# if 0
+ shapecost += dot_v3v3(co1, keepv->co);
- if (p_wheel_edge_next(e) == NULL)
- shapecost += dot_v3v3(co2, keepv->co);
-#endif
+ if (p_wheel_edge_next(e) == NULL)
+ shapecost += dot_v3v3(co2, keepv->co);
+# endif
- p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3);
- a1 = a1 - M_PI / 3.0;
- a2 = a2 - M_PI / 3.0;
- a3 = a3 - M_PI / 3.0;
- shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
-
- nshapeold++;
- }
- else {
- p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3);
- a1 = a1 - M_PI / 3.0;
- a2 = a2 - M_PI / 3.0;
- a3 = a3 - M_PI / 3.0;
- shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
-
- nshapenew++;
- }
-
- e = p_wheel_edge_next(e);
- } while (e && (e != oldv->edge));
-
- if (!p_vert_interior(oldv)) {
- PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert;
- PVert *v2 = p_boundary_edge_next(oldv->edge)->vert;
-
- areacost = area_tri_v3(oldv->co, v1->co, v2->co);
- }
-
- elen = len_v3(edgevec);
- weight = 1.0f; /* 0.2f */
- cost = weight * volumecost * volumecost + elen * elen * areacost * areacost;
-#if 0
- cost += shapecost;
-#else
- shapeold /= nshapeold;
- shapenew /= nshapenew;
- shapecost = (shapeold + 0.00001) / (shapenew + 0.00001);
+ p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3);
+ a1 = a1 - M_PI / 3.0;
+ a2 = a2 - M_PI / 3.0;
+ a3 = a3 - M_PI / 3.0;
+ shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
+
+ nshapeold++;
+ }
+ else {
+ p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3);
+ a1 = a1 - M_PI / 3.0;
+ a2 = a2 - M_PI / 3.0;
+ a3 = a3 - M_PI / 3.0;
+ shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2));
+
+ nshapenew++;
+ }
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
+
+ if (!p_vert_interior(oldv)) {
+ PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert;
+ PVert *v2 = p_boundary_edge_next(oldv->edge)->vert;
+
+ areacost = area_tri_v3(oldv->co, v1->co, v2->co);
+ }
+
+ elen = len_v3(edgevec);
+ weight = 1.0f; /* 0.2f */
+ cost = weight * volumecost * volumecost + elen * elen * areacost * areacost;
+# if 0
+ cost += shapecost;
+# else
+ shapeold /= nshapeold;
+ shapenew /= nshapenew;
+ shapecost = (shapeold + 0.00001) / (shapenew + 0.00001);
- cost *= shapecost;
-#endif
+ cost *= shapecost;
+# endif
- return cost;
+ return cost;
}
static void p_collapse_cost_vertex(PVert *vert, float *mincost, PEdge **mine)
{
- PEdge *e, *enext, *pair;
+ PEdge *e, *enext, *pair;
- *mine = NULL;
- *mincost = 0.0f;
- e = vert->edge;
- do {
- if (p_collapse_allowed(e, e->pair)) {
- float cost = p_collapse_cost(e, e->pair);
+ *mine = NULL;
+ *mincost = 0.0f;
+ e = vert->edge;
+ do {
+ if (p_collapse_allowed(e, e->pair)) {
+ float cost = p_collapse_cost(e, e->pair);
- if ((*mine == NULL) || (cost < *mincost)) {
- *mincost = cost;
- *mine = e;
- }
- }
+ if ((*mine == NULL) || (cost < *mincost)) {
+ *mincost = cost;
+ *mine = e;
+ }
+ }
- enext = p_wheel_edge_next(e);
+ enext = p_wheel_edge_next(e);
- if (enext == NULL) {
- /* the other boundary edge, where we only have the pair halfedge */
- pair = e->next->next;
+ if (enext == NULL) {
+ /* the other boundary edge, where we only have the pair halfedge */
+ pair = e->next->next;
- if (p_collapse_allowed(NULL, pair)) {
- float cost = p_collapse_cost(NULL, pair);
+ if (p_collapse_allowed(NULL, pair)) {
+ float cost = p_collapse_cost(NULL, pair);
- if ((*mine == NULL) || (cost < *mincost)) {
- *mincost = cost;
- *mine = pair;
- }
- }
+ if ((*mine == NULL) || (cost < *mincost)) {
+ *mincost = cost;
+ *mine = pair;
+ }
+ }
- break;
- }
+ break;
+ }
- e = enext;
- } while (e != vert->edge);
+ e = enext;
+ } while (e != vert->edge);
}
static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
{
- /* move to collapsed_ */
-
- PVert *v, *nextv = NULL, *verts = chart->verts;
- PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL;
- PFace *f, *nextf = NULL, *faces = chart->faces;
-
- chart->verts = chart->collapsed_verts = NULL;
- chart->edges = chart->collapsed_edges = NULL;
- chart->faces = chart->collapsed_faces = NULL;
-
- chart->nverts = chart->nedges = chart->nfaces = 0;
-
- for (v = verts; v; v = nextv) {
- nextv = v->nextlink;
-
- if (v->flag & PVERT_COLLAPSE) {
- v->nextlink = chart->collapsed_verts;
- chart->collapsed_verts = v;
- }
- else {
- v->nextlink = chart->verts;
- chart->verts = v;
- chart->nverts++;
- }
- }
-
- for (e = edges; e; e = nexte) {
- nexte = e->nextlink;
-
- if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) {
- if (e->flag & PEDGE_COLLAPSE) {
- e->nextlink = chart->collapsed_edges;
- chart->collapsed_edges = e;
- }
- else {
- e->nextlink = chart->edges;
- chart->edges = e;
- chart->nedges++;
- }
- }
- }
-
- /* these are added last so they can be popped of in the right order
- * for splitting */
- for (e = collapsed; e; e = e->nextlink) {
- e->nextlink = e->u.nextcollapse;
- laste = e;
- }
- if (laste) {
- laste->nextlink = chart->collapsed_edges;
- chart->collapsed_edges = collapsed;
- }
-
- for (f = faces; f; f = nextf) {
- nextf = f->nextlink;
-
- if (f->flag & PFACE_COLLAPSE) {
- f->nextlink = chart->collapsed_faces;
- chart->collapsed_faces = f;
- }
- else {
- f->nextlink = chart->faces;
- chart->faces = f;
- chart->nfaces++;
- }
- }
+ /* move to collapsed_ */
+
+ PVert *v, *nextv = NULL, *verts = chart->verts;
+ PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL;
+ PFace *f, *nextf = NULL, *faces = chart->faces;
+
+ chart->verts = chart->collapsed_verts = NULL;
+ chart->edges = chart->collapsed_edges = NULL;
+ chart->faces = chart->collapsed_faces = NULL;
+
+ chart->nverts = chart->nedges = chart->nfaces = 0;
+
+ for (v = verts; v; v = nextv) {
+ nextv = v->nextlink;
+
+ if (v->flag & PVERT_COLLAPSE) {
+ v->nextlink = chart->collapsed_verts;
+ chart->collapsed_verts = v;
+ }
+ else {
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
+ }
+
+ for (e = edges; e; e = nexte) {
+ nexte = e->nextlink;
+
+ if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) {
+ if (e->flag & PEDGE_COLLAPSE) {
+ e->nextlink = chart->collapsed_edges;
+ chart->collapsed_edges = e;
+ }
+ else {
+ e->nextlink = chart->edges;
+ chart->edges = e;
+ chart->nedges++;
+ }
+ }
+ }
+
+ /* these are added last so they can be popped of in the right order
+ * for splitting */
+ for (e = collapsed; e; e = e->nextlink) {
+ e->nextlink = e->u.nextcollapse;
+ laste = e;
+ }
+ if (laste) {
+ laste->nextlink = chart->collapsed_edges;
+ chart->collapsed_edges = collapsed;
+ }
+
+ for (f = faces; f; f = nextf) {
+ nextf = f->nextlink;
+
+ if (f->flag & PFACE_COLLAPSE) {
+ f->nextlink = chart->collapsed_faces;
+ chart->collapsed_faces = f;
+ }
+ else {
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ chart->nfaces++;
+ }
+ }
}
static void p_chart_post_split_flush(PChart *chart)
{
- /* move from collapsed_ */
+ /* move from collapsed_ */
- PVert *v, *nextv = NULL;
- PEdge *e, *nexte = NULL;
- PFace *f, *nextf = NULL;
+ PVert *v, *nextv = NULL;
+ PEdge *e, *nexte = NULL;
+ PFace *f, *nextf = NULL;
- for (v = chart->collapsed_verts; v; v = nextv) {
- nextv = v->nextlink;
- v->nextlink = chart->verts;
- chart->verts = v;
- chart->nverts++;
- }
+ for (v = chart->collapsed_verts; v; v = nextv) {
+ nextv = v->nextlink;
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
- for (e = chart->collapsed_edges; e; e = nexte) {
- nexte = e->nextlink;
- e->nextlink = chart->edges;
- chart->edges = e;
- chart->nedges++;
- }
+ for (e = chart->collapsed_edges; e; e = nexte) {
+ nexte = e->nextlink;
+ e->nextlink = chart->edges;
+ chart->edges = e;
+ chart->nedges++;
+ }
- for (f = chart->collapsed_faces; f; f = nextf) {
- nextf = f->nextlink;
- f->nextlink = chart->faces;
- chart->faces = f;
- chart->nfaces++;
- }
+ for (f = chart->collapsed_faces; f; f = nextf) {
+ nextf = f->nextlink;
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ chart->nfaces++;
+ }
- chart->collapsed_verts = NULL;
- chart->collapsed_edges = NULL;
- chart->collapsed_faces = NULL;
+ chart->collapsed_verts = NULL;
+ chart->collapsed_edges = NULL;
+ chart->collapsed_faces = NULL;
}
static void p_chart_simplify_compute(PChart *chart)
{
- /* Computes a list of edge collapses / vertex splits. The collapsed
- * simplices go in the chart->collapsed_* lists, The original and
- * collapsed may then be view as stacks, where the next collapse/split
- * is at the top of the respective lists. */
+ /* Computes a list of edge collapses / vertex splits. The collapsed
+ * simplices go in the chart->collapsed_* lists, The original and
+ * collapsed may then be view as stacks, where the next collapse/split
+ * is at the top of the respective lists. */
- Heap *heap = BLI_heap_new();
- PVert *v, **wheelverts;
- PEdge *collapsededges = NULL, *e;
- int nwheelverts, i, ncollapsed = 0;
+ Heap *heap = BLI_heap_new();
+ PVert *v, **wheelverts;
+ PEdge *collapsededges = NULL, *e;
+ int nwheelverts, i, ncollapsed = 0;
- wheelverts = MEM_mallocN(sizeof(PVert *) * chart->nverts, "PChartWheelVerts");
+ wheelverts = MEM_mallocN(sizeof(PVert *) * chart->nverts, "PChartWheelVerts");
- /* insert all potential collapses into heap */
- for (v = chart->verts; v; v = v->nextlink) {
- float cost;
- PEdge *e = NULL;
+ /* insert all potential collapses into heap */
+ for (v = chart->verts; v; v = v->nextlink) {
+ float cost;
+ PEdge *e = NULL;
- p_collapse_cost_vertex(v, &cost, &e);
+ p_collapse_cost_vertex(v, &cost, &e);
- if (e)
- v->u.heaplink = BLI_heap_insert(heap, cost, e);
- else
- v->u.heaplink = NULL;
- }
+ if (e)
+ v->u.heaplink = BLI_heap_insert(heap, cost, e);
+ else
+ v->u.heaplink = NULL;
+ }
- for (e = chart->edges; e; e = e->nextlink)
- e->u.nextcollapse = NULL;
+ for (e = chart->edges; e; e = e->nextlink)
+ e->u.nextcollapse = NULL;
- /* pop edge collapse out of heap one by one */
- while (!BLI_heap_is_empty(heap)) {
- if (ncollapsed == NCOLLAPSE)
- break;
+ /* pop edge collapse out of heap one by one */
+ while (!BLI_heap_is_empty(heap)) {
+ if (ncollapsed == NCOLLAPSE)
+ break;
- HeapNode *link = BLI_heap_top(heap);
- PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair;
- PVert *oldv, *keepv;
- PEdge *wheele, *nexte;
+ HeapNode *link = BLI_heap_top(heap);
+ PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair;
+ PVert *oldv, *keepv;
+ PEdge *wheele, *nexte;
- /* remember the edges we collapsed */
- edge->u.nextcollapse = collapsededges;
- collapsededges = edge;
+ /* remember the edges we collapsed */
+ edge->u.nextcollapse = collapsededges;
+ collapsededges = edge;
- if (edge->vert->u.heaplink != link) {
- edge->flag |= (PEDGE_COLLAPSE_EDGE | PEDGE_COLLAPSE_PAIR);
- edge->next->vert->u.heaplink = NULL;
- SWAP(PEdge *, edge, pair);
- }
- else {
- edge->flag |= PEDGE_COLLAPSE_EDGE;
- edge->vert->u.heaplink = NULL;
- }
+ if (edge->vert->u.heaplink != link) {
+ edge->flag |= (PEDGE_COLLAPSE_EDGE | PEDGE_COLLAPSE_PAIR);
+ edge->next->vert->u.heaplink = NULL;
+ SWAP(PEdge *, edge, pair);
+ }
+ else {
+ edge->flag |= PEDGE_COLLAPSE_EDGE;
+ edge->vert->u.heaplink = NULL;
+ }
- p_collapsing_verts(edge, pair, &oldv, &keepv);
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
- /* gather all wheel verts and remember them before collapse */
- nwheelverts = 0;
- wheele = oldv->edge;
+ /* gather all wheel verts and remember them before collapse */
+ nwheelverts = 0;
+ wheele = oldv->edge;
- do {
- wheelverts[nwheelverts++] = wheele->next->vert;
- nexte = p_wheel_edge_next(wheele);
+ do {
+ wheelverts[nwheelverts++] = wheele->next->vert;
+ nexte = p_wheel_edge_next(wheele);
- if (nexte == NULL)
- wheelverts[nwheelverts++] = wheele->next->next->vert;
+ if (nexte == NULL)
+ wheelverts[nwheelverts++] = wheele->next->next->vert;
- wheele = nexte;
- } while (wheele && (wheele != oldv->edge));
+ wheele = nexte;
+ } while (wheele && (wheele != oldv->edge));
- /* collapse */
- p_collapse_edge(edge, pair);
+ /* collapse */
+ p_collapse_edge(edge, pair);
- for (i = 0; i < nwheelverts; i++) {
- float cost;
- PEdge *collapse = NULL;
+ for (i = 0; i < nwheelverts; i++) {
+ float cost;
+ PEdge *collapse = NULL;
- v = wheelverts[i];
+ v = wheelverts[i];
- if (v->u.heaplink) {
- BLI_heap_remove(heap, v->u.heaplink);
- v->u.heaplink = NULL;
- }
+ if (v->u.heaplink) {
+ BLI_heap_remove(heap, v->u.heaplink);
+ v->u.heaplink = NULL;
+ }
- p_collapse_cost_vertex(v, &cost, &collapse);
+ p_collapse_cost_vertex(v, &cost, &collapse);
- if (collapse)
- v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
- }
+ if (collapse)
+ v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
+ }
- ncollapsed++;
- }
+ ncollapsed++;
+ }
- MEM_freeN(wheelverts);
- BLI_heap_free(heap, NULL);
+ MEM_freeN(wheelverts);
+ BLI_heap_free(heap, NULL);
- p_chart_post_collapse_flush(chart, collapsededges);
+ p_chart_post_collapse_flush(chart, collapsededges);
}
static void p_chart_complexify(PChart *chart)
{
- PEdge *e, *pair, *edge;
- PVert *newv, *keepv;
- int x = 0;
+ PEdge *e, *pair, *edge;
+ PVert *newv, *keepv;
+ int x = 0;
- for (e = chart->collapsed_edges; e; e = e->nextlink) {
- if (!(e->flag & PEDGE_COLLAPSE_EDGE))
- break;
+ for (e = chart->collapsed_edges; e; e = e->nextlink) {
+ if (!(e->flag & PEDGE_COLLAPSE_EDGE))
+ break;
- edge = e;
- pair = e->pair;
+ edge = e;
+ pair = e->pair;
- if (edge->flag & PEDGE_COLLAPSE_PAIR) {
- SWAP(PEdge *, edge, pair);
- }
+ if (edge->flag & PEDGE_COLLAPSE_PAIR) {
+ SWAP(PEdge *, edge, pair);
+ }
- p_split_vertex(edge, pair);
- p_collapsing_verts(edge, pair, &newv, &keepv);
+ p_split_vertex(edge, pair);
+ p_collapsing_verts(edge, pair, &newv, &keepv);
- if (x >= NCOLLAPSEX) {
- newv->uv[0] = keepv->uv[0];
- newv->uv[1] = keepv->uv[1];
- }
- else {
- p_vert_harmonic_insert(newv);
- x++;
- }
- }
+ if (x >= NCOLLAPSEX) {
+ newv->uv[0] = keepv->uv[0];
+ newv->uv[1] = keepv->uv[1];
+ }
+ else {
+ p_vert_harmonic_insert(newv);
+ x++;
+ }
+ }
- p_chart_post_split_flush(chart);
+ p_chart_post_split_flush(chart);
}
-#if 0
+# if 0
static void p_chart_simplify(PChart *chart)
{
- /* Not implemented, needs proper reordering in split_flush. */
+ /* Not implemented, needs proper reordering in split_flush. */
}
-#endif
+# endif
#endif
/* ABF */
@@ -2300,925 +2316,937 @@ static void p_chart_simplify(PChart *chart)
#define ABF_MAX_ITER 20
typedef struct PAbfSystem {
- int ninterior, nfaces, nangles;
- float *alpha, *beta, *sine, *cosine, *weight;
- float *bAlpha, *bTriangle, *bInterior;
- float *lambdaTriangle, *lambdaPlanar, *lambdaLength;
- float (*J2dt)[3], *bstar, *dstar;
- float minangle, maxangle;
+ int ninterior, nfaces, nangles;
+ float *alpha, *beta, *sine, *cosine, *weight;
+ float *bAlpha, *bTriangle, *bInterior;
+ float *lambdaTriangle, *lambdaPlanar, *lambdaLength;
+ float (*J2dt)[3], *bstar, *dstar;
+ float minangle, maxangle;
} PAbfSystem;
static void p_abf_setup_system(PAbfSystem *sys)
{
- int i;
+ int i;
- sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha");
- sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta");
- sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine");
- sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine");
- sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight");
+ sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha");
+ sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta");
+ sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine");
+ sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine");
+ sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight");
- sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha");
- sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle");
- sys->bInterior = (float *)MEM_mallocN(sizeof(float) * 2 * sys->ninterior, "ABFbinterior");
+ sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha");
+ sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle");
+ sys->bInterior = (float *)MEM_mallocN(sizeof(float) * 2 * sys->ninterior, "ABFbinterior");
- sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri");
- sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane");
- sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen");
+ sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri");
+ sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane");
+ sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen");
- sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt");
- sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar");
- sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar");
+ sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt");
+ sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar");
+ sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar");
- for (i = 0; i < sys->ninterior; i++)
- sys->lambdaLength[i] = 1.0;
+ for (i = 0; i < sys->ninterior; i++)
+ sys->lambdaLength[i] = 1.0;
- sys->minangle = 1.0 * M_PI / 180.0;
- sys->maxangle = (float)M_PI - sys->minangle;
+ sys->minangle = 1.0 * M_PI / 180.0;
+ sys->maxangle = (float)M_PI - sys->minangle;
}
static void p_abf_free_system(PAbfSystem *sys)
{
- MEM_freeN(sys->alpha);
- MEM_freeN(sys->beta);
- MEM_freeN(sys->sine);
- MEM_freeN(sys->cosine);
- MEM_freeN(sys->weight);
- MEM_freeN(sys->bAlpha);
- MEM_freeN(sys->bTriangle);
- MEM_freeN(sys->bInterior);
- MEM_freeN(sys->lambdaTriangle);
- MEM_freeN(sys->lambdaPlanar);
- MEM_freeN(sys->lambdaLength);
- MEM_freeN(sys->J2dt);
- MEM_freeN(sys->bstar);
- MEM_freeN(sys->dstar);
+ MEM_freeN(sys->alpha);
+ MEM_freeN(sys->beta);
+ MEM_freeN(sys->sine);
+ MEM_freeN(sys->cosine);
+ MEM_freeN(sys->weight);
+ MEM_freeN(sys->bAlpha);
+ MEM_freeN(sys->bTriangle);
+ MEM_freeN(sys->bInterior);
+ MEM_freeN(sys->lambdaTriangle);
+ MEM_freeN(sys->lambdaPlanar);
+ MEM_freeN(sys->lambdaLength);
+ MEM_freeN(sys->J2dt);
+ MEM_freeN(sys->bstar);
+ MEM_freeN(sys->dstar);
}
static void p_abf_compute_sines(PAbfSystem *sys)
{
- int i;
- float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
+ int i;
+ float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
- for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
- *sine = sinf(*alpha);
- *cosine = cosf(*alpha);
- }
+ for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
+ *sine = sinf(*alpha);
+ *cosine = cosf(*alpha);
+ }
}
static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
{
- PEdge *e, *e1, *e2;
- float sin1, sin2;
+ PEdge *e, *e1, *e2;
+ float sin1, sin2;
- sin1 = sin2 = 1.0;
+ sin1 = sin2 = 1.0;
- e = v->edge;
- do {
- e1 = e->next;
- e2 = e->next->next;
+ e = v->edge;
+ do {
+ e1 = e->next;
+ e2 = e->next->next;
- if (aid == e1->u.id) {
- /* we are computing a derivative for this angle,
- * so we use cos and drop the other part */
- sin1 *= sys->cosine[e1->u.id];
- sin2 = 0.0;
- }
- else
- sin1 *= sys->sine[e1->u.id];
+ if (aid == e1->u.id) {
+ /* we are computing a derivative for this angle,
+ * so we use cos and drop the other part */
+ sin1 *= sys->cosine[e1->u.id];
+ sin2 = 0.0;
+ }
+ else
+ sin1 *= sys->sine[e1->u.id];
- if (aid == e2->u.id) {
- /* see above */
- sin1 = 0.0;
- sin2 *= sys->cosine[e2->u.id];
- }
- else
- sin2 *= sys->sine[e2->u.id];
+ if (aid == e2->u.id) {
+ /* see above */
+ sin1 = 0.0;
+ sin2 *= sys->cosine[e2->u.id];
+ }
+ else
+ sin2 *= sys->sine[e2->u.id];
- e = e->next->next->pair;
- } while (e && (e != v->edge));
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
- return (sin1 - sin2);
+ return (sin1 - sin2);
}
static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e)
{
- PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert;
- float deriv;
+ PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert;
+ float deriv;
- deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id];
- deriv += sys->lambdaTriangle[f->u.id];
+ deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id];
+ deriv += sys->lambdaTriangle[f->u.id];
- if (v->flag & PVERT_INTERIOR) {
- deriv += sys->lambdaPlanar[v->u.id];
- }
+ if (v->flag & PVERT_INTERIOR) {
+ deriv += sys->lambdaPlanar[v->u.id];
+ }
- if (v1->flag & PVERT_INTERIOR) {
- float product = p_abf_compute_sin_product(sys, v1, e->u.id);
- deriv += sys->lambdaLength[v1->u.id] * product;
- }
+ if (v1->flag & PVERT_INTERIOR) {
+ float product = p_abf_compute_sin_product(sys, v1, e->u.id);
+ deriv += sys->lambdaLength[v1->u.id] * product;
+ }
- if (v2->flag & PVERT_INTERIOR) {
- float product = p_abf_compute_sin_product(sys, v2, e->u.id);
- deriv += sys->lambdaLength[v2->u.id] * product;
- }
+ if (v2->flag & PVERT_INTERIOR) {
+ float product = p_abf_compute_sin_product(sys, v2, e->u.id);
+ deriv += sys->lambdaLength[v2->u.id] * product;
+ }
- return deriv;
+ return deriv;
}
static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
{
- PFace *f;
- PEdge *e;
- PVert *v;
- float norm = 0.0;
+ PFace *f;
+ PEdge *e;
+ PVert *v;
+ float norm = 0.0;
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- float gtriangle, galpha1, galpha2, galpha3;
+ for (f = chart->faces; f; f = f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ float gtriangle, galpha1, galpha2, galpha3;
- galpha1 = p_abf_compute_grad_alpha(sys, f, e1);
- galpha2 = p_abf_compute_grad_alpha(sys, f, e2);
- galpha3 = p_abf_compute_grad_alpha(sys, f, e3);
+ galpha1 = p_abf_compute_grad_alpha(sys, f, e1);
+ galpha2 = p_abf_compute_grad_alpha(sys, f, e2);
+ galpha3 = p_abf_compute_grad_alpha(sys, f, e3);
- sys->bAlpha[e1->u.id] = -galpha1;
- sys->bAlpha[e2->u.id] = -galpha2;
- sys->bAlpha[e3->u.id] = -galpha3;
+ sys->bAlpha[e1->u.id] = -galpha1;
+ sys->bAlpha[e2->u.id] = -galpha2;
+ sys->bAlpha[e3->u.id] = -galpha3;
- norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;
+ norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;
- gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI;
- sys->bTriangle[f->u.id] = -gtriangle;
- norm += gtriangle * gtriangle;
- }
+ gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI;
+ sys->bTriangle[f->u.id] = -gtriangle;
+ norm += gtriangle * gtriangle;
+ }
- for (v = chart->verts; v; v = v->nextlink) {
- if (v->flag & PVERT_INTERIOR) {
- float gplanar = -2 * M_PI, glength;
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (v->flag & PVERT_INTERIOR) {
+ float gplanar = -2 * M_PI, glength;
- e = v->edge;
- do {
- gplanar += sys->alpha[e->u.id];
- e = e->next->next->pair;
- } while (e && (e != v->edge));
+ e = v->edge;
+ do {
+ gplanar += sys->alpha[e->u.id];
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
- sys->bInterior[v->u.id] = -gplanar;
- norm += gplanar * gplanar;
+ sys->bInterior[v->u.id] = -gplanar;
+ norm += gplanar * gplanar;
- glength = p_abf_compute_sin_product(sys, v, -1);
- sys->bInterior[sys->ninterior + v->u.id] = -glength;
- norm += glength * glength;
- }
- }
+ glength = p_abf_compute_sin_product(sys, v, -1);
+ sys->bInterior[sys->ninterior + v->u.id] = -glength;
+ norm += glength * glength;
+ }
+ }
- return norm;
+ return norm;
}
static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
{
- PFace *f;
- PEdge *e;
- int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
- PBool success;
- LinearSolver *context;
-
- context = EIG_linear_solver_new(0, nvar, 1);
-
- for (i = 0; i < nvar; i++)
- EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
-
- for (f = chart->faces; f; f = f->nextlink) {
- float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
- float row1[6], row2[6], row3[6];
- int vid[6];
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
-
- wi1 = 1.0f / sys->weight[e1->u.id];
- wi2 = 1.0f / sys->weight[e2->u.id];
- wi3 = 1.0f / sys->weight[e3->u.id];
-
- /* bstar1 = (J1*dInv*bAlpha - bTriangle) */
- b = sys->bAlpha[e1->u.id] * wi1;
- b += sys->bAlpha[e2->u.id] * wi2;
- b += sys->bAlpha[e3->u.id] * wi3;
- b -= sys->bTriangle[f->u.id];
-
- /* si = J1*d*J1t */
- si = 1.0f / (wi1 + wi2 + wi3);
-
- /* J1t*si*bstar1 - bAlpha */
- beta[0] = b * si - sys->bAlpha[e1->u.id];
- beta[1] = b * si - sys->bAlpha[e2->u.id];
- beta[2] = b * si - sys->bAlpha[e3->u.id];
-
- /* use this later for computing other lambda's */
- sys->bstar[f->u.id] = b;
- sys->dstar[f->u.id] = si;
-
- /* set matrix */
- W[0][0] = si - sys->weight[e1->u.id]; W[0][1] = si; W[0][2] = si;
- W[1][0] = si; W[1][1] = si - sys->weight[e2->u.id]; W[1][2] = si;
- W[2][0] = si; W[2][1] = si; W[2][2] = si - sys->weight[e3->u.id];
-
- vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1;
-
- if (v1->flag & PVERT_INTERIOR) {
- vid[0] = v1->u.id;
- vid[3] = ninterior + v1->u.id;
-
- sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1;
- sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2;
- sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3;
-
- EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]);
- EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
-
- row1[0] = j2[0][0] * W[0][0];
- row2[0] = j2[0][0] * W[1][0];
- row3[0] = j2[0][0] * W[2][0];
-
- row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2];
- row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2];
- row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2];
- }
-
- if (v2->flag & PVERT_INTERIOR) {
- vid[1] = v2->u.id;
- vid[4] = ninterior + v2->u.id;
-
- sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1;
- sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2;
- sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3;
-
- EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]);
- EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
-
- row1[1] = j2[1][1] * W[0][1];
- row2[1] = j2[1][1] * W[1][1];
- row3[1] = j2[1][1] * W[2][1];
-
- row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2];
- row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2];
- row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2];
- }
-
- if (v3->flag & PVERT_INTERIOR) {
- vid[2] = v3->u.id;
- vid[5] = ninterior + v3->u.id;
-
- sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1;
- sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2;
- sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3;
-
- EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]);
- EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
-
- row1[2] = j2[2][2] * W[0][2];
- row2[2] = j2[2][2] * W[1][2];
- row3[2] = j2[2][2] * W[2][2];
-
- row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1];
- row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1];
- row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
- }
-
- for (i = 0; i < 3; i++) {
- int r = vid[i];
-
- if (r == -1)
- continue;
-
- for (j = 0; j < 6; j++) {
- int c = vid[j];
-
- if (c == -1)
- continue;
-
- if (i == 0)
- EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]);
- else
- EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]);
-
- if (i == 1)
- EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]);
- else
- EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]);
-
-
- if (i == 2)
- EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]);
- else
- EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]);
- }
- }
- }
-
- success = EIG_linear_solver_solve(context);
-
- if (success) {
- for (f = chart->faces; f; f = f->nextlink) {
- float dlambda1, pre[3], dalpha;
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
-
- pre[0] = pre[1] = pre[2] = 0.0;
-
- if (v1->flag & PVERT_INTERIOR) {
- float x = EIG_linear_solver_variable_get(context, 0, v1->u.id);
- float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id);
- pre[0] += sys->J2dt[e1->u.id][0] * x;
- pre[1] += sys->J2dt[e2->u.id][0] * x2;
- pre[2] += sys->J2dt[e3->u.id][0] * x2;
- }
-
- if (v2->flag & PVERT_INTERIOR) {
- float x = EIG_linear_solver_variable_get(context, 0, v2->u.id);
- float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id);
- pre[0] += sys->J2dt[e1->u.id][1] * x2;
- pre[1] += sys->J2dt[e2->u.id][1] * x;
- pre[2] += sys->J2dt[e3->u.id][1] * x2;
- }
-
- if (v3->flag & PVERT_INTERIOR) {
- float x = EIG_linear_solver_variable_get(context, 0, v3->u.id);
- float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id);
- pre[0] += sys->J2dt[e1->u.id][2] * x2;
- pre[1] += sys->J2dt[e2->u.id][2] * x2;
- pre[2] += sys->J2dt[e3->u.id][2] * x;
- }
-
- dlambda1 = pre[0] + pre[1] + pre[2];
- dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1);
-
- sys->lambdaTriangle[f->u.id] += dlambda1;
-
- dalpha = (sys->bAlpha[e1->u.id] - dlambda1);
- sys->alpha[e1->u.id] += dalpha / sys->weight[e1->u.id] - pre[0];
-
- dalpha = (sys->bAlpha[e2->u.id] - dlambda1);
- sys->alpha[e2->u.id] += dalpha / sys->weight[e2->u.id] - pre[1];
-
- dalpha = (sys->bAlpha[e3->u.id] - dlambda1);
- sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2];
-
- /* clamp */
- e = f->edge;
- do {
- if (sys->alpha[e->u.id] > (float)M_PI)
- sys->alpha[e->u.id] = (float)M_PI;
- else if (sys->alpha[e->u.id] < 0.0f)
- sys->alpha[e->u.id] = 0.0f;
- } while (e != f->edge);
- }
-
- for (i = 0; i < ninterior; i++) {
- sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
- sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
- }
- }
-
- EIG_linear_solver_delete(context);
-
- return success;
+ PFace *f;
+ PEdge *e;
+ int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
+ PBool success;
+ LinearSolver *context;
+
+ context = EIG_linear_solver_new(0, nvar, 1);
+
+ for (i = 0; i < nvar; i++)
+ EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
+
+ for (f = chart->faces; f; f = f->nextlink) {
+ float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
+ float row1[6], row2[6], row3[6];
+ int vid[6];
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ wi1 = 1.0f / sys->weight[e1->u.id];
+ wi2 = 1.0f / sys->weight[e2->u.id];
+ wi3 = 1.0f / sys->weight[e3->u.id];
+
+ /* bstar1 = (J1*dInv*bAlpha - bTriangle) */
+ b = sys->bAlpha[e1->u.id] * wi1;
+ b += sys->bAlpha[e2->u.id] * wi2;
+ b += sys->bAlpha[e3->u.id] * wi3;
+ b -= sys->bTriangle[f->u.id];
+
+ /* si = J1*d*J1t */
+ si = 1.0f / (wi1 + wi2 + wi3);
+
+ /* J1t*si*bstar1 - bAlpha */
+ beta[0] = b * si - sys->bAlpha[e1->u.id];
+ beta[1] = b * si - sys->bAlpha[e2->u.id];
+ beta[2] = b * si - sys->bAlpha[e3->u.id];
+
+ /* use this later for computing other lambda's */
+ sys->bstar[f->u.id] = b;
+ sys->dstar[f->u.id] = si;
+
+ /* set matrix */
+ W[0][0] = si - sys->weight[e1->u.id];
+ W[0][1] = si;
+ W[0][2] = si;
+ W[1][0] = si;
+ W[1][1] = si - sys->weight[e2->u.id];
+ W[1][2] = si;
+ W[2][0] = si;
+ W[2][1] = si;
+ W[2][2] = si - sys->weight[e3->u.id];
+
+ vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1;
+
+ if (v1->flag & PVERT_INTERIOR) {
+ vid[0] = v1->u.id;
+ vid[3] = ninterior + v1->u.id;
+
+ sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1;
+ sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2;
+ sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3;
+
+ EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]);
+ EIG_linear_solver_right_hand_side_add(
+ context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
+
+ row1[0] = j2[0][0] * W[0][0];
+ row2[0] = j2[0][0] * W[1][0];
+ row3[0] = j2[0][0] * W[2][0];
+
+ row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2];
+ row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2];
+ row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2];
+ }
+
+ if (v2->flag & PVERT_INTERIOR) {
+ vid[1] = v2->u.id;
+ vid[4] = ninterior + v2->u.id;
+
+ sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1;
+ sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2;
+ sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3;
+
+ EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]);
+ EIG_linear_solver_right_hand_side_add(
+ context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
+
+ row1[1] = j2[1][1] * W[0][1];
+ row2[1] = j2[1][1] * W[1][1];
+ row3[1] = j2[1][1] * W[2][1];
+
+ row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2];
+ row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2];
+ row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2];
+ }
+
+ if (v3->flag & PVERT_INTERIOR) {
+ vid[2] = v3->u.id;
+ vid[5] = ninterior + v3->u.id;
+
+ sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1;
+ sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2;
+ sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3;
+
+ EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]);
+ EIG_linear_solver_right_hand_side_add(
+ context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
+
+ row1[2] = j2[2][2] * W[0][2];
+ row2[2] = j2[2][2] * W[1][2];
+ row3[2] = j2[2][2] * W[2][2];
+
+ row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1];
+ row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1];
+ row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
+ }
+
+ for (i = 0; i < 3; i++) {
+ int r = vid[i];
+
+ if (r == -1)
+ continue;
+
+ for (j = 0; j < 6; j++) {
+ int c = vid[j];
+
+ if (c == -1)
+ continue;
+
+ if (i == 0)
+ EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]);
+ else
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]);
+
+ if (i == 1)
+ EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]);
+ else
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]);
+
+ if (i == 2)
+ EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]);
+ else
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]);
+ }
+ }
+ }
+
+ success = EIG_linear_solver_solve(context);
+
+ if (success) {
+ for (f = chart->faces; f; f = f->nextlink) {
+ float dlambda1, pre[3], dalpha;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ pre[0] = pre[1] = pre[2] = 0.0;
+
+ if (v1->flag & PVERT_INTERIOR) {
+ float x = EIG_linear_solver_variable_get(context, 0, v1->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id);
+ pre[0] += sys->J2dt[e1->u.id][0] * x;
+ pre[1] += sys->J2dt[e2->u.id][0] * x2;
+ pre[2] += sys->J2dt[e3->u.id][0] * x2;
+ }
+
+ if (v2->flag & PVERT_INTERIOR) {
+ float x = EIG_linear_solver_variable_get(context, 0, v2->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id);
+ pre[0] += sys->J2dt[e1->u.id][1] * x2;
+ pre[1] += sys->J2dt[e2->u.id][1] * x;
+ pre[2] += sys->J2dt[e3->u.id][1] * x2;
+ }
+
+ if (v3->flag & PVERT_INTERIOR) {
+ float x = EIG_linear_solver_variable_get(context, 0, v3->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id);
+ pre[0] += sys->J2dt[e1->u.id][2] * x2;
+ pre[1] += sys->J2dt[e2->u.id][2] * x2;
+ pre[2] += sys->J2dt[e3->u.id][2] * x;
+ }
+
+ dlambda1 = pre[0] + pre[1] + pre[2];
+ dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1);
+
+ sys->lambdaTriangle[f->u.id] += dlambda1;
+
+ dalpha = (sys->bAlpha[e1->u.id] - dlambda1);
+ sys->alpha[e1->u.id] += dalpha / sys->weight[e1->u.id] - pre[0];
+
+ dalpha = (sys->bAlpha[e2->u.id] - dlambda1);
+ sys->alpha[e2->u.id] += dalpha / sys->weight[e2->u.id] - pre[1];
+
+ dalpha = (sys->bAlpha[e3->u.id] - dlambda1);
+ sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2];
+
+ /* clamp */
+ e = f->edge;
+ do {
+ if (sys->alpha[e->u.id] > (float)M_PI)
+ sys->alpha[e->u.id] = (float)M_PI;
+ else if (sys->alpha[e->u.id] < 0.0f)
+ sys->alpha[e->u.id] = 0.0f;
+ } while (e != f->edge);
+ }
+
+ for (i = 0; i < ninterior; i++) {
+ sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
+ sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
+ }
+ }
+
+ EIG_linear_solver_delete(context);
+
+ return success;
}
static PBool p_chart_abf_solve(PChart *chart)
{
- PVert *v;
- PFace *f;
- PEdge *e, *e1, *e2, *e3;
- PAbfSystem sys;
- int i;
- float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f;
-
- /* setup id's */
- sys.ninterior = sys.nfaces = sys.nangles = 0;
-
- for (v = chart->verts; v; v = v->nextlink) {
- if (p_vert_interior(v)) {
- v->flag |= PVERT_INTERIOR;
- v->u.id = sys.ninterior++;
- }
- else
- v->flag &= ~PVERT_INTERIOR;
- }
-
- for (f = chart->faces; f; f = f->nextlink) {
- e1 = f->edge; e2 = e1->next; e3 = e2->next;
- f->u.id = sys.nfaces++;
-
- /* angle id's are conveniently stored in half edges */
- e1->u.id = sys.nangles++;
- e2->u.id = sys.nangles++;
- e3->u.id = sys.nangles++;
- }
-
- p_abf_setup_system(&sys);
-
- /* compute initial angles */
- for (f = chart->faces; f; f = f->nextlink) {
- float a1, a2, a3;
-
- e1 = f->edge; e2 = e1->next; e3 = e2->next;
- p_face_angles(f, &a1, &a2, &a3);
-
- if (a1 < sys.minangle)
- a1 = sys.minangle;
- else if (a1 > sys.maxangle)
- a1 = sys.maxangle;
- if (a2 < sys.minangle)
- a2 = sys.minangle;
- else if (a2 > sys.maxangle)
- a2 = sys.maxangle;
- if (a3 < sys.minangle)
- a3 = sys.minangle;
- else if (a3 > sys.maxangle)
- a3 = sys.maxangle;
-
- sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
- sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
- sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;
-
- sys.weight[e1->u.id] = 2.0f / (a1 * a1);
- sys.weight[e2->u.id] = 2.0f / (a2 * a2);
- sys.weight[e3->u.id] = 2.0f / (a3 * a3);
- }
-
- for (v = chart->verts; v; v = v->nextlink) {
- if (v->flag & PVERT_INTERIOR) {
- float anglesum = 0.0, scale;
-
- e = v->edge;
- do {
- anglesum += sys.beta[e->u.id];
- e = e->next->next->pair;
- } while (e && (e != v->edge));
-
- scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum;
-
- e = v->edge;
- do {
- sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale;
- e = e->next->next->pair;
- } while (e && (e != v->edge));
- }
- }
-
- if (sys.ninterior > 0) {
- p_abf_compute_sines(&sys);
-
- /* iteration */
- /* lastnorm = 1e10; */ /* UNUSED */
-
- for (i = 0; i < ABF_MAX_ITER; i++) {
- float norm = p_abf_compute_gradient(&sys, chart);
-
- /* lastnorm = norm; */ /* UNUSED */
-
- if (norm < limit)
- break;
-
- if (!p_abf_matrix_invert(&sys, chart)) {
- param_warning("ABF failed to invert matrix");
- p_abf_free_system(&sys);
- return P_FALSE;
- }
-
- p_abf_compute_sines(&sys);
- }
-
- if (i == ABF_MAX_ITER) {
- param_warning("ABF maximum iterations reached");
- p_abf_free_system(&sys);
- return P_FALSE;
- }
- }
-
- chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
- p_abf_free_system(&sys);
-
- return P_TRUE;
+ PVert *v;
+ PFace *f;
+ PEdge *e, *e1, *e2, *e3;
+ PAbfSystem sys;
+ int i;
+ float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f;
+
+ /* setup id's */
+ sys.ninterior = sys.nfaces = sys.nangles = 0;
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (p_vert_interior(v)) {
+ v->flag |= PVERT_INTERIOR;
+ v->u.id = sys.ninterior++;
+ }
+ else
+ v->flag &= ~PVERT_INTERIOR;
+ }
+
+ for (f = chart->faces; f; f = f->nextlink) {
+ e1 = f->edge;
+ e2 = e1->next;
+ e3 = e2->next;
+ f->u.id = sys.nfaces++;
+
+ /* angle id's are conveniently stored in half edges */
+ e1->u.id = sys.nangles++;
+ e2->u.id = sys.nangles++;
+ e3->u.id = sys.nangles++;
+ }
+
+ p_abf_setup_system(&sys);
+
+ /* compute initial angles */
+ for (f = chart->faces; f; f = f->nextlink) {
+ float a1, a2, a3;
+
+ e1 = f->edge;
+ e2 = e1->next;
+ e3 = e2->next;
+ p_face_angles(f, &a1, &a2, &a3);
+
+ if (a1 < sys.minangle)
+ a1 = sys.minangle;
+ else if (a1 > sys.maxangle)
+ a1 = sys.maxangle;
+ if (a2 < sys.minangle)
+ a2 = sys.minangle;
+ else if (a2 > sys.maxangle)
+ a2 = sys.maxangle;
+ if (a3 < sys.minangle)
+ a3 = sys.minangle;
+ else if (a3 > sys.maxangle)
+ a3 = sys.maxangle;
+
+ sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
+ sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
+ sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;
+
+ sys.weight[e1->u.id] = 2.0f / (a1 * a1);
+ sys.weight[e2->u.id] = 2.0f / (a2 * a2);
+ sys.weight[e3->u.id] = 2.0f / (a3 * a3);
+ }
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (v->flag & PVERT_INTERIOR) {
+ float anglesum = 0.0, scale;
+
+ e = v->edge;
+ do {
+ anglesum += sys.beta[e->u.id];
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+
+ scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum;
+
+ e = v->edge;
+ do {
+ sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale;
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+ }
+ }
+
+ if (sys.ninterior > 0) {
+ p_abf_compute_sines(&sys);
+
+ /* iteration */
+ /* lastnorm = 1e10; */ /* UNUSED */
+
+ for (i = 0; i < ABF_MAX_ITER; i++) {
+ float norm = p_abf_compute_gradient(&sys, chart);
+
+ /* lastnorm = norm; */ /* UNUSED */
+
+ if (norm < limit)
+ break;
+
+ if (!p_abf_matrix_invert(&sys, chart)) {
+ param_warning("ABF failed to invert matrix");
+ p_abf_free_system(&sys);
+ return P_FALSE;
+ }
+
+ p_abf_compute_sines(&sys);
+ }
+
+ if (i == ABF_MAX_ITER) {
+ param_warning("ABF maximum iterations reached");
+ p_abf_free_system(&sys);
+ return P_FALSE;
+ }
+ }
+
+ chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
+ p_abf_free_system(&sys);
+
+ return P_TRUE;
}
/* Least Squares Conformal Maps */
static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
{
- if (!*pin1 || !*pin2 || *pin1 == *pin2) {
- /* degenerate case */
- PFace *f = chart->faces;
- *pin1 = f->edge->vert;
- *pin2 = f->edge->next->vert;
-
- (*pin1)->uv[0] = 0.0f;
- (*pin1)->uv[1] = 0.5f;
- (*pin2)->uv[0] = 1.0f;
- (*pin2)->uv[1] = 0.5f;
- }
- else {
- int diru, dirv, dirx, diry;
- float sub[3];
-
- sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co);
- sub[0] = fabsf(sub[0]);
- sub[1] = fabsf(sub[1]);
- sub[2] = fabsf(sub[2]);
-
- if ((sub[0] > sub[1]) && (sub[0] > sub[2])) {
- dirx = 0;
- diry = (sub[1] > sub[2]) ? 1 : 2;
- }
- else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) {
- dirx = 1;
- diry = (sub[0] > sub[2]) ? 0 : 2;
- }
- else {
- dirx = 2;
- diry = (sub[0] > sub[1]) ? 0 : 1;
- }
-
- if (dirx == 2) {
- diru = 1;
- dirv = 0;
- }
- else {
- diru = 0;
- dirv = 1;
- }
-
- (*pin1)->uv[diru] = (*pin1)->co[dirx];
- (*pin1)->uv[dirv] = (*pin1)->co[diry];
- (*pin2)->uv[diru] = (*pin2)->co[dirx];
- (*pin2)->uv[dirv] = (*pin2)->co[diry];
- }
+ if (!*pin1 || !*pin2 || *pin1 == *pin2) {
+ /* degenerate case */
+ PFace *f = chart->faces;
+ *pin1 = f->edge->vert;
+ *pin2 = f->edge->next->vert;
+
+ (*pin1)->uv[0] = 0.0f;
+ (*pin1)->uv[1] = 0.5f;
+ (*pin2)->uv[0] = 1.0f;
+ (*pin2)->uv[1] = 0.5f;
+ }
+ else {
+ int diru, dirv, dirx, diry;
+ float sub[3];
+
+ sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co);
+ sub[0] = fabsf(sub[0]);
+ sub[1] = fabsf(sub[1]);
+ sub[2] = fabsf(sub[2]);
+
+ if ((sub[0] > sub[1]) && (sub[0] > sub[2])) {
+ dirx = 0;
+ diry = (sub[1] > sub[2]) ? 1 : 2;
+ }
+ else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) {
+ dirx = 1;
+ diry = (sub[0] > sub[2]) ? 0 : 2;
+ }
+ else {
+ dirx = 2;
+ diry = (sub[0] > sub[1]) ? 0 : 1;
+ }
+
+ if (dirx == 2) {
+ diru = 1;
+ dirv = 0;
+ }
+ else {
+ diru = 0;
+ dirv = 1;
+ }
+
+ (*pin1)->uv[diru] = (*pin1)->co[dirx];
+ (*pin1)->uv[dirv] = (*pin1)->co[diry];
+ (*pin2)->uv[diru] = (*pin2)->co[dirx];
+ (*pin2)->uv[dirv] = (*pin2)->co[diry];
+ }
}
static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
{
- PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
- PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
- float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
- float len1, len2;
-
- /* find longest series of verts split in the chart itself, these are
- * marked during construction */
- be = outer;
- lastbe = p_boundary_edge_prev(be);
- do {
- float len = p_edge_length(be);
- totlen += len;
-
- nextbe = p_boundary_edge_next(be);
-
- if ((be->vert->flag & PVERT_SPLIT) ||
- (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT))
- {
- if (!cure) {
- if (be == outer)
- firste1 = be;
- cure = be;
- }
- else
- curlen += p_edge_length(lastbe);
- }
- else if (cure) {
- if (curlen > maxlen) {
- maxlen = curlen;
- maxe1 = cure;
- maxe2 = lastbe;
- }
-
- if (firste1 == cure) {
- firstlen = curlen;
- firste2 = lastbe;
- }
-
- curlen = 0.0f;
- cure = NULL;
- }
-
- lastbe = be;
- be = nextbe;
- } while (be != outer);
-
- /* make sure we also count a series of splits over the starting point */
- if (cure && (cure != outer)) {
- firstlen += curlen + p_edge_length(be);
-
- if (firstlen > maxlen) {
- maxlen = firstlen;
- maxe1 = cure;
- maxe2 = firste2;
- }
- }
-
- if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen))
- return P_FALSE;
-
- /* find pin1 in the split vertices */
- be1 = maxe1;
- be2 = maxe2;
- len1 = 0.0f;
- len2 = 0.0f;
-
- do {
- if (len1 < len2) {
- len1 += p_edge_length(be1);
- be1 = p_boundary_edge_next(be1);
- }
- else {
- be2 = p_boundary_edge_prev(be2);
- len2 += p_edge_length(be2);
- }
- } while (be1 != be2);
-
- *pin1 = be1->vert;
-
- /* find pin2 outside the split vertices */
- be1 = maxe1;
- be2 = maxe2;
- len1 = 0.0f;
- len2 = 0.0f;
-
- do {
- if (len1 < len2) {
- be1 = p_boundary_edge_prev(be1);
- len1 += p_edge_length(be1);
- }
- else {
- len2 += p_edge_length(be2);
- be2 = p_boundary_edge_next(be2);
- }
- } while (be1 != be2);
-
- *pin2 = be1->vert;
-
- p_chart_pin_positions(chart, pin1, pin2);
-
- return !equals_v3v3((*pin1)->co, (*pin2)->co);
+ PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
+ PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
+ float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
+ float len1, len2;
+
+ /* find longest series of verts split in the chart itself, these are
+ * marked during construction */
+ be = outer;
+ lastbe = p_boundary_edge_prev(be);
+ do {
+ float len = p_edge_length(be);
+ totlen += len;
+
+ nextbe = p_boundary_edge_next(be);
+
+ if ((be->vert->flag & PVERT_SPLIT) ||
+ (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) {
+ if (!cure) {
+ if (be == outer)
+ firste1 = be;
+ cure = be;
+ }
+ else
+ curlen += p_edge_length(lastbe);
+ }
+ else if (cure) {
+ if (curlen > maxlen) {
+ maxlen = curlen;
+ maxe1 = cure;
+ maxe2 = lastbe;
+ }
+
+ if (firste1 == cure) {
+ firstlen = curlen;
+ firste2 = lastbe;
+ }
+
+ curlen = 0.0f;
+ cure = NULL;
+ }
+
+ lastbe = be;
+ be = nextbe;
+ } while (be != outer);
+
+ /* make sure we also count a series of splits over the starting point */
+ if (cure && (cure != outer)) {
+ firstlen += curlen + p_edge_length(be);
+
+ if (firstlen > maxlen) {
+ maxlen = firstlen;
+ maxe1 = cure;
+ maxe2 = firste2;
+ }
+ }
+
+ if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen))
+ return P_FALSE;
+
+ /* find pin1 in the split vertices */
+ be1 = maxe1;
+ be2 = maxe2;
+ len1 = 0.0f;
+ len2 = 0.0f;
+
+ do {
+ if (len1 < len2) {
+ len1 += p_edge_length(be1);
+ be1 = p_boundary_edge_next(be1);
+ }
+ else {
+ be2 = p_boundary_edge_prev(be2);
+ len2 += p_edge_length(be2);
+ }
+ } while (be1 != be2);
+
+ *pin1 = be1->vert;
+
+ /* find pin2 outside the split vertices */
+ be1 = maxe1;
+ be2 = maxe2;
+ len1 = 0.0f;
+ len2 = 0.0f;
+
+ do {
+ if (len1 < len2) {
+ be1 = p_boundary_edge_prev(be1);
+ len1 += p_edge_length(be1);
+ }
+ else {
+ len2 += p_edge_length(be2);
+ be2 = p_boundary_edge_next(be2);
+ }
+ } while (be1 != be2);
+
+ *pin2 = be1->vert;
+
+ p_chart_pin_positions(chart, pin1, pin2);
+
+ return !equals_v3v3((*pin1)->co, (*pin2)->co);
}
static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
{
- float minv[3], maxv[3], dirlen;
- PVert *v, *minvert[3], *maxvert[3];
- int i, dir;
+ float minv[3], maxv[3], dirlen;
+ PVert *v, *minvert[3], *maxvert[3];
+ int i, dir;
- /* find minimum and maximum verts over x/y/z axes */
- minv[0] = minv[1] = minv[2] = 1e20;
- maxv[0] = maxv[1] = maxv[2] = -1e20;
+ /* find minimum and maximum verts over x/y/z axes */
+ minv[0] = minv[1] = minv[2] = 1e20;
+ maxv[0] = maxv[1] = maxv[2] = -1e20;
- minvert[0] = minvert[1] = minvert[2] = NULL;
- maxvert[0] = maxvert[1] = maxvert[2] = NULL;
+ minvert[0] = minvert[1] = minvert[2] = NULL;
+ maxvert[0] = maxvert[1] = maxvert[2] = NULL;
- for (v = chart->verts; v; v = v->nextlink) {
- for (i = 0; i < 3; i++) {
- if (v->co[i] < minv[i]) {
- minv[i] = v->co[i];
- minvert[i] = v;
- }
- if (v->co[i] > maxv[i]) {
- maxv[i] = v->co[i];
- maxvert[i] = v;
- }
- }
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ for (i = 0; i < 3; i++) {
+ if (v->co[i] < minv[i]) {
+ minv[i] = v->co[i];
+ minvert[i] = v;
+ }
+ if (v->co[i] > maxv[i]) {
+ maxv[i] = v->co[i];
+ maxvert[i] = v;
+ }
+ }
+ }
- /* find axes with longest distance */
- dir = 0;
- dirlen = -1.0;
+ /* find axes with longest distance */
+ dir = 0;
+ dirlen = -1.0;
- for (i = 0; i < 3; i++) {
- if (maxv[i] - minv[i] > dirlen) {
- dir = i;
- dirlen = maxv[i] - minv[i];
- }
- }
+ for (i = 0; i < 3; i++) {
+ if (maxv[i] - minv[i] > dirlen) {
+ dir = i;
+ dirlen = maxv[i] - minv[i];
+ }
+ }
- *pin1 = minvert[dir];
- *pin2 = maxvert[dir];
+ *pin1 = minvert[dir];
+ *pin2 = maxvert[dir];
- p_chart_pin_positions(chart, pin1, pin2);
+ p_chart_pin_positions(chart, pin1, pin2);
}
static void p_chart_lscm_load_solution(PChart *chart)
{
- LinearSolver *context = chart->u.lscm.context;
- PVert *v;
+ LinearSolver *context = chart->u.lscm.context;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id);
- v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1);
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id);
+ v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1);
+ }
}
static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
{
- PVert *v, *pin1, *pin2;
- PBool select = P_FALSE, deselect = P_FALSE;
- int npins = 0, id = 0;
-
- /* give vertices matrix indices and count pins */
- for (v = chart->verts; v; v = v->nextlink) {
- if (v->flag & PVERT_PIN) {
- npins++;
- if (v->flag & PVERT_SELECT)
- select = P_TRUE;
- }
-
- if (!(v->flag & PVERT_SELECT))
- deselect = P_TRUE;
- }
-
- if ((live && (!select || !deselect)) || (npins == 1)) {
- chart->u.lscm.context = NULL;
- }
- else {
+ PVert *v, *pin1, *pin2;
+ PBool select = P_FALSE, deselect = P_FALSE;
+ int npins = 0, id = 0;
+
+ /* give vertices matrix indices and count pins */
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (v->flag & PVERT_PIN) {
+ npins++;
+ if (v->flag & PVERT_SELECT)
+ select = P_TRUE;
+ }
+
+ if (!(v->flag & PVERT_SELECT))
+ deselect = P_TRUE;
+ }
+
+ if ((live && (!select || !deselect)) || (npins == 1)) {
+ chart->u.lscm.context = NULL;
+ }
+ else {
#if 0
- p_chart_simplify_compute(chart);
- p_chart_topological_sanity_check(chart);
+ p_chart_simplify_compute(chart);
+ p_chart_topological_sanity_check(chart);
#endif
- if (abf) {
- if (!p_chart_abf_solve(chart))
- param_warning("ABF solving failed: falling back to LSCM.\n");
- }
+ if (abf) {
+ if (!p_chart_abf_solve(chart))
+ param_warning("ABF solving failed: falling back to LSCM.\n");
+ }
- if (npins <= 1) {
- /* not enough pins, lets find some ourself */
- PEdge *outer;
+ if (npins <= 1) {
+ /* not enough pins, lets find some ourself */
+ PEdge *outer;
- p_chart_boundaries(chart, NULL, &outer);
+ p_chart_boundaries(chart, NULL, &outer);
- /* outer can be NULL with non-finite coords. */
- if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
- p_chart_extrema_verts(chart, &pin1, &pin2);
- }
+ /* outer can be NULL with non-finite coords. */
+ if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
+ p_chart_extrema_verts(chart, &pin1, &pin2);
+ }
- chart->u.lscm.pin1 = pin1;
- chart->u.lscm.pin2 = pin2;
- }
+ chart->u.lscm.pin1 = pin1;
+ chart->u.lscm.pin2 = pin2;
+ }
- for (v = chart->verts; v; v = v->nextlink)
- v->u.id = id++;
+ for (v = chart->verts; v; v = v->nextlink)
+ v->u.id = id++;
- chart->u.lscm.context = EIG_linear_least_squares_solver_new(2 * chart->nfaces, 2 * chart->nverts, 1);
- }
+ chart->u.lscm.context = EIG_linear_least_squares_solver_new(
+ 2 * chart->nfaces, 2 * chart->nverts, 1);
+ }
}
static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
{
- LinearSolver *context = chart->u.lscm.context;
- PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
- PFace *f;
- float *alpha = chart->u.lscm.abf_alpha;
- float area_pinned_up, area_pinned_down;
- bool flip_faces;
- int row;
+ LinearSolver *context = chart->u.lscm.context;
+ PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
+ PFace *f;
+ float *alpha = chart->u.lscm.abf_alpha;
+ float area_pinned_up, area_pinned_down;
+ bool flip_faces;
+ int row;
#if 0
- /* TODO: make loading pins work for simplify/complexify. */
+ /* TODO: make loading pins work for simplify/complexify. */
#endif
- for (v = chart->verts; v; v = v->nextlink)
- if (v->flag & PVERT_PIN)
- p_vert_load_pin_select_uvs(handle, v); /* reload for live */
-
- if (chart->u.lscm.pin1) {
- EIG_linear_solver_variable_lock(context, 2 * pin1->u.id);
- EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
- EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
- EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1);
-
- EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]);
- EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]);
- EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]);
- EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
- }
- else {
- /* set and lock the pins */
- for (v = chart->verts; v; v = v->nextlink) {
- if (v->flag & PVERT_PIN) {
- EIG_linear_solver_variable_lock(context, 2 * v->u.id);
- EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
-
- EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]);
- EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]);
- }
- }
- }
-
- /* detect up direction based on pinned vertices */
- area_pinned_up = 0.0f;
- area_pinned_down = 0.0f;
-
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
-
- if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) {
- float area = p_face_uv_area_signed(f);
-
- if (area > 0.0f)
- area_pinned_up += area;
- else
- area_pinned_down -= area;
- }
- }
-
- flip_faces = (area_pinned_down > area_pinned_up);
-
- /* construct matrix */
-
- row = 0;
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- float a1, a2, a3, ratio, cosine, sine;
- float sina1, sina2, sina3, sinmax;
-
- if (alpha) {
- /* use abf angles if passed on */
- a1 = *(alpha++);
- a2 = *(alpha++);
- a3 = *(alpha++);
- }
- else
- p_face_angles(f, &a1, &a2, &a3);
-
- if (flip_faces) {
- SWAP(float, a2, a3);
- SWAP(PEdge *, e2, e3);
- SWAP(PVert *, v2, v3);
- }
-
- sina1 = sinf(a1);
- sina2 = sinf(a2);
- sina3 = sinf(a3);
-
- sinmax = max_fff(sina1, sina2, sina3);
-
- /* shift vertices to find most stable order */
- if (sina3 != sinmax) {
- SHIFT3(PVert *, v1, v2, v3);
- SHIFT3(float, a1, a2, a3);
- SHIFT3(float, sina1, sina2, sina3);
-
- if (sina2 == sinmax) {
- SHIFT3(PVert *, v1, v2, v3);
- SHIFT3(float, a1, a2, a3);
- SHIFT3(float, sina1, sina2, sina3);
- }
- }
-
- /* angle based lscm formulation */
- ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
- cosine = cosf(a1) * ratio;
- sine = sina1 * ratio;
-
- EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
- EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
- EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine);
- EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine);
- EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0);
- row++;
-
- EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine);
- EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f);
- EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine);
- EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine);
- EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0);
- row++;
- }
-
- if (EIG_linear_solver_solve(context)) {
- p_chart_lscm_load_solution(chart);
- return P_TRUE;
- }
- else {
- for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] = 0.0f;
- v->uv[1] = 0.0f;
- }
- }
-
- return P_FALSE;
+ for (v = chart->verts; v; v = v->nextlink)
+ if (v->flag & PVERT_PIN)
+ p_vert_load_pin_select_uvs(handle, v); /* reload for live */
+
+ if (chart->u.lscm.pin1) {
+ EIG_linear_solver_variable_lock(context, 2 * pin1->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
+ EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1);
+
+ EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
+ }
+ else {
+ /* set and lock the pins */
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (v->flag & PVERT_PIN) {
+ EIG_linear_solver_variable_lock(context, 2 * v->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
+
+ EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]);
+ }
+ }
+ }
+
+ /* detect up direction based on pinned vertices */
+ area_pinned_up = 0.0f;
+ area_pinned_down = 0.0f;
+
+ for (f = chart->faces; f; f = f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) {
+ float area = p_face_uv_area_signed(f);
+
+ if (area > 0.0f)
+ area_pinned_up += area;
+ else
+ area_pinned_down -= area;
+ }
+ }
+
+ flip_faces = (area_pinned_down > area_pinned_up);
+
+ /* construct matrix */
+
+ row = 0;
+ for (f = chart->faces; f; f = f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ float a1, a2, a3, ratio, cosine, sine;
+ float sina1, sina2, sina3, sinmax;
+
+ if (alpha) {
+ /* use abf angles if passed on */
+ a1 = *(alpha++);
+ a2 = *(alpha++);
+ a3 = *(alpha++);
+ }
+ else
+ p_face_angles(f, &a1, &a2, &a3);
+
+ if (flip_faces) {
+ SWAP(float, a2, a3);
+ SWAP(PEdge *, e2, e3);
+ SWAP(PVert *, v2, v3);
+ }
+
+ sina1 = sinf(a1);
+ sina2 = sinf(a2);
+ sina3 = sinf(a3);
+
+ sinmax = max_fff(sina1, sina2, sina3);
+
+ /* shift vertices to find most stable order */
+ if (sina3 != sinmax) {
+ SHIFT3(PVert *, v1, v2, v3);
+ SHIFT3(float, a1, a2, a3);
+ SHIFT3(float, sina1, sina2, sina3);
+
+ if (sina2 == sinmax) {
+ SHIFT3(PVert *, v1, v2, v3);
+ SHIFT3(float, a1, a2, a3);
+ SHIFT3(float, sina1, sina2, sina3);
+ }
+ }
+
+ /* angle based lscm formulation */
+ ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3;
+ cosine = cosf(a1) * ratio;
+ sine = sina1 * ratio;
+
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0);
+ row++;
+
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0);
+ row++;
+ }
+
+ if (EIG_linear_solver_solve(context)) {
+ p_chart_lscm_load_solution(chart);
+ return P_TRUE;
+ }
+ else {
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->uv[0] = 0.0f;
+ v->uv[1] = 0.0f;
+ }
+ }
+
+ return P_FALSE;
}
static void p_chart_lscm_end(PChart *chart)
{
- if (chart->u.lscm.context)
- EIG_linear_solver_delete(chart->u.lscm.context);
+ if (chart->u.lscm.context)
+ EIG_linear_solver_delete(chart->u.lscm.context);
- if (chart->u.lscm.abf_alpha) {
- MEM_freeN(chart->u.lscm.abf_alpha);
- chart->u.lscm.abf_alpha = NULL;
- }
+ if (chart->u.lscm.abf_alpha) {
+ MEM_freeN(chart->u.lscm.abf_alpha);
+ chart->u.lscm.abf_alpha = NULL;
+ }
- chart->u.lscm.context = NULL;
- chart->u.lscm.pin1 = NULL;
- chart->u.lscm.pin2 = NULL;
+ chart->u.lscm.context = NULL;
+ chart->u.lscm.pin1 = NULL;
+ chart->u.lscm.pin2 = NULL;
}
/* Stretch */
@@ -3227,386 +3255,386 @@ static void p_chart_lscm_end(PChart *chart)
static void p_stretch_pin_boundary(PChart *chart)
{
- PVert *v;
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink)
- if (v->edge->pair == NULL)
- v->flag |= PVERT_PIN;
- else
- v->flag &= ~PVERT_PIN;
+ for (v = chart->verts; v; v = v->nextlink)
+ if (v->edge->pair == NULL)
+ v->flag |= PVERT_PIN;
+ else
+ v->flag &= ~PVERT_PIN;
}
static float p_face_stretch(PFace *f)
{
- float T, w, tmp[3];
- float Ps[3], Pt[3];
- float a, c, area;
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ float T, w, tmp[3];
+ float Ps[3], Pt[3];
+ float a, c, area;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
- area = p_face_uv_area_signed(f);
+ area = p_face_uv_area_signed(f);
- if (area <= 0.0f) /* flipped face -> infinite stretch */
- return 1e10f;
+ if (area <= 0.0f) /* flipped face -> infinite stretch */
+ return 1e10f;
- w = 1.0f / (2.0f * area);
+ w = 1.0f / (2.0f * area);
- /* compute derivatives */
- copy_v3_v3(Ps, v1->co);
- mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1]));
+ /* compute derivatives */
+ copy_v3_v3(Ps, v1->co);
+ mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1]));
- copy_v3_v3(tmp, v2->co);
- mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1]));
- add_v3_v3(Ps, tmp);
+ copy_v3_v3(tmp, v2->co);
+ mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1]));
+ add_v3_v3(Ps, tmp);
- copy_v3_v3(tmp, v3->co);
- mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1]));
- add_v3_v3(Ps, tmp);
+ copy_v3_v3(tmp, v3->co);
+ mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1]));
+ add_v3_v3(Ps, tmp);
- mul_v3_fl(Ps, w);
+ mul_v3_fl(Ps, w);
- copy_v3_v3(Pt, v1->co);
- mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0]));
+ copy_v3_v3(Pt, v1->co);
+ mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0]));
- copy_v3_v3(tmp, v2->co);
- mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0]));
- add_v3_v3(Pt, tmp);
+ copy_v3_v3(tmp, v2->co);
+ mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0]));
+ add_v3_v3(Pt, tmp);
- copy_v3_v3(tmp, v3->co);
- mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0]));
- add_v3_v3(Pt, tmp);
+ copy_v3_v3(tmp, v3->co);
+ mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0]));
+ add_v3_v3(Pt, tmp);
- mul_v3_fl(Pt, w);
+ mul_v3_fl(Pt, w);
- /* Sander Tensor */
- a = dot_v3v3(Ps, Ps);
- c = dot_v3v3(Pt, Pt);
+ /* Sander Tensor */
+ a = dot_v3v3(Ps, Ps);
+ c = dot_v3v3(Pt, Pt);
- T = sqrtf(0.5f * (a + c));
- if (f->flag & PFACE_FILLED)
- T *= 0.2f;
+ T = sqrtf(0.5f * (a + c));
+ if (f->flag & PFACE_FILLED)
+ T *= 0.2f;
- return T;
+ return T;
}
static float p_stretch_compute_vertex(PVert *v)
{
- PEdge *e = v->edge;
- float sum = 0.0f;
+ PEdge *e = v->edge;
+ float sum = 0.0f;
- do {
- sum += p_face_stretch(e->face);
- e = p_wheel_edge_next(e);
- } while (e && e != (v->edge));
+ do {
+ sum += p_face_stretch(e->face);
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
- return sum;
+ return sum;
}
static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
{
- PVert *v;
- PEdge *e;
- int j, nedges;
- float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch;
- float orig_uv[2], dir[2], random_angle, trusted_radius;
-
- for (v = chart->verts; v; v = v->nextlink) {
- if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT))
- continue;
-
- orig_stretch = p_stretch_compute_vertex(v);
- orig_uv[0] = v->uv[0];
- orig_uv[1] = v->uv[1];
-
- /* move vertex in a random direction */
- trusted_radius = 0.0f;
- nedges = 0;
- e = v->edge;
-
- do {
- trusted_radius += p_edge_uv_length(e);
- nedges++;
-
- e = p_wheel_edge_next(e);
- } while (e && e != (v->edge));
-
- trusted_radius /= 2 * nedges;
-
- random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI;
- dir[0] = trusted_radius * cosf(random_angle);
- dir[1] = trusted_radius * sinf(random_angle);
-
- /* calculate old and new stretch */
- low = 0;
- stretch_low = orig_stretch;
-
- add_v2_v2v2(v->uv, orig_uv, dir);
- high = 1;
- stretch = stretch_high = p_stretch_compute_vertex(v);
-
- /* binary search for lowest stretch position */
- for (j = 0; j < P_STRETCH_ITER; j++) {
- mid = 0.5f * (low + high);
- v->uv[0] = orig_uv[0] + mid * dir[0];
- v->uv[1] = orig_uv[1] + mid * dir[1];
- stretch = p_stretch_compute_vertex(v);
-
- if (stretch_low < stretch_high) {
- high = mid;
- stretch_high = stretch;
- }
- else {
- low = mid;
- stretch_low = stretch;
- }
- }
-
- /* no luck, stretch has increased, reset to old values */
- if (stretch >= orig_stretch)
- copy_v2_v2(v->uv, orig_uv);
- }
+ PVert *v;
+ PEdge *e;
+ int j, nedges;
+ float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch;
+ float orig_uv[2], dir[2], random_angle, trusted_radius;
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT))
+ continue;
+
+ orig_stretch = p_stretch_compute_vertex(v);
+ orig_uv[0] = v->uv[0];
+ orig_uv[1] = v->uv[1];
+
+ /* move vertex in a random direction */
+ trusted_radius = 0.0f;
+ nedges = 0;
+ e = v->edge;
+
+ do {
+ trusted_radius += p_edge_uv_length(e);
+ nedges++;
+
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
+
+ trusted_radius /= 2 * nedges;
+
+ random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI;
+ dir[0] = trusted_radius * cosf(random_angle);
+ dir[1] = trusted_radius * sinf(random_angle);
+
+ /* calculate old and new stretch */
+ low = 0;
+ stretch_low = orig_stretch;
+
+ add_v2_v2v2(v->uv, orig_uv, dir);
+ high = 1;
+ stretch = stretch_high = p_stretch_compute_vertex(v);
+
+ /* binary search for lowest stretch position */
+ for (j = 0; j < P_STRETCH_ITER; j++) {
+ mid = 0.5f * (low + high);
+ v->uv[0] = orig_uv[0] + mid * dir[0];
+ v->uv[1] = orig_uv[1] + mid * dir[1];
+ stretch = p_stretch_compute_vertex(v);
+
+ if (stretch_low < stretch_high) {
+ high = mid;
+ stretch_high = stretch;
+ }
+ else {
+ low = mid;
+ stretch_low = stretch;
+ }
+ }
+
+ /* no luck, stretch has increased, reset to old values */
+ if (stretch >= orig_stretch)
+ copy_v2_v2(v->uv, orig_uv);
+ }
}
/* Minimum area enclosing rectangle for packing */
static int p_compare_geometric_uv(const void *a, const void *b)
{
- const PVert *v1 = *(const PVert * const *)a;
- const PVert *v2 = *(const PVert * const *)b;
+ const PVert *v1 = *(const PVert *const *)a;
+ const PVert *v2 = *(const PVert *const *)b;
- if (v1->uv[0] < v2->uv[0])
- return -1;
- else if (v1->uv[0] == v2->uv[0]) {
- if (v1->uv[1] < v2->uv[1])
- return -1;
- else if (v1->uv[1] == v2->uv[1])
- return 0;
- else
- return 1;
- }
- else
- return 1;
+ if (v1->uv[0] < v2->uv[0])
+ return -1;
+ else if (v1->uv[0] == v2->uv[0]) {
+ if (v1->uv[1] < v2->uv[1])
+ return -1;
+ else if (v1->uv[1] == v2->uv[1])
+ return 0;
+ else
+ return 1;
+ }
+ else
+ return 1;
}
static PBool p_chart_convex_hull(PChart *chart, PVert ***verts, int *nverts, int *right)
{
- /* Graham algorithm, taken from:
- * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
+ /* Graham algorithm, taken from:
+ * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
- PEdge *be, *e;
- int npoints = 0, i, ulen, llen;
- PVert **U, **L, **points, **p;
+ PEdge *be, *e;
+ int npoints = 0, i, ulen, llen;
+ PVert **U, **L, **points, **p;
- p_chart_boundaries(chart, NULL, &be);
+ p_chart_boundaries(chart, NULL, &be);
- if (!be)
- return P_FALSE;
+ if (!be)
+ return P_FALSE;
- e = be;
- do {
- npoints++;
- e = p_boundary_edge_next(e);
- } while (e != be);
+ e = be;
+ do {
+ npoints++;
+ e = p_boundary_edge_next(e);
+ } while (e != be);
- p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints");
- U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU");
- L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL");
+ p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints");
+ U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU");
+ L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL");
- e = be;
- do {
- *p = e->vert;
- p++;
- e = p_boundary_edge_next(e);
- } while (e != be);
+ e = be;
+ do {
+ *p = e->vert;
+ p++;
+ e = p_boundary_edge_next(e);
+ } while (e != be);
- qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv);
+ qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv);
- ulen = llen = 0;
- for (p = points, i = 0; i < npoints; i++, p++) {
- while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0))
- ulen--;
- while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0))
- llen--;
+ ulen = llen = 0;
+ for (p = points, i = 0; i < npoints; i++, p++) {
+ while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0))
+ ulen--;
+ while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0))
+ llen--;
- U[ulen] = *p;
- ulen++;
- L[llen] = *p;
- llen++;
- }
+ U[ulen] = *p;
+ ulen++;
+ L[llen] = *p;
+ llen++;
+ }
- npoints = 0;
- for (p = points, i = 0; i < ulen; i++, p++, npoints++)
- *p = U[i];
+ npoints = 0;
+ for (p = points, i = 0; i < ulen; i++, p++, npoints++)
+ *p = U[i];
- /* the first and last point in L are left out, since they are also in U */
- for (i = llen - 2; i > 0; i--, p++, npoints++)
- *p = L[i];
+ /* the first and last point in L are left out, since they are also in U */
+ for (i = llen - 2; i > 0; i--, p++, npoints++)
+ *p = L[i];
- *verts = points;
- *nverts = npoints;
- *right = ulen - 1;
+ *verts = points;
+ *nverts = npoints;
+ *right = ulen - 1;
- MEM_freeN(U);
- MEM_freeN(L);
+ MEM_freeN(U);
+ MEM_freeN(L);
- return P_TRUE;
+ return P_TRUE;
}
static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
{
- /* given 4 points on the rectangle edges and the direction of on edge,
- * compute the area of the rectangle */
+ /* given 4 points on the rectangle edges and the direction of on edge,
+ * compute the area of the rectangle */
- float orthodir[2], corner1[2], corner2[2], corner3[2];
+ float orthodir[2], corner1[2], corner2[2], corner3[2];
- orthodir[0] = dir[1];
- orthodir[1] = -dir[0];
+ orthodir[0] = dir[1];
+ orthodir[1] = -dir[0];
- if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1))
- return 1e10;
+ if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1))
+ return 1e10;
- if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2))
- return 1e10;
+ if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2))
+ return 1e10;
- if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3))
- return 1e10;
+ if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3))
+ return 1e10;
- return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3);
+ return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3);
}
static float p_chart_minimum_area_angle(PChart *chart)
{
- /* minimum area enclosing rectangle with rotating calipers, info:
- * http://cgm.cs.mcgill.ca/~orm/maer.html */
-
- float rotated, minarea, minangle, area, len;
- float *angles, miny, maxy, v[2], a[4], mina;
- int npoints, right, i_min, i_max, i, idx[4], nextidx;
- PVert **points, *p1, *p2, *p3, *p4, *p1n;
-
- /* compute convex hull */
- if (!p_chart_convex_hull(chart, &points, &npoints, &right))
- return 0.0;
-
- /* find left/top/right/bottom points, and compute angle for each point */
- angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles");
-
- i_min = i_max = 0;
- miny = 1e10;
- maxy = -1e10;
+ /* minimum area enclosing rectangle with rotating calipers, info:
+ * http://cgm.cs.mcgill.ca/~orm/maer.html */
+
+ float rotated, minarea, minangle, area, len;
+ float *angles, miny, maxy, v[2], a[4], mina;
+ int npoints, right, i_min, i_max, i, idx[4], nextidx;
+ PVert **points, *p1, *p2, *p3, *p4, *p1n;
+
+ /* compute convex hull */
+ if (!p_chart_convex_hull(chart, &points, &npoints, &right))
+ return 0.0;
+
+ /* find left/top/right/bottom points, and compute angle for each point */
+ angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles");
+
+ i_min = i_max = 0;
+ miny = 1e10;
+ maxy = -1e10;
- for (i = 0; i < npoints; i++) {
- p1 = (i == 0) ? points[npoints - 1] : points[i - 1];
- p2 = points[i];
- p3 = (i == npoints - 1) ? points[0] : points[i + 1];
+ for (i = 0; i < npoints; i++) {
+ p1 = (i == 0) ? points[npoints - 1] : points[i - 1];
+ p2 = points[i];
+ p3 = (i == npoints - 1) ? points[0] : points[i + 1];
- angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv);
+ angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv);
- if (points[i]->uv[1] < miny) {
- miny = points[i]->uv[1];
- i_min = i;
- }
- if (points[i]->uv[1] > maxy) {
- maxy = points[i]->uv[1];
- i_max = i;
- }
- }
+ if (points[i]->uv[1] < miny) {
+ miny = points[i]->uv[1];
+ i_min = i;
+ }
+ if (points[i]->uv[1] > maxy) {
+ maxy = points[i]->uv[1];
+ i_max = i;
+ }
+ }
- /* left, top, right, bottom */
- idx[0] = 0;
- idx[1] = i_max;
- idx[2] = right;
- idx[3] = i_min;
+ /* left, top, right, bottom */
+ idx[0] = 0;
+ idx[1] = i_max;
+ idx[2] = right;
+ idx[3] = i_min;
- v[0] = points[idx[0]]->uv[0];
- v[1] = points[idx[0]]->uv[1] + 1.0f;
- a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
+ v[0] = points[idx[0]]->uv[0];
+ v[1] = points[idx[0]]->uv[1] + 1.0f;
+ a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v);
- v[0] = points[idx[1]]->uv[0] + 1.0f;
- v[1] = points[idx[1]]->uv[1];
- a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
+ v[0] = points[idx[1]]->uv[0] + 1.0f;
+ v[1] = points[idx[1]]->uv[1];
+ a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v);
- v[0] = points[idx[2]]->uv[0];
- v[1] = points[idx[2]]->uv[1] - 1.0f;
- a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
+ v[0] = points[idx[2]]->uv[0];
+ v[1] = points[idx[2]]->uv[1] - 1.0f;
+ a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v);
- v[0] = points[idx[3]]->uv[0] - 1.0f;
- v[1] = points[idx[3]]->uv[1];
- a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
+ v[0] = points[idx[3]]->uv[0] - 1.0f;
+ v[1] = points[idx[3]]->uv[1];
+ a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v);
- /* 4 rotating calipers */
+ /* 4 rotating calipers */
- rotated = 0.0;
- minarea = 1e10;
- minangle = 0.0;
+ rotated = 0.0;
+ minarea = 1e10;
+ minangle = 0.0;
- while (rotated <= (float)(M_PI / 2.0)) { /* INVESTIGATE: how far to rotate? */
- /* rotate with the smallest angle */
- i_min = 0;
- mina = 1e10;
+ while (rotated <= (float)(M_PI / 2.0)) { /* INVESTIGATE: how far to rotate? */
+ /* rotate with the smallest angle */
+ i_min = 0;
+ mina = 1e10;
- for (i = 0; i < 4; i++)
- if (a[i] < mina) {
- mina = a[i];
- i_min = i;
- }
+ for (i = 0; i < 4; i++)
+ if (a[i] < mina) {
+ mina = a[i];
+ i_min = i;
+ }
- rotated += mina;
- nextidx = (idx[i_min] + 1) % npoints;
+ rotated += mina;
+ nextidx = (idx[i_min] + 1) % npoints;
- a[i_min] = angles[nextidx];
- a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina;
- a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina;
- a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina;
+ a[i_min] = angles[nextidx];
+ a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina;
+ a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina;
+ a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina;
- /* compute area */
- p1 = points[idx[i_min]];
- p1n = points[nextidx];
- p2 = points[idx[(i_min + 1) % 4]];
- p3 = points[idx[(i_min + 2) % 4]];
- p4 = points[idx[(i_min + 3) % 4]];
+ /* compute area */
+ p1 = points[idx[i_min]];
+ p1n = points[nextidx];
+ p2 = points[idx[(i_min + 1) % 4]];
+ p3 = points[idx[(i_min + 2) % 4]];
+ p4 = points[idx[(i_min + 3) % 4]];
- len = len_v2v2(p1->uv, p1n->uv);
+ len = len_v2v2(p1->uv, p1n->uv);
- if (len > 0.0f) {
- len = 1.0f / len;
- v[0] = (p1n->uv[0] - p1->uv[0]) * len;
- v[1] = (p1n->uv[1] - p1->uv[1]) * len;
+ if (len > 0.0f) {
+ len = 1.0f / len;
+ v[0] = (p1n->uv[0] - p1->uv[0]) * len;
+ v[1] = (p1n->uv[1] - p1->uv[1]) * len;
- area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv);
+ area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv);
- /* remember smallest area */
- if (area < minarea) {
- minarea = area;
- minangle = rotated;
- }
- }
+ /* remember smallest area */
+ if (area < minarea) {
+ minarea = area;
+ minangle = rotated;
+ }
+ }
- idx[i_min] = nextidx;
- }
+ idx[i_min] = nextidx;
+ }
- /* try keeping rotation as small as possible */
- if (minangle > (float)(M_PI / 4))
- minangle -= (float)(M_PI / 2.0);
+ /* try keeping rotation as small as possible */
+ if (minangle > (float)(M_PI / 4))
+ minangle -= (float)(M_PI / 2.0);
- MEM_freeN(angles);
- MEM_freeN(points);
-
- return minangle;
+ MEM_freeN(angles);
+ MEM_freeN(points);
+
+ return minangle;
}
static void p_chart_rotate_minimum_area(PChart *chart)
{
- float angle = p_chart_minimum_area_angle(chart);
- float sine = sinf(angle);
- float cosine = cosf(angle);
- PVert *v;
+ float angle = p_chart_minimum_area_angle(chart);
+ float sine = sinf(angle);
+ float cosine = cosf(angle);
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink) {
- float oldu = v->uv[0], oldv = v->uv[1];
- v->uv[0] = cosine * oldu - sine * oldv;
- v->uv[1] = sine * oldu + cosine * oldv;
- }
+ for (v = chart->verts; v; v = v->nextlink) {
+ float oldu = v->uv[0], oldv = v->uv[1];
+ v->uv[0] = cosine * oldu - sine * oldv;
+ v->uv[1] = sine * oldu + cosine * oldv;
+ }
}
/* Area Smoothing */
@@ -3614,1083 +3642,1110 @@ static void p_chart_rotate_minimum_area(PChart *chart)
/* 2d bsp tree for inverse mapping - that's a bit silly */
typedef struct SmoothTriangle {
- float co1[2], co2[2], co3[2];
- float oco1[2], oco2[2], oco3[2];
+ float co1[2], co2[2], co3[2];
+ float oco1[2], oco2[2], oco3[2];
} SmoothTriangle;
typedef struct SmoothNode {
- struct SmoothNode *c1, *c2;
- SmoothTriangle **tri;
- float split;
- int axis, ntri;
+ struct SmoothNode *c1, *c2;
+ SmoothTriangle **tri;
+ float split;
+ int axis, ntri;
} SmoothNode;
-static void p_barycentric_2d(const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
+static void p_barycentric_2d(
+ const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
{
- float a[2], c[2], h[2], div;
+ float a[2], c[2], h[2], div;
- a[0] = v2[0] - v1[0];
- a[1] = v2[1] - v1[1];
- c[0] = v3[0] - v1[0];
- c[1] = v3[1] - v1[1];
+ a[0] = v2[0] - v1[0];
+ a[1] = v2[1] - v1[1];
+ c[0] = v3[0] - v1[0];
+ c[1] = v3[1] - v1[1];
- div = a[0] * c[1] - a[1] * c[0];
+ div = a[0] * c[1] - a[1] * c[0];
- if (div == 0.0f) {
- b[0] = 1.0f / 3.0f;
- b[1] = 1.0f / 3.0f;
- b[2] = 1.0f / 3.0f;
- }
- else {
- h[0] = p[0] - v1[0];
- h[1] = p[1] - v1[1];
+ if (div == 0.0f) {
+ b[0] = 1.0f / 3.0f;
+ b[1] = 1.0f / 3.0f;
+ b[2] = 1.0f / 3.0f;
+ }
+ else {
+ h[0] = p[0] - v1[0];
+ h[1] = p[1] - v1[1];
- div = 1.0f / div;
+ div = 1.0f / div;
- b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
- b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
- b[0] = 1.0f - b[1] - b[2];
- }
+ b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
+ b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
+ b[0] = 1.0f - b[1] - b[2];
+ }
}
static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
{
- float b[3];
+ float b[3];
- p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
+ p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
- if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
- co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
- co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
- return P_TRUE;
- }
+ if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
+ co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
+ co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
+ return P_TRUE;
+ }
- return P_FALSE;
+ return P_FALSE;
}
-static SmoothNode *p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
+static SmoothNode *p_node_new(
+ MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
{
- SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
- int axis, i, t1size = 0, t2size = 0;
- float split, /* mi, */ /* UNUSED */ mx;
- SmoothTriangle **t1, **t2, *t;
+ SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
+ int axis, i, t1size = 0, t2size = 0;
+ float split, /* mi, */ /* UNUSED */ mx;
+ SmoothTriangle **t1, **t2, *t;
- node->tri = tri;
- node->ntri = ntri;
+ node->tri = tri;
+ node->ntri = ntri;
- if (ntri <= 10 || depth >= 15)
- return node;
+ if (ntri <= 10 || depth >= 15)
+ return node;
- t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
- t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
+ t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
+ t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
- axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
- split = 0.5f * (bmin[axis] + bmax[axis]);
+ axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
+ split = 0.5f * (bmin[axis] + bmax[axis]);
- for (i = 0; i < ntri; i++) {
- t = tri[i];
+ for (i = 0; i < ntri; i++) {
+ t = tri[i];
- if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
- t1[t1size] = t;
- t1size++;
- }
- if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
- t2[t2size] = t;
- t2size++;
- }
- }
+ if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
+ t1[t1size] = t;
+ t1size++;
+ }
+ if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
+ t2[t2size] = t;
+ t2size++;
+ }
+ }
- if ((t1size == t2size) && (t1size == ntri)) {
- MEM_freeN(t1);
- MEM_freeN(t2);
- return node;
- }
+ if ((t1size == t2size) && (t1size == ntri)) {
+ MEM_freeN(t1);
+ MEM_freeN(t2);
+ return node;
+ }
- node->tri = NULL;
- node->ntri = 0;
- MEM_freeN(tri);
+ node->tri = NULL;
+ node->ntri = 0;
+ MEM_freeN(tri);
- node->axis = axis;
- node->split = split;
+ node->axis = axis;
+ node->split = split;
- /* mi = bmin[axis]; */ /* UNUSED */
- mx = bmax[axis];
- bmax[axis] = split;
- node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
+ /* mi = bmin[axis]; */ /* UNUSED */
+ mx = bmax[axis];
+ bmax[axis] = split;
+ node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
- bmin[axis] = bmax[axis];
- bmax[axis] = mx;
- node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
+ bmin[axis] = bmax[axis];
+ bmax[axis] = mx;
+ node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
- return node;
+ return node;
}
static void p_node_delete(SmoothNode *node)
{
- if (node->c1)
- p_node_delete(node->c1);
- if (node->c2)
- p_node_delete(node->c2);
- if (node->tri)
- MEM_freeN(node->tri);
+ if (node->c1)
+ p_node_delete(node->c1);
+ if (node->c2)
+ p_node_delete(node->c2);
+ if (node->tri)
+ MEM_freeN(node->tri);
}
static PBool p_node_intersect(SmoothNode *node, float co[2])
{
- int i;
-
- if (node->tri) {
- for (i = 0; i < node->ntri; i++)
- if (p_triangle_inside(node->tri[i], co))
- return P_TRUE;
+ int i;
- return P_FALSE;
- }
- else {
- if (co[node->axis] < node->split)
- return p_node_intersect(node->c1, co);
- else
- return p_node_intersect(node->c2, co);
- }
+ if (node->tri) {
+ for (i = 0; i < node->ntri; i++)
+ if (p_triangle_inside(node->tri[i], co))
+ return P_TRUE;
+ return P_FALSE;
+ }
+ else {
+ if (co[node->axis] < node->split)
+ return p_node_intersect(node->c1, co);
+ else
+ return p_node_intersect(node->c2, co);
+ }
}
/* smoothing */
static int p_compare_float(const void *a_, const void *b_)
{
- const float a = *(const float *)a_;
- const float b = *(const float *)b_;
+ const float a = *(const float *)a_;
+ const float b = *(const float *)b_;
- if (a < b)
- return -1;
- else if (a == b)
- return 0;
- else
- return 1;
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
}
static float p_smooth_median_edge_length(PChart *chart)
{
- PEdge *e;
- float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
- float median;
- int i;
+ PEdge *e;
+ float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
+ float median;
+ int i;
- /* ok, so i'm lazy */
- for (i = 0, e = chart->edges; e; e = e->nextlink, i++)
- lengths[i] = p_edge_length(e);
+ /* ok, so i'm lazy */
+ for (i = 0, e = chart->edges; e; e = e->nextlink, i++)
+ lengths[i] = p_edge_length(e);
- qsort(lengths, i, sizeof(float), p_compare_float);
+ qsort(lengths, i, sizeof(float), p_compare_float);
- median = lengths[i / 2];
- MEM_freeN(lengths);
+ median = lengths[i / 2];
+ MEM_freeN(lengths);
- return median;
+ return median;
}
static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
{
- float len2d = p_edge_uv_length(e) * avg3d;
- float len3d = p_edge_length(e) * avg2d;
+ float len2d = p_edge_uv_length(e) * avg3d;
+ float len3d = p_edge_length(e) * avg2d;
- return (len3d == 0.0f) ? 0.0f : len2d / len3d;
+ return (len3d == 0.0f) ? 0.0f : len2d / len3d;
}
static void p_smooth(PChart *chart)
{
- PEdge *e;
- PVert *v;
- PFace *f;
- int j, it2, maxiter2, it;
- int nedges = chart->nedges, nwheel, gridx, gridy;
- int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter;
- float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
- float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
- float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
- SmoothTriangle *triangles, *t, *t2, **tri, **trip;
- SmoothNode *root;
- MemArena *arena;
-
- if (nedges == 0)
- return;
-
- p_chart_uv_bbox(chart, minv, maxv);
- median = p_smooth_median_edge_length(chart) * 0.10f;
-
- if (median == 0.0f)
- return;
-
- invmedian = 1.0f / median;
-
- /* compute edge distortion */
- avglen2d = avglen3d = 0.0;
-
- for (e = chart->edges; e; e = e->nextlink) {
- avglen2d += p_edge_uv_length(e);
- avglen3d += p_edge_length(e);
- }
-
- avglen2d /= nedges;
- avglen3d /= nedges;
-
- for (v = chart->verts; v; v = v->nextlink) {
- v->u.distortion = 0.0;
- nwheel = 0;
-
- e = v->edge;
- do {
- v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
- nwheel++;
-
- e = e->next->next->pair;
- } while (e && (e != v->edge));
-
- v->u.distortion /= nwheel;
- }
-
- /* need to do excessive grid size checking still */
- center[0] = 0.5f * (minv[0] + maxv[0]);
- center[1] = 0.5f * (minv[1] + maxv[1]);
-
- dx = 0.5f * (maxv[0] - minv[0]);
- dy = 0.5f * (maxv[1] - minv[1]);
-
- padding = 0.15f;
- dx += padding * dx + 2.0f * median;
- dy += padding * dy + 2.0f * median;
-
- gridx = (int)(dx * invmedian);
- gridy = (int)(dy * invmedian);
-
- minv[0] = center[0] - median * gridx;
- minv[1] = center[1] - median * gridy;
- maxv[0] = center[0] + median * gridx;
- maxv[1] = center[1] + median * gridy;
-
- /* create grid */
- gridx = gridx * 2 + 1;
- gridy = gridy * 2 + 1;
-
- if ((gridx <= 2) || (gridy <= 2))
- return;
-
- edgesx = gridx - 1;
- edgesy = gridy - 1;
- nsize = gridx * gridy;
- esize = edgesx * edgesy;
-
- nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
- nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
- nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
- oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
- oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
- hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
- vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
-
- if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
- if (nodes) MEM_freeN(nodes);
- if (nodesx) MEM_freeN(nodesx);
- if (nodesy) MEM_freeN(nodesy);
- if (oldnodesx) MEM_freeN(oldnodesx);
- if (oldnodesy) MEM_freeN(oldnodesy);
- if (hedges) MEM_freeN(hedges);
- if (vedges) MEM_freeN(vedges);
-
- // printf("Not enough memory for area smoothing grid");
- return;
- }
-
- for (x = 0; x < gridx; x++) {
- for (y = 0; y < gridy; y++) {
- i = x + y * gridx;
-
- nodesx[i] = minv[0] + median * x;
- nodesy[i] = minv[1] + median * y;
-
- nodes[i] = 1.0f;
- }
- }
-
- /* embed in grid */
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- float fmin[2], fmax[2];
- int bx1, by1, bx2, by2;
-
- INIT_MINMAX2(fmin, fmax);
+ PEdge *e;
+ PVert *v;
+ PFace *f;
+ int j, it2, maxiter2, it;
+ int nedges = chart->nedges, nwheel, gridx, gridy;
+ int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter;
+ float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
+ float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
+ float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
+ SmoothTriangle *triangles, *t, *t2, **tri, **trip;
+ SmoothNode *root;
+ MemArena *arena;
+
+ if (nedges == 0)
+ return;
+
+ p_chart_uv_bbox(chart, minv, maxv);
+ median = p_smooth_median_edge_length(chart) * 0.10f;
+
+ if (median == 0.0f)
+ return;
+
+ invmedian = 1.0f / median;
+
+ /* compute edge distortion */
+ avglen2d = avglen3d = 0.0;
+
+ for (e = chart->edges; e; e = e->nextlink) {
+ avglen2d += p_edge_uv_length(e);
+ avglen3d += p_edge_length(e);
+ }
+
+ avglen2d /= nedges;
+ avglen3d /= nedges;
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ v->u.distortion = 0.0;
+ nwheel = 0;
+
+ e = v->edge;
+ do {
+ v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
+ nwheel++;
+
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+
+ v->u.distortion /= nwheel;
+ }
+
+ /* need to do excessive grid size checking still */
+ center[0] = 0.5f * (minv[0] + maxv[0]);
+ center[1] = 0.5f * (minv[1] + maxv[1]);
+
+ dx = 0.5f * (maxv[0] - minv[0]);
+ dy = 0.5f * (maxv[1] - minv[1]);
+
+ padding = 0.15f;
+ dx += padding * dx + 2.0f * median;
+ dy += padding * dy + 2.0f * median;
+
+ gridx = (int)(dx * invmedian);
+ gridy = (int)(dy * invmedian);
+
+ minv[0] = center[0] - median * gridx;
+ minv[1] = center[1] - median * gridy;
+ maxv[0] = center[0] + median * gridx;
+ maxv[1] = center[1] + median * gridy;
+
+ /* create grid */
+ gridx = gridx * 2 + 1;
+ gridy = gridy * 2 + 1;
+
+ if ((gridx <= 2) || (gridy <= 2))
+ return;
+
+ edgesx = gridx - 1;
+ edgesy = gridy - 1;
+ nsize = gridx * gridy;
+ esize = edgesx * edgesy;
+
+ nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
+ nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
+ nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
+ oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
+ oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
+ hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
+ vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
+
+ if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
+ if (nodes)
+ MEM_freeN(nodes);
+ if (nodesx)
+ MEM_freeN(nodesx);
+ if (nodesy)
+ MEM_freeN(nodesy);
+ if (oldnodesx)
+ MEM_freeN(oldnodesx);
+ if (oldnodesy)
+ MEM_freeN(oldnodesy);
+ if (hedges)
+ MEM_freeN(hedges);
+ if (vedges)
+ MEM_freeN(vedges);
+
+ // printf("Not enough memory for area smoothing grid");
+ return;
+ }
+
+ for (x = 0; x < gridx; x++) {
+ for (y = 0; y < gridy; y++) {
+ i = x + y * gridx;
+
+ nodesx[i] = minv[0] + median * x;
+ nodesy[i] = minv[1] + median * y;
+
+ nodes[i] = 1.0f;
+ }
+ }
+
+ /* embed in grid */
+ for (f = chart->faces; f; f = f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ float fmin[2], fmax[2];
+ int bx1, by1, bx2, by2;
+
+ INIT_MINMAX2(fmin, fmax);
+
+ minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
+ minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
+ minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
+
+ bx1 = (int)((fmin[0] - minv[0]) * invmedian);
+ by1 = (int)((fmin[1] - minv[1]) * invmedian);
+ bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
+ by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
+
+ for (x = bx1; x < bx2; x++) {
+ for (y = by1; y < by2; y++) {
+ float p[2], b[3];
+
+ i = x + y * gridx;
+
+ p[0] = nodesx[i];
+ p[1] = nodesy[i];
+
+ p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
+
+ if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
+ nodes[i] = e1->vert->u.distortion * b[0];
+ nodes[i] += e2->vert->u.distortion * b[1];
+ nodes[i] += e3->vert->u.distortion * b[2];
+ }
+ }
+ }
+ }
+
+ /* smooth the grid */
+ maxiter = 10;
+ totiter = 0;
+ climit = 0.00001f * nsize;
+
+ for (it = 0; it < maxiter; it++) {
+ moved = 0.0f;
+
+ for (x = 0; x < edgesx; x++) {
+ for (y = 0; y < edgesy; y++) {
+ i = x + y * gridx;
+ j = x + y * edgesx;
+
+ hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
+ vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
+
+ /* we do *inverse* mapping */
+ hedges[j] = 1.0f / hedges[j];
+ vedges[j] = 1.0f / vedges[j];
+ }
+ }
+
+ maxiter2 = 50;
+ dlimit = 0.0001f;
+
+ for (it2 = 0; it2 < maxiter2; it2++) {
+ d = 0.0f;
+ totiter += 1;
+
+ memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
+ memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
- minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
-
- bx1 = (int)((fmin[0] - minv[0]) * invmedian);
- by1 = (int)((fmin[1] - minv[1]) * invmedian);
- bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
- by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
-
- for (x = bx1; x < bx2; x++) {
- for (y = by1; y < by2; y++) {
- float p[2], b[3];
-
- i = x + y * gridx;
-
- p[0] = nodesx[i];
- p[1] = nodesy[i];
-
- p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
-
- if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
- nodes[i] = e1->vert->u.distortion * b[0];
- nodes[i] += e2->vert->u.distortion * b[1];
- nodes[i] += e3->vert->u.distortion * b[2];
- }
- }
- }
- }
-
- /* smooth the grid */
- maxiter = 10;
- totiter = 0;
- climit = 0.00001f * nsize;
-
- for (it = 0; it < maxiter; it++) {
- moved = 0.0f;
-
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
- j = x + y * edgesx;
-
- hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
- vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
-
- /* we do *inverse* mapping */
- hedges[j] = 1.0f / hedges[j];
- vedges[j] = 1.0f / vedges[j];
- }
- }
+ for (x = 1; x < gridx - 1; x++) {
+ for (y = 1; y < gridy - 1; y++) {
+ float p[2], oldp[2], sum1, sum2, diff[2], length;
- maxiter2 = 50;
- dlimit = 0.0001f;
+ i = x + gridx * y;
+ j = x + edgesx * y;
- for (it2 = 0; it2 < maxiter2; it2++) {
- d = 0.0f;
- totiter += 1;
+ oldp[0] = oldnodesx[i];
+ oldp[1] = oldnodesy[i];
- memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
- memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
+ sum1 = hedges[j - 1] * oldnodesx[i - 1];
+ sum1 += hedges[j] * oldnodesx[i + 1];
+ sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
+ sum1 += vedges[j] * oldnodesx[i + gridx];
- for (x = 1; x < gridx - 1; x++) {
- for (y = 1; y < gridy - 1; y++) {
- float p[2], oldp[2], sum1, sum2, diff[2], length;
+ sum2 = hedges[j - 1];
+ sum2 += hedges[j];
+ sum2 += vedges[j - edgesx];
+ sum2 += vedges[j];
- i = x + gridx * y;
- j = x + edgesx * y;
+ nodesx[i] = sum1 / sum2;
- oldp[0] = oldnodesx[i];
- oldp[1] = oldnodesy[i];
+ sum1 = hedges[j - 1] * oldnodesy[i - 1];
+ sum1 += hedges[j] * oldnodesy[i + 1];
+ sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
+ sum1 += vedges[j] * oldnodesy[i + gridx];
- sum1 = hedges[j - 1] * oldnodesx[i - 1];
- sum1 += hedges[j] * oldnodesx[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
- sum1 += vedges[j] * oldnodesx[i + gridx];
+ nodesy[i] = sum1 / sum2;
- sum2 = hedges[j - 1];
- sum2 += hedges[j];
- sum2 += vedges[j - edgesx];
- sum2 += vedges[j];
+ p[0] = nodesx[i];
+ p[1] = nodesy[i];
- nodesx[i] = sum1 / sum2;
+ diff[0] = p[0] - oldp[0];
+ diff[1] = p[1] - oldp[1];
- sum1 = hedges[j - 1] * oldnodesy[i - 1];
- sum1 += hedges[j] * oldnodesy[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
- sum1 += vedges[j] * oldnodesy[i + gridx];
+ length = len_v2(diff);
+ d = max_ff(d, length);
+ moved += length;
+ }
+ }
- nodesy[i] = sum1 / sum2;
+ if (d < dlimit)
+ break;
+ }
- p[0] = nodesx[i];
- p[1] = nodesy[i];
+ if (moved < climit)
+ break;
+ }
- diff[0] = p[0] - oldp[0];
- diff[1] = p[1] - oldp[1];
+ MEM_freeN(oldnodesx);
+ MEM_freeN(oldnodesy);
+ MEM_freeN(hedges);
+ MEM_freeN(vedges);
- length = len_v2(diff);
- d = max_ff(d, length);
- moved += length;
- }
- }
+ /* create bsp */
+ t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
+ trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
- if (d < dlimit)
- break;
- }
+ if (!triangles || !tri) {
+ MEM_freeN(nodes);
+ MEM_freeN(nodesx);
+ MEM_freeN(nodesy);
- if (moved < climit)
- break;
- }
+ if (triangles)
+ MEM_freeN(triangles);
+ if (tri)
+ MEM_freeN(tri);
- MEM_freeN(oldnodesx);
- MEM_freeN(oldnodesy);
- MEM_freeN(hedges);
- MEM_freeN(vedges);
+ // printf("Not enough memory for area smoothing grid");
+ return;
+ }
- /* create bsp */
- t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
- trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
+ for (x = 0; x < edgesx; x++) {
+ for (y = 0; y < edgesy; y++) {
+ i = x + y * gridx;
- if (!triangles || !tri) {
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
+ t->co1[0] = nodesx[i];
+ t->co1[1] = nodesy[i];
- if (triangles) MEM_freeN(triangles);
- if (tri) MEM_freeN(tri);
+ t->co2[0] = nodesx[i + 1];
+ t->co2[1] = nodesy[i + 1];
- // printf("Not enough memory for area smoothing grid");
- return;
- }
+ t->co3[0] = nodesx[i + gridx];
+ t->co3[1] = nodesy[i + gridx];
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
+ t->oco1[0] = minv[0] + x * median;
+ t->oco1[1] = minv[1] + y * median;
- t->co1[0] = nodesx[i];
- t->co1[1] = nodesy[i];
+ t->oco2[0] = minv[0] + (x + 1) * median;
+ t->oco2[1] = minv[1] + y * median;
- t->co2[0] = nodesx[i + 1];
- t->co2[1] = nodesy[i + 1];
+ t->oco3[0] = minv[0] + x * median;
+ t->oco3[1] = minv[1] + (y + 1) * median;
- t->co3[0] = nodesx[i + gridx];
- t->co3[1] = nodesy[i + gridx];
+ t2 = t + 1;
- t->oco1[0] = minv[0] + x * median;
- t->oco1[1] = minv[1] + y * median;
+ t2->co1[0] = nodesx[i + gridx + 1];
+ t2->co1[1] = nodesy[i + gridx + 1];
- t->oco2[0] = minv[0] + (x + 1) * median;
- t->oco2[1] = minv[1] + y * median;
+ t2->oco1[0] = minv[0] + (x + 1) * median;
+ t2->oco1[1] = minv[1] + (y + 1) * median;
- t->oco3[0] = minv[0] + x * median;
- t->oco3[1] = minv[1] + (y + 1) * median;
+ t2->co2[0] = t->co2[0];
+ t2->co2[1] = t->co2[1];
+ t2->oco2[0] = t->oco2[0];
+ t2->oco2[1] = t->oco2[1];
- t2 = t + 1;
+ t2->co3[0] = t->co3[0];
+ t2->co3[1] = t->co3[1];
+ t2->oco3[0] = t->oco3[0];
+ t2->oco3[1] = t->oco3[1];
- t2->co1[0] = nodesx[i + gridx + 1];
- t2->co1[1] = nodesy[i + gridx + 1];
+ *trip = t;
+ trip++;
+ t++;
+ *trip = t;
+ trip++;
+ t++;
+ }
+ }
- t2->oco1[0] = minv[0] + (x + 1) * median;
- t2->oco1[1] = minv[1] + (y + 1) * median;
+ MEM_freeN(nodes);
+ MEM_freeN(nodesx);
+ MEM_freeN(nodesy);
- t2->co2[0] = t->co2[0]; t2->co2[1] = t->co2[1];
- t2->oco2[0] = t->oco2[0]; t2->oco2[1] = t->oco2[1];
+ arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
+ root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
- t2->co3[0] = t->co3[0]; t2->co3[1] = t->co3[1];
- t2->oco3[0] = t->oco3[0]; t2->oco3[1] = t->oco3[1];
+ for (v = chart->verts; v; v = v->nextlink)
+ if (!p_node_intersect(root, v->uv))
+ param_warning("area smoothing error: couldn't find mapping triangle\n");
- *trip = t; trip++; t++;
- *trip = t; trip++; t++;
- }
- }
+ p_node_delete(root);
+ BLI_memarena_free(arena);
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
-
- arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
- root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
-
- for (v = chart->verts; v; v = v->nextlink)
- if (!p_node_intersect(root, v->uv))
- param_warning("area smoothing error: couldn't find mapping triangle\n");
-
- p_node_delete(root);
- BLI_memarena_free(arena);
-
- MEM_freeN(triangles);
+ MEM_freeN(triangles);
}
/* Exported */
ParamHandle *param_construct_begin(void)
{
- PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle");
- handle->construction_chart = p_chart_new(handle);
- handle->state = PHANDLE_STATE_ALLOCATED;
- handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena");
- handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena");
- handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
- handle->aspx = 1.0f;
- handle->aspy = 1.0f;
- handle->do_aspect = false;
+ PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle");
+ handle->construction_chart = p_chart_new(handle);
+ handle->state = PHANDLE_STATE_ALLOCATED;
+ handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena");
+ handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena");
+ handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ handle->aspx = 1.0f;
+ handle->aspy = 1.0f;
+ handle->do_aspect = false;
- handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1);
- handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
- handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1);
+ handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1);
+ handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
+ handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1);
- return (ParamHandle *)handle;
+ return (ParamHandle *)handle;
}
void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
{
- PHandle *phandle = (PHandle *)handle;
+ PHandle *phandle = (PHandle *)handle;
- phandle->aspx = aspx;
- phandle->aspy = aspy;
- phandle->do_aspect = true;
+ phandle->aspx = aspx;
+ phandle->aspy = aspy;
+ phandle->do_aspect = true;
}
void param_delete(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- int i;
-
- param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) ||
- (phandle->state == PHANDLE_STATE_CONSTRUCTED));
-
- for (i = 0; i < phandle->ncharts; i++)
- p_chart_delete(phandle->charts[i]);
-
- if (phandle->charts)
- MEM_freeN(phandle->charts);
-
- if (phandle->construction_chart) {
- p_chart_delete(phandle->construction_chart);
-
- phash_delete(phandle->hash_verts);
- phash_delete(phandle->hash_edges);
- phash_delete(phandle->hash_faces);
- }
-
- BLI_memarena_free(phandle->arena);
- BLI_memarena_free(phandle->polyfill_arena);
- BLI_heap_free(phandle->polyfill_heap, NULL);
- MEM_freeN(phandle);
-}
-
-static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
- ParamKey *vkeys, float **co, float **uv,
- ParamBool *pin, ParamBool *select)
-{
- /* Allocate memory for polyfill. */
- PHandle *phandle = (PHandle *)handle;
- MemArena *arena = phandle->polyfill_arena;
- Heap *heap = phandle->polyfill_heap;
- unsigned int nfilltri = nverts - 2;
- unsigned int (*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
- float (*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
-
- /* Calc normal, flipped: to get a positive 2d cross product. */
- float normal[3];
- zero_v3(normal);
-
- const float *co_curr, *co_prev = co[nverts - 1];
- for (int j = 0; j < nverts; j++) {
- co_curr = co[j];
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* Project verts to 2d. */
- float axis_mat[3][3];
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
- for (int j = 0; j < nverts; j++) {
- mul_v2_m3v3(projverts[j], axis_mat, co[j]);
- }
-
- BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena);
-
- /* Beautify helps avoid thin triangles that give numerical problems. */
- BLI_polyfill_beautify(projverts, nverts, tris, arena, heap);
-
- /* Add triangles. */
- for (int j = 0; j < nfilltri; j++) {
- unsigned int *tri = tris[j];
- unsigned int v0 = tri[0];
- unsigned int v1 = tri[1];
- unsigned int v2 = tri[2];
-
- ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
- float *tri_co[3] = {co[v0], co[v1], co[v2]};
- float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
- ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
- ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
-
- param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
- }
-
- BLI_memarena_clear(arena);
-}
-
-void param_face_add(ParamHandle *handle, ParamKey key, int nverts,
- ParamKey *vkeys, float *co[4], float *uv[4],
- ParamBool *pin, ParamBool *select)
-{
- PHandle *phandle = (PHandle *)handle;
-
- param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
- param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- param_assert((nverts == 3) || (nverts == 4));
-
- if (nverts > 4) {
- /* ngon */
- p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select);
- }
- else if (nverts == 4) {
- /* quad */
- if (p_quad_split_direction(phandle, co, vkeys)) {
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select);
- }
- else {
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select);
- p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select);
- }
- }
- else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) {
- /* triangle */
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
- }
+ PHandle *phandle = (PHandle *)handle;
+ int i;
+
+ param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) ||
+ (phandle->state == PHANDLE_STATE_CONSTRUCTED));
+
+ for (i = 0; i < phandle->ncharts; i++)
+ p_chart_delete(phandle->charts[i]);
+
+ if (phandle->charts)
+ MEM_freeN(phandle->charts);
+
+ if (phandle->construction_chart) {
+ p_chart_delete(phandle->construction_chart);
+
+ phash_delete(phandle->hash_verts);
+ phash_delete(phandle->hash_edges);
+ phash_delete(phandle->hash_faces);
+ }
+
+ BLI_memarena_free(phandle->arena);
+ BLI_memarena_free(phandle->polyfill_arena);
+ BLI_heap_free(phandle->polyfill_heap, NULL);
+ MEM_freeN(phandle);
+}
+
+static void p_add_ngon(ParamHandle *handle,
+ ParamKey key,
+ int nverts,
+ ParamKey *vkeys,
+ float **co,
+ float **uv,
+ ParamBool *pin,
+ ParamBool *select)
+{
+ /* Allocate memory for polyfill. */
+ PHandle *phandle = (PHandle *)handle;
+ MemArena *arena = phandle->polyfill_arena;
+ Heap *heap = phandle->polyfill_heap;
+ unsigned int nfilltri = nverts - 2;
+ unsigned int(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
+ float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
+
+ /* Calc normal, flipped: to get a positive 2d cross product. */
+ float normal[3];
+ zero_v3(normal);
+
+ const float *co_curr, *co_prev = co[nverts - 1];
+ for (int j = 0; j < nverts; j++) {
+ co_curr = co[j];
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+
+ /* Project verts to 2d. */
+ float axis_mat[3][3];
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+ for (int j = 0; j < nverts; j++) {
+ mul_v2_m3v3(projverts[j], axis_mat, co[j]);
+ }
+
+ BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena);
+
+ /* Beautify helps avoid thin triangles that give numerical problems. */
+ BLI_polyfill_beautify(projverts, nverts, tris, arena, heap);
+
+ /* Add triangles. */
+ for (int j = 0; j < nfilltri; j++) {
+ unsigned int *tri = tris[j];
+ unsigned int v0 = tri[0];
+ unsigned int v1 = tri[1];
+ unsigned int v2 = tri[2];
+
+ ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
+ float *tri_co[3] = {co[v0], co[v1], co[v2]};
+ float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
+ ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
+ ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
+
+ param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
+ }
+
+ BLI_memarena_clear(arena);
+}
+
+void param_face_add(ParamHandle *handle,
+ ParamKey key,
+ int nverts,
+ ParamKey *vkeys,
+ float *co[4],
+ float *uv[4],
+ ParamBool *pin,
+ ParamBool *select)
+{
+ PHandle *phandle = (PHandle *)handle;
+
+ param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+ param_assert((nverts == 3) || (nverts == 4));
+
+ if (nverts > 4) {
+ /* ngon */
+ p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select);
+ }
+ else if (nverts == 4) {
+ /* quad */
+ if (p_quad_split_direction(phandle, co, vkeys)) {
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select);
+ }
+ else {
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select);
+ }
+ }
+ else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) {
+ /* triangle */
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
+ }
}
void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
{
- PHandle *phandle = (PHandle *)handle;
- PEdge *e;
+ PHandle *phandle = (PHandle *)handle;
+ PEdge *e;
- param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- e = p_edge_lookup(phandle, vkeys);
- if (e)
- e->flag |= PEDGE_SEAM;
+ e = p_edge_lookup(phandle, vkeys);
+ if (e)
+ e->flag |= PEDGE_SEAM;
}
void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart = phandle->construction_chart;
- int i, j, nboundaries = 0;
- PEdge *outer;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart = phandle->construction_chart;
+ int i, j, nboundaries = 0;
+ PEdge *outer;
- param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- phandle->ncharts = p_connect_pairs(phandle, (PBool)impl);
- phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
+ phandle->ncharts = p_connect_pairs(phandle, (PBool)impl);
+ phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
- p_chart_delete(phandle->construction_chart);
- phandle->construction_chart = NULL;
+ p_chart_delete(phandle->construction_chart);
+ phandle->construction_chart = NULL;
- phash_delete(phandle->hash_verts);
- phash_delete(phandle->hash_edges);
- phash_delete(phandle->hash_faces);
- phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL;
+ phash_delete(phandle->hash_verts);
+ phash_delete(phandle->hash_edges);
+ phash_delete(phandle->hash_faces);
+ phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL;
- for (i = j = 0; i < phandle->ncharts; i++) {
- PVert *v;
- chart = phandle->charts[i];
+ for (i = j = 0; i < phandle->ncharts; i++) {
+ PVert *v;
+ chart = phandle->charts[i];
- p_chart_boundaries(chart, &nboundaries, &outer);
+ p_chart_boundaries(chart, &nboundaries, &outer);
- if (!impl && nboundaries == 0) {
- p_chart_delete(chart);
- continue;
- }
+ if (!impl && nboundaries == 0) {
+ p_chart_delete(chart);
+ continue;
+ }
- phandle->charts[j] = chart;
- j++;
+ phandle->charts[j] = chart;
+ j++;
- if (fill && (nboundaries > 1))
- p_chart_fill_boundaries(chart, outer);
+ if (fill && (nboundaries > 1))
+ p_chart_fill_boundaries(chart, outer);
- for (v = chart->verts; v; v = v->nextlink)
- p_vert_load_pin_select_uvs(handle, v);
- }
+ for (v = chart->verts; v; v = v->nextlink)
+ p_vert_load_pin_select_uvs(handle, v);
+ }
- phandle->ncharts = j;
+ phandle->ncharts = j;
- phandle->state = PHANDLE_STATE_CONSTRUCTED;
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
{
- PHandle *phandle = (PHandle *)handle;
- PFace *f;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PFace *f;
+ int i;
- param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
- phandle->state = PHANDLE_STATE_LSCM;
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ phandle->state = PHANDLE_STATE_LSCM;
- for (i = 0; i < phandle->ncharts; i++) {
- for (f = phandle->charts[i]->faces; f; f = f->nextlink)
- p_face_backup_uvs(f);
- p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf);
- }
+ for (i = 0; i < phandle->ncharts; i++) {
+ for (f = phandle->charts[i]->faces; f; f = f->nextlink)
+ p_face_backup_uvs(f);
+ p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf);
+ }
}
void param_lscm_solve(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- int i;
- PBool result;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
+ PBool result;
- param_assert(phandle->state == PHANDLE_STATE_LSCM);
+ param_assert(phandle->state == PHANDLE_STATE_LSCM);
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- if (chart->u.lscm.context) {
- result = p_chart_lscm_solve(phandle, chart);
+ if (chart->u.lscm.context) {
+ result = p_chart_lscm_solve(phandle, chart);
- if (result && !(chart->flag & PCHART_HAS_PINS))
- p_chart_rotate_minimum_area(chart);
+ if (result && !(chart->flag & PCHART_HAS_PINS))
+ p_chart_rotate_minimum_area(chart);
- if (!result || (chart->u.lscm.pin1))
- p_chart_lscm_end(chart);
- }
- }
+ if (!result || (chart->u.lscm.pin1))
+ p_chart_lscm_end(chart);
+ }
+ }
}
void param_lscm_end(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ int i;
- param_assert(phandle->state == PHANDLE_STATE_LSCM);
+ param_assert(phandle->state == PHANDLE_STATE_LSCM);
- for (i = 0; i < phandle->ncharts; i++) {
- p_chart_lscm_end(phandle->charts[i]);
+ for (i = 0; i < phandle->ncharts; i++) {
+ p_chart_lscm_end(phandle->charts[i]);
#if 0
- p_chart_complexify(phandle->charts[i]);
+ p_chart_complexify(phandle->charts[i]);
#endif
- }
+ }
- phandle->state = PHANDLE_STATE_CONSTRUCTED;
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
void param_stretch_begin(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- PVert *v;
- PFace *f;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ PVert *v;
+ PFace *f;
+ int i;
- param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
- phandle->state = PHANDLE_STATE_STRETCH;
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ phandle->state = PHANDLE_STATE_STRETCH;
- phandle->rng = BLI_rng_new(31415926);
- phandle->blend = 0.0f;
+ phandle->rng = BLI_rng_new(31415926);
+ phandle->blend = 0.0f;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- for (v = chart->verts; v; v = v->nextlink)
- v->flag &= ~PVERT_PIN; /* don't use user-defined pins */
+ for (v = chart->verts; v; v = v->nextlink)
+ v->flag &= ~PVERT_PIN; /* don't use user-defined pins */
- p_stretch_pin_boundary(chart);
+ p_stretch_pin_boundary(chart);
- for (f = chart->faces; f; f = f->nextlink) {
- p_face_backup_uvs(f);
- f->u.area3d = p_face_area(f);
- }
- }
+ for (f = chart->faces; f; f = f->nextlink) {
+ p_face_backup_uvs(f);
+ f->u.area3d = p_face_area(f);
+ }
+ }
}
void param_stretch_blend(ParamHandle *handle, float blend)
{
- PHandle *phandle = (PHandle *)handle;
+ PHandle *phandle = (PHandle *)handle;
- param_assert(phandle->state == PHANDLE_STATE_STRETCH);
- phandle->blend = blend;
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+ phandle->blend = blend;
}
void param_stretch_iter(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
- param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
- p_chart_stretch_minimize(chart, phandle->rng);
- }
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ p_chart_stretch_minimize(chart, phandle->rng);
+ }
}
void param_stretch_end(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
+ PHandle *phandle = (PHandle *)handle;
- param_assert(phandle->state == PHANDLE_STATE_STRETCH);
- phandle->state = PHANDLE_STATE_CONSTRUCTED;
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
- BLI_rng_free(phandle->rng);
- phandle->rng = NULL;
+ BLI_rng_free(phandle->rng);
+ phandle->rng = NULL;
}
void param_smooth_area(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ int i;
- param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
- for (i = 0; i < phandle->ncharts; i++) {
- PChart *chart = phandle->charts[i];
- PVert *v;
+ for (i = 0; i < phandle->ncharts; i++) {
+ PChart *chart = phandle->charts[i];
+ PVert *v;
- for (v = chart->verts; v; v = v->nextlink)
- v->flag &= ~PVERT_PIN;
+ for (v = chart->verts; v; v = v->nextlink)
+ v->flag &= ~PVERT_PIN;
- p_smooth(chart);
- }
+ p_smooth(chart);
+ }
}
/* don't pack, just rotate (used for better packing) */
static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned)
{
- PChart *chart;
- int i;
+ PChart *chart;
+ int i;
- PHandle *phandle = (PHandle *)handle;
+ PHandle *phandle = (PHandle *)handle;
- for (i = 0; i < phandle->ncharts; i++) {
- float (*points)[2];
- float angle;
+ for (i = 0; i < phandle->ncharts; i++) {
+ float(*points)[2];
+ float angle;
- chart = phandle->charts[i];
+ chart = phandle->charts[i];
- if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
- continue;
- }
+ if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
+ continue;
+ }
- points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__);
+ points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__);
- p_chart_uv_to_array(chart, points);
+ p_chart_uv_to_array(chart, points);
- angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts);
+ angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts);
- MEM_freeN(points);
+ MEM_freeN(points);
- if (angle != 0.0f) {
- float mat[2][2];
- angle_to_mat2(mat, angle);
- p_chart_uv_transform(chart, mat);
- }
- }
+ if (angle != 0.0f) {
+ float mat[2][2];
+ angle_to_mat2(mat, angle);
+ p_chart_uv_transform(chart, mat);
+ }
+ }
}
void param_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
{
- /* box packing variables */
- BoxPack *boxarray, *box;
- float tot_width, tot_height, scale;
-
- PChart *chart;
- int i, unpacked = 0;
- float trans[2];
- double area = 0.0;
+ /* box packing variables */
+ BoxPack *boxarray, *box;
+ float tot_width, tot_height, scale;
- PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i, unpacked = 0;
+ float trans[2];
+ double area = 0.0;
- if (phandle->ncharts == 0)
- return;
+ PHandle *phandle = (PHandle *)handle;
- /* this could be its own function */
- if (do_rotate) {
- param_pack_rotate(handle, ignore_pinned);
- }
+ if (phandle->ncharts == 0)
+ return;
- if (phandle->aspx != phandle->aspy)
- param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy);
+ /* this could be its own function */
+ if (do_rotate) {
+ param_pack_rotate(handle, ignore_pinned);
+ }
- /* we may not use all these boxes */
- boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box");
+ if (phandle->aspx != phandle->aspy)
+ param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy);
+ /* we may not use all these boxes */
+ boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box");
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
- unpacked++;
- continue;
- }
+ if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
+ unpacked++;
+ continue;
+ }
- box = boxarray + (i - unpacked);
+ box = boxarray + (i - unpacked);
- p_chart_uv_bbox(chart, trans, chart->u.pack.size);
+ p_chart_uv_bbox(chart, trans, chart->u.pack.size);
- trans[0] = -trans[0];
- trans[1] = -trans[1];
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
- p_chart_uv_translate(chart, trans);
+ p_chart_uv_translate(chart, trans);
- box->w = chart->u.pack.size[0] + trans[0];
- box->h = chart->u.pack.size[1] + trans[1];
- box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */
+ box->w = chart->u.pack.size[0] + trans[0];
+ box->h = chart->u.pack.size[1] + trans[1];
+ box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */
- if (margin > 0.0f)
- area += (double)sqrtf(box->w * box->h);
- }
+ if (margin > 0.0f)
+ area += (double)sqrtf(box->w * box->h);
+ }
- if (margin > 0.0f) {
- /* multiply the margin by the area to give predictable results not dependent on UV scale,
- * ...Without using the area running pack multiple times also gives a bad feedback loop.
- * multiply by 0.1 so the margin value from the UI can be from
- * 0.0 to 1.0 but not give a massive margin */
- margin = (margin * (float)area) * 0.1f;
- unpacked = 0;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ if (margin > 0.0f) {
+ /* multiply the margin by the area to give predictable results not dependent on UV scale,
+ * ...Without using the area running pack multiple times also gives a bad feedback loop.
+ * multiply by 0.1 so the margin value from the UI can be from
+ * 0.0 to 1.0 but not give a massive margin */
+ margin = (margin * (float)area) * 0.1f;
+ unpacked = 0;
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
- unpacked++;
- continue;
- }
+ if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
+ unpacked++;
+ continue;
+ }
- box = boxarray + (i - unpacked);
- trans[0] = margin;
- trans[1] = margin;
- p_chart_uv_translate(chart, trans);
- box->w += margin * 2;
- box->h += margin * 2;
- }
- }
+ box = boxarray + (i - unpacked);
+ trans[0] = margin;
+ trans[1] = margin;
+ p_chart_uv_translate(chart, trans);
+ box->w += margin * 2;
+ box->h += margin * 2;
+ }
+ }
- BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height);
+ BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height);
- if (tot_height > tot_width)
- scale = 1.0f / tot_height;
- else
- scale = 1.0f / tot_width;
+ if (tot_height > tot_width)
+ scale = 1.0f / tot_height;
+ else
+ scale = 1.0f / tot_width;
- for (i = 0; i < phandle->ncharts - unpacked; i++) {
- box = boxarray + i;
- trans[0] = box->x;
- trans[1] = box->y;
+ for (i = 0; i < phandle->ncharts - unpacked; i++) {
+ box = boxarray + i;
+ trans[0] = box->x;
+ trans[1] = box->y;
- chart = phandle->charts[box->index];
- p_chart_uv_translate(chart, trans);
- p_chart_uv_scale(chart, scale);
- }
- MEM_freeN(boxarray);
+ chart = phandle->charts[box->index];
+ p_chart_uv_translate(chart, trans);
+ p_chart_uv_scale(chart, scale);
+ }
+ MEM_freeN(boxarray);
- if (phandle->aspx != phandle->aspy)
- param_scale(handle, phandle->aspx, phandle->aspy);
+ if (phandle->aspx != phandle->aspy)
+ param_scale(handle, phandle->aspx, phandle->aspy);
}
void param_average(ParamHandle *handle, bool ignore_pinned)
{
- PChart *chart;
- int i;
- float tot_uvarea = 0.0f, tot_facearea = 0.0f;
- float tot_fac, fac;
- float minv[2], maxv[2], trans[2];
- PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
+ float tot_uvarea = 0.0f, tot_facearea = 0.0f;
+ float tot_fac, fac;
+ float minv[2], maxv[2], trans[2];
+ PHandle *phandle = (PHandle *)handle;
- if (phandle->ncharts == 0)
- return;
+ if (phandle->ncharts == 0)
+ return;
- for (i = 0; i < phandle->ncharts; i++) {
- PFace *f;
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ PFace *f;
+ chart = phandle->charts[i];
- if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
- continue;
- }
+ if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
+ continue;
+ }
- chart->u.pack.area = 0.0f; /* 3d area */
- chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */
+ chart->u.pack.area = 0.0f; /* 3d area */
+ chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */
- for (f = chart->faces; f; f = f->nextlink) {
- chart->u.pack.area += p_face_area(f);
- chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f));
- }
+ for (f = chart->faces; f; f = f->nextlink) {
+ chart->u.pack.area += p_face_area(f);
+ chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f));
+ }
- tot_facearea += chart->u.pack.area;
- tot_uvarea += chart->u.pack.rescale;
- }
+ tot_facearea += chart->u.pack.area;
+ tot_uvarea += chart->u.pack.rescale;
+ }
- if (tot_facearea == tot_uvarea || tot_facearea == 0.0f || tot_uvarea == 0.0f) {
- /* nothing to do */
- return;
- }
+ if (tot_facearea == tot_uvarea || tot_facearea == 0.0f || tot_uvarea == 0.0f) {
+ /* nothing to do */
+ return;
+ }
- tot_fac = tot_facearea / tot_uvarea;
+ tot_fac = tot_facearea / tot_uvarea;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
- continue;
- }
+ if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
+ continue;
+ }
- if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) {
- fac = chart->u.pack.area / chart->u.pack.rescale;
+ if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) {
+ fac = chart->u.pack.area / chart->u.pack.rescale;
- /* Get the island center */
- p_chart_uv_bbox(chart, minv, maxv);
- trans[0] = (minv[0] + maxv[0]) / -2.0f;
- trans[1] = (minv[1] + maxv[1]) / -2.0f;
+ /* Get the island center */
+ p_chart_uv_bbox(chart, minv, maxv);
+ trans[0] = (minv[0] + maxv[0]) / -2.0f;
+ trans[1] = (minv[1] + maxv[1]) / -2.0f;
- /* Move center to 0,0 */
- p_chart_uv_translate(chart, trans);
- p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
+ /* Move center to 0,0 */
+ p_chart_uv_translate(chart, trans);
+ p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
- /* Move to original center */
- trans[0] = -trans[0];
- trans[1] = -trans[1];
- p_chart_uv_translate(chart, trans);
- }
- }
+ /* Move to original center */
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
+ p_chart_uv_translate(chart, trans);
+ }
+ }
}
void param_scale(ParamHandle *handle, float x, float y)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
- p_chart_uv_scale_xy(chart, x, y);
- }
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ p_chart_uv_scale_xy(chart, x, y);
+ }
}
void param_flush(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context)
- continue;
+ if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context)
+ continue;
- if (phandle->blend == 0.0f)
- p_flush_uvs(phandle, chart);
- else
- p_flush_uvs_blend(phandle, chart, phandle->blend);
- }
+ if (phandle->blend == 0.0f)
+ p_flush_uvs(phandle, chart);
+ else
+ p_flush_uvs_blend(phandle, chart, phandle->blend);
+ }
}
void param_flush_restore(ParamHandle *handle)
{
- PHandle *phandle = (PHandle *)handle;
- PChart *chart;
- PFace *f;
- int i;
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ PFace *f;
+ int i;
- for (i = 0; i < phandle->ncharts; i++) {
- chart = phandle->charts[i];
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
- for (f = chart->faces; f; f = f->nextlink)
- p_face_restore_uvs(f);
- }
+ for (f = chart->faces; f; f = f->nextlink)
+ p_face_restore_uvs(f);
+ }
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index 6724b568f57..2b80241e6e3 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -25,13 +25,13 @@
extern "C" {
#endif
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
-typedef void ParamHandle; /* handle to a set of charts */
-typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
+typedef void ParamHandle; /* handle to a set of charts */
+typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
typedef enum ParamBool {
- PARAM_TRUE = 1,
- PARAM_FALSE = 0,
+ PARAM_TRUE = 1,
+ PARAM_FALSE = 0,
} ParamBool;
/* Chart construction:
@@ -58,8 +58,7 @@ void param_face_add(ParamHandle *handle,
ParamBool *pin,
ParamBool *select);
-void param_edge_set_seam(ParamHandle *handle,
- ParamKey *vkeys);
+void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl);
void param_delete(ParamHandle *chart);
@@ -107,7 +106,6 @@ void param_scale(ParamHandle *handle, float x, float y);
void param_flush(ParamHandle *handle);
void param_flush_restore(ParamHandle *handle);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 91167e247f4..71a3fdf055e 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -21,7 +21,6 @@
* \ingroup eduv
*/
-
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -73,26 +72,25 @@
/* object that stores display data for previewing before confirming stitching */
typedef struct StitchPreviewer {
- /* here we'll store the preview triangle indices of the mesh */
- float *preview_polys;
- /* uvs per polygon. */
- unsigned int *uvs_per_polygon;
- /*number of preview polygons */
- unsigned int num_polys;
- /* preview data. These will be either the previewed vertices or edges
- * depending on stitch mode settings */
- float *preview_stitchable;
- float *preview_unstitchable;
- /* here we'll store the number of elements to be drawn */
- unsigned int num_stitchable;
- unsigned int num_unstitchable;
- unsigned int preview_uvs;
- /* ...and here we'll store the static island triangles */
- float *static_tris;
- unsigned int num_static_tris;
+ /* here we'll store the preview triangle indices of the mesh */
+ float *preview_polys;
+ /* uvs per polygon. */
+ unsigned int *uvs_per_polygon;
+ /*number of preview polygons */
+ unsigned int num_polys;
+ /* preview data. These will be either the previewed vertices or edges
+ * depending on stitch mode settings */
+ float *preview_stitchable;
+ float *preview_unstitchable;
+ /* here we'll store the number of elements to be drawn */
+ unsigned int num_stitchable;
+ unsigned int num_unstitchable;
+ unsigned int preview_uvs;
+ /* ...and here we'll store the static island triangles */
+ float *static_tris;
+ unsigned int num_static_tris;
} StitchPreviewer;
-
struct IslandStitchData;
/**
@@ -101,115 +99,114 @@ struct IslandStitchData;
* elements of the island except from the stitchable.
*/
typedef struct IslandStitchData {
- /* rotation can be used only for edges, for vertices there is no such notion */
- float rotation;
- float rotation_neg;
- float translation[2];
- /* Used for rotation, the island will rotate around this point */
- float medianPoint[2];
- int numOfElements;
- int num_rot_elements;
- int num_rot_elements_neg;
- /* flag to remember if island has been added for preview */
- char addedForPreview;
- /* flag an island to be considered for determining static island */
- char stitchableCandidate;
- /* if edge rotation is used, flag so that vertex rotation is not used */
- bool use_edge_rotation;
+ /* rotation can be used only for edges, for vertices there is no such notion */
+ float rotation;
+ float rotation_neg;
+ float translation[2];
+ /* Used for rotation, the island will rotate around this point */
+ float medianPoint[2];
+ int numOfElements;
+ int num_rot_elements;
+ int num_rot_elements_neg;
+ /* flag to remember if island has been added for preview */
+ char addedForPreview;
+ /* flag an island to be considered for determining static island */
+ char stitchableCandidate;
+ /* if edge rotation is used, flag so that vertex rotation is not used */
+ bool use_edge_rotation;
} IslandStitchData;
/* just for averaging UVs */
typedef struct UVVertAverage {
- float uv[2];
- unsigned short count;
+ float uv[2];
+ unsigned short count;
} UVVertAverage;
typedef struct UvEdge {
- /** index to uv buffer */
- unsigned int uv1;
- unsigned int uv2;
- /** general use flag
- * (Used to check if edge is boundary here, and propagates to adjacency elements) */
- unsigned char flag;
- /** element that guarantees element->face
- * has the edge on element->tfindex and element->tfindex+1 is the second uv */
- UvElement *element;
- /** next uv edge with the same exact vertices as this one.
- * Calculated at startup to save time */
- struct UvEdge *next;
- /** point to first of common edges. Needed for iteration */
- struct UvEdge *first;
+ /** index to uv buffer */
+ unsigned int uv1;
+ unsigned int uv2;
+ /** general use flag
+ * (Used to check if edge is boundary here, and propagates to adjacency elements) */
+ unsigned char flag;
+ /** element that guarantees element->face
+ * has the edge on element->tfindex and element->tfindex+1 is the second uv */
+ UvElement *element;
+ /** next uv edge with the same exact vertices as this one.
+ * Calculated at startup to save time */
+ struct UvEdge *next;
+ /** point to first of common edges. Needed for iteration */
+ struct UvEdge *first;
} UvEdge;
-
/* stitch state object */
typedef struct StitchState {
- float aspect;
- /* object for editmesh */
- Object *obedit;
- /* editmesh, cached for use in modal handler */
- BMEditMesh *em;
-
- /* element map for getting info about uv connectivity */
- UvElementMap *element_map;
- /* edge container */
- UvEdge *uvedges;
- /* container of first of a group of coincident uvs, these will be operated upon */
- UvElement **uvs;
- /* maps uvelements to their first coincident uv */
- int *map;
- /* 2D normals per uv to calculate rotation for snapping */
- float *normals;
- /* edge storage */
- UvEdge *edges;
- /* hash for quick lookup of edges */
- GHash *edge_hash;
- /* which islands to stop at (to make active) when pressing 'I' */
- bool *island_is_stitchable;
-
- /* count of separate uvs and edges */
- int total_separate_edges;
- int total_separate_uvs;
- /* hold selection related information */
- void **selection_stack;
- int selection_size;
-
- /* store number of primitives per face so that we can allocate the active island buffer later */
- unsigned int *tris_per_island;
- /* preview data */
- StitchPreviewer *stitch_preview;
+ float aspect;
+ /* object for editmesh */
+ Object *obedit;
+ /* editmesh, cached for use in modal handler */
+ BMEditMesh *em;
+
+ /* element map for getting info about uv connectivity */
+ UvElementMap *element_map;
+ /* edge container */
+ UvEdge *uvedges;
+ /* container of first of a group of coincident uvs, these will be operated upon */
+ UvElement **uvs;
+ /* maps uvelements to their first coincident uv */
+ int *map;
+ /* 2D normals per uv to calculate rotation for snapping */
+ float *normals;
+ /* edge storage */
+ UvEdge *edges;
+ /* hash for quick lookup of edges */
+ GHash *edge_hash;
+ /* which islands to stop at (to make active) when pressing 'I' */
+ bool *island_is_stitchable;
+
+ /* count of separate uvs and edges */
+ int total_separate_edges;
+ int total_separate_uvs;
+ /* hold selection related information */
+ void **selection_stack;
+ int selection_size;
+
+ /* store number of primitives per face so that we can allocate the active island buffer later */
+ unsigned int *tris_per_island;
+ /* preview data */
+ StitchPreviewer *stitch_preview;
} StitchState;
/* Stitch state container. */
typedef struct StitchStateContainer {
- /* clear seams of stitched edges after stitch */
- bool clear_seams;
- /* use limit flag */
- bool use_limit;
- /* limit to operator, same as original operator */
- float limit_dist;
- /* snap uv islands together during stitching */
- bool snap_islands;
- /* stitch at midpoints or at islands */
- bool midpoints;
- /* vert or edge mode used for stitching */
- char mode;
- /* handle for drawing */
- void *draw_handle;
- /* island that stays in place */
- int static_island;
-
- /* Objects and states are aligned. */
- int objects_len;
- Object **objects;
- StitchState **states;
-
- int active_object_index;
+ /* clear seams of stitched edges after stitch */
+ bool clear_seams;
+ /* use limit flag */
+ bool use_limit;
+ /* limit to operator, same as original operator */
+ float limit_dist;
+ /* snap uv islands together during stitching */
+ bool snap_islands;
+ /* stitch at midpoints or at islands */
+ bool midpoints;
+ /* vert or edge mode used for stitching */
+ char mode;
+ /* handle for drawing */
+ void *draw_handle;
+ /* island that stays in place */
+ int static_island;
+
+ /* Objects and states are aligned. */
+ int objects_len;
+ Object **objects;
+ StitchState **states;
+
+ int active_object_index;
} StitchStateContainer;
typedef struct PreviewPosition {
- int data_position;
- int polycount_position;
+ int data_position;
+ int polycount_position;
} PreviewPosition;
/*
* defines for UvElement/UcEdge flags
@@ -223,2529 +220,2614 @@ typedef struct PreviewPosition {
#define STITCH_NO_PREVIEW -1
enum StitchModes {
- STITCH_VERT,
- STITCH_EDGE,
+ STITCH_VERT,
+ STITCH_EDGE,
};
/* UvElement identification. */
typedef struct UvElementID {
- int faceIndex;
- int elementIndex;
+ int faceIndex;
+ int elementIndex;
} UvElementID;
/* StitchState initializition. */
typedef struct StitchStateInit {
- int uv_selected_count;
- UvElementID *to_select;
+ int uv_selected_count;
+ UvElementID *to_select;
} StitchStateInit;
/* constructor */
static StitchPreviewer *stitch_preview_init(void)
{
- StitchPreviewer *stitch_preview;
+ StitchPreviewer *stitch_preview;
- stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
- stitch_preview->preview_polys = NULL;
- stitch_preview->preview_stitchable = NULL;
- stitch_preview->preview_unstitchable = NULL;
- stitch_preview->uvs_per_polygon = NULL;
+ stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
+ stitch_preview->preview_polys = NULL;
+ stitch_preview->preview_stitchable = NULL;
+ stitch_preview->preview_unstitchable = NULL;
+ stitch_preview->uvs_per_polygon = NULL;
- stitch_preview->preview_uvs = 0;
- stitch_preview->num_polys = 0;
- stitch_preview->num_stitchable = 0;
- stitch_preview->num_unstitchable = 0;
+ stitch_preview->preview_uvs = 0;
+ stitch_preview->num_polys = 0;
+ stitch_preview->num_stitchable = 0;
+ stitch_preview->num_unstitchable = 0;
- stitch_preview->static_tris = NULL;
+ stitch_preview->static_tris = NULL;
- stitch_preview->num_static_tris = 0;
+ stitch_preview->num_static_tris = 0;
- return stitch_preview;
+ return stitch_preview;
}
/* destructor...yeah this should be C++ :) */
static void stitch_preview_delete(StitchPreviewer *stitch_preview)
{
- if (stitch_preview) {
- if (stitch_preview->preview_polys) {
- MEM_freeN(stitch_preview->preview_polys);
- stitch_preview->preview_polys = NULL;
- }
- if (stitch_preview->uvs_per_polygon) {
- MEM_freeN(stitch_preview->uvs_per_polygon);
- stitch_preview->uvs_per_polygon = NULL;
- }
- if (stitch_preview->preview_stitchable) {
- MEM_freeN(stitch_preview->preview_stitchable);
- stitch_preview->preview_stitchable = NULL;
- }
- if (stitch_preview->preview_unstitchable) {
- MEM_freeN(stitch_preview->preview_unstitchable);
- stitch_preview->preview_unstitchable = NULL;
- }
- if (stitch_preview->static_tris) {
- MEM_freeN(stitch_preview->static_tris);
- stitch_preview->static_tris = NULL;
- }
- MEM_freeN(stitch_preview);
- }
+ if (stitch_preview) {
+ if (stitch_preview->preview_polys) {
+ MEM_freeN(stitch_preview->preview_polys);
+ stitch_preview->preview_polys = NULL;
+ }
+ if (stitch_preview->uvs_per_polygon) {
+ MEM_freeN(stitch_preview->uvs_per_polygon);
+ stitch_preview->uvs_per_polygon = NULL;
+ }
+ if (stitch_preview->preview_stitchable) {
+ MEM_freeN(stitch_preview->preview_stitchable);
+ stitch_preview->preview_stitchable = NULL;
+ }
+ if (stitch_preview->preview_unstitchable) {
+ MEM_freeN(stitch_preview->preview_unstitchable);
+ stitch_preview->preview_unstitchable = NULL;
+ }
+ if (stitch_preview->static_tris) {
+ MEM_freeN(stitch_preview->static_tris);
+ stitch_preview->static_tris = NULL;
+ }
+ MEM_freeN(stitch_preview);
+ }
}
/* This function updates the header of the UV editor when the stitch tool updates its settings */
static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
{
- const char *str = IFACE_(
- "Mode(TAB) %s, "
- "(S)nap %s, "
- "(M)idpoints %s, "
- "(L)imit %.2f (Alt Wheel adjust) %s, "
- "Switch (I)sland, "
- "shift select vertices"
- );
-
- char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
-
- if (sa) {
- BLI_snprintf(
- msg, sizeof(msg), str,
- ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
- WM_bool_as_string(ssc->snap_islands),
- WM_bool_as_string(ssc->midpoints),
- ssc->limit_dist,
- WM_bool_as_string(ssc->use_limit));
-
- ED_workspace_status_text(C, msg);
- }
+ const char *str = IFACE_(
+ "Mode(TAB) %s, "
+ "(S)nap %s, "
+ "(M)idpoints %s, "
+ "(L)imit %.2f (Alt Wheel adjust) %s, "
+ "Switch (I)sland, "
+ "shift select vertices");
+
+ char msg[UI_MAX_DRAW_STR];
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa) {
+ BLI_snprintf(msg,
+ sizeof(msg),
+ str,
+ ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
+ WM_bool_as_string(ssc->snap_islands),
+ WM_bool_as_string(ssc->midpoints),
+ ssc->limit_dist,
+ WM_bool_as_string(ssc->use_limit));
+
+ ED_workspace_status_text(C, msg);
+ }
}
static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
{
- if (island == elementMap->totalIslands - 1) {
- return elementMap->totalUVs - elementMap->islandIndices[island];
- }
- else {
- return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island];
- }
+ if (island == elementMap->totalIslands - 1) {
+ return elementMap->totalUVs - elementMap->islandIndices[island];
+ }
+ else {
+ return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island];
+ }
}
static void stitch_uv_rotate(float mat[2][2], float medianPoint[2], float uv[2], float aspect)
{
- float uv_rotation_result[2];
+ float uv_rotation_result[2];
- uv[1] /= aspect;
+ uv[1] /= aspect;
- sub_v2_v2(uv, medianPoint);
- mul_v2_m2v2(uv_rotation_result, mat, uv);
- add_v2_v2v2(uv, uv_rotation_result, medianPoint);
+ sub_v2_v2(uv, medianPoint);
+ mul_v2_m2v2(uv_rotation_result, mat, uv);
+ add_v2_v2v2(uv, uv_rotation_result, medianPoint);
- uv[1] *= aspect;
+ uv[1] *= aspect;
}
/* check if two uvelements are stitchable.
* This should only operate on -different- separate UvElements */
-static bool stitch_check_uvs_stitchable(
- UvElement *element, UvElement *element_iter,
- StitchStateContainer *ssc, StitchState *state)
+static bool stitch_check_uvs_stitchable(UvElement *element,
+ UvElement *element_iter,
+ StitchStateContainer *ssc,
+ StitchState *state)
{
- BMesh *bm = state->em->bm;
- float limit;
-
- if (element_iter == element) {
- return 0;
- }
-
- limit = ssc->limit_dist;
-
- if (ssc->use_limit) {
- MLoopUV *luv, *luv_iter;
- BMLoop *l;
-
-
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- l = element_iter->l;
- luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
- fabsf(luv->uv[1] - luv_iter->uv[1]) < limit)
- {
- return 1;
- }
- else {
- return 0;
- }
- }
- else {
- return 1;
- }
+ BMesh *bm = state->em->bm;
+ float limit;
+
+ if (element_iter == element) {
+ return 0;
+ }
+
+ limit = ssc->limit_dist;
+
+ if (ssc->use_limit) {
+ MLoopUV *luv, *luv_iter;
+ BMLoop *l;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ l = element_iter->l;
+ luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
+ fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 1;
+ }
}
-static bool stitch_check_edges_stitchable(
- UvEdge *edge, UvEdge *edge_iter,
- StitchStateContainer *ssc, StitchState *state)
+static bool stitch_check_edges_stitchable(UvEdge *edge,
+ UvEdge *edge_iter,
+ StitchStateContainer *ssc,
+ StitchState *state)
{
- BMesh *bm = state->em->bm;
- float limit;
-
- if (edge_iter == edge) {
- return 0;
- }
-
- limit = ssc->limit_dist;
-
- if (ssc->use_limit) {
- BMLoop *l;
- MLoopUV *luv_orig1, *luv_iter1;
- MLoopUV *luv_orig2, *luv_iter2;
-
- l = state->uvs[edge->uv1]->l;
- luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- l = state->uvs[edge_iter->uv1]->l;
- luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- l = state->uvs[edge->uv2]->l;
- luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- l = state->uvs[edge_iter->uv2]->l;
- luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit &&
- fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit &&
- fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit &&
- fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit)
- {
- return 1;
- }
- else {
- return 0;
- }
- }
- else {
- return 1;
- }
+ BMesh *bm = state->em->bm;
+ float limit;
+
+ if (edge_iter == edge) {
+ return 0;
+ }
+
+ limit = ssc->limit_dist;
+
+ if (ssc->use_limit) {
+ BMLoop *l;
+ MLoopUV *luv_orig1, *luv_iter1;
+ MLoopUV *luv_orig2, *luv_iter2;
+
+ l = state->uvs[edge->uv1]->l;
+ luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv1]->l;
+ luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ l = state->uvs[edge->uv2]->l;
+ luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv2]->l;
+ luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit &&
+ fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit &&
+ fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit &&
+ fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return 1;
+ }
}
-static bool stitch_check_uvs_state_stitchable(
- UvElement *element, UvElement *element_iter,
- StitchStateContainer *ssc, StitchState *state)
+static bool stitch_check_uvs_state_stitchable(UvElement *element,
+ UvElement *element_iter,
+ StitchStateContainer *ssc,
+ StitchState *state)
{
- if ((ssc->snap_islands && element->island == element_iter->island) ||
- (!ssc->midpoints && element->island == element_iter->island))
- {
- return 0;
- }
+ if ((ssc->snap_islands && element->island == element_iter->island) ||
+ (!ssc->midpoints && element->island == element_iter->island)) {
+ return 0;
+ }
- return stitch_check_uvs_stitchable(element, element_iter, ssc, state);
+ return stitch_check_uvs_stitchable(element, element_iter, ssc, state);
}
-static bool stitch_check_edges_state_stitchable(
- UvEdge *edge, UvEdge *edge_iter,
- StitchStateContainer *ssc, StitchState *state)
+static bool stitch_check_edges_state_stitchable(UvEdge *edge,
+ UvEdge *edge_iter,
+ StitchStateContainer *ssc,
+ StitchState *state)
{
- if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) ||
- (!ssc->midpoints && edge->element->island == edge_iter->element->island))
- {
- return 0;
- }
+ if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) ||
+ (!ssc->midpoints && edge->element->island == edge_iter->element->island)) {
+ return 0;
+ }
- return stitch_check_edges_stitchable(edge, edge_iter, ssc, state);
+ return stitch_check_edges_stitchable(edge, edge_iter, ssc, state);
}
/* calculate snapping for islands */
-static void stitch_calculate_island_snapping(
- StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview,
- IslandStitchData *island_stitch_data, int final)
+static void stitch_calculate_island_snapping(StitchState *state,
+ PreviewPosition *preview_position,
+ StitchPreviewer *preview,
+ IslandStitchData *island_stitch_data,
+ int final)
{
- BMesh *bm = state->em->bm;
- int i;
- UvElement *element;
-
- for (i = 0; i < state->element_map->totalIslands; i++) {
- if (island_stitch_data[i].addedForPreview) {
- int numOfIslandUVs = 0, j;
- int totelem = island_stitch_data[i].num_rot_elements_neg + island_stitch_data[i].num_rot_elements;
- float rotation;
- float rotation_mat[2][2];
-
- /* check to avoid divide by 0 */
- if (island_stitch_data[i].num_rot_elements > 1)
- island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
-
- if (island_stitch_data[i].num_rot_elements_neg > 1)
- island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg;
-
- if (island_stitch_data[i].numOfElements > 1) {
- island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
- island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
-
- island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
- island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
- }
-
- island_stitch_data[i].medianPoint[1] /= state->aspect;
- if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) ||
- island_stitch_data[i].num_rot_elements == 0 || island_stitch_data[i].num_rot_elements_neg == 0)
- {
- rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements -
- island_stitch_data[i].rotation_neg *
- island_stitch_data[i].num_rot_elements_neg) / totelem;
- }
- else {
- rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements +
- (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) *
- island_stitch_data[i].num_rot_elements_neg) / totelem;
- }
-
- angle_to_mat2(rotation_mat, rotation);
- numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
- element = &state->element_map->buf[state->element_map->islandIndices[i]];
- for (j = 0; j < numOfIslandUVs; j++, element++) {
- /* stitchable uvs have already been processed, don't process */
- if (!(element->flag & STITCH_PROCESSED)) {
- MLoopUV *luv;
- BMLoop *l;
-
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- if (final) {
-
- stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect);
-
- add_v2_v2(luv->uv, island_stitch_data[i].translation);
- }
-
- else {
-
- int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position;
-
- stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint,
- preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index,
- state->aspect);
-
- add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index,
- island_stitch_data[i].translation);
- }
- }
- /* cleanup */
- element->flag &= STITCH_SELECTED;
- }
- }
- }
+ BMesh *bm = state->em->bm;
+ int i;
+ UvElement *element;
+
+ for (i = 0; i < state->element_map->totalIslands; i++) {
+ if (island_stitch_data[i].addedForPreview) {
+ int numOfIslandUVs = 0, j;
+ int totelem = island_stitch_data[i].num_rot_elements_neg +
+ island_stitch_data[i].num_rot_elements;
+ float rotation;
+ float rotation_mat[2][2];
+
+ /* check to avoid divide by 0 */
+ if (island_stitch_data[i].num_rot_elements > 1)
+ island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
+
+ if (island_stitch_data[i].num_rot_elements_neg > 1)
+ island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg;
+
+ if (island_stitch_data[i].numOfElements > 1) {
+ island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
+ island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
+
+ island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
+ island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
+ }
+
+ island_stitch_data[i].medianPoint[1] /= state->aspect;
+ if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) ||
+ island_stitch_data[i].num_rot_elements == 0 ||
+ island_stitch_data[i].num_rot_elements_neg == 0) {
+ rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements -
+ island_stitch_data[i].rotation_neg *
+ island_stitch_data[i].num_rot_elements_neg) /
+ totelem;
+ }
+ else {
+ rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements +
+ (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) *
+ island_stitch_data[i].num_rot_elements_neg) /
+ totelem;
+ }
+
+ angle_to_mat2(rotation_mat, rotation);
+ numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
+ element = &state->element_map->buf[state->element_map->islandIndices[i]];
+ for (j = 0; j < numOfIslandUVs; j++, element++) {
+ /* stitchable uvs have already been processed, don't process */
+ if (!(element->flag & STITCH_PROCESSED)) {
+ MLoopUV *luv;
+ BMLoop *l;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (final) {
+
+ stitch_uv_rotate(
+ rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect);
+
+ add_v2_v2(luv->uv, island_stitch_data[i].translation);
+ }
+
+ else {
+
+ int face_preview_pos =
+ preview_position[BM_elem_index_get(element->l->f)].data_position;
+
+ stitch_uv_rotate(rotation_mat,
+ island_stitch_data[i].medianPoint,
+ preview->preview_polys + face_preview_pos +
+ 2 * element->loop_of_poly_index,
+ state->aspect);
+
+ add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index,
+ island_stitch_data[i].translation);
+ }
+ }
+ /* cleanup */
+ element->flag &= STITCH_SELECTED;
+ }
+ }
+ }
}
-
-
-static void stitch_island_calculate_edge_rotation(
- UvEdge *edge, StitchStateContainer *ssc, StitchState *state, UVVertAverage *uv_average,
- unsigned int *uvfinal_map, IslandStitchData *island_stitch_data)
+static void stitch_island_calculate_edge_rotation(UvEdge *edge,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ UVVertAverage *uv_average,
+ unsigned int *uvfinal_map,
+ IslandStitchData *island_stitch_data)
{
- BMesh *bm = state->em->bm;
- UvElement *element1, *element2;
- float uv1[2], uv2[2];
- float edgecos, edgesin;
- int index1, index2;
- float rotation;
- MLoopUV *luv1, *luv2;
-
- element1 = state->uvs[edge->uv1];
- element2 = state->uvs[edge->uv2];
-
- luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV);
- luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
-
- if (ssc->mode == STITCH_VERT) {
- index1 = uvfinal_map[element1 - state->element_map->buf];
- index2 = uvfinal_map[element2 - state->element_map->buf];
- }
- else {
- index1 = edge->uv1;
- index2 = edge->uv2;
- }
- /* the idea here is to take the directions of the edges and find the rotation between
- * final and initial direction. This, using inner and outer vector products,
- * gives the angle. Directions are differences so... */
- uv1[0] = luv2->uv[0] - luv1->uv[0];
- uv1[1] = luv2->uv[1] - luv1->uv[1];
-
- uv1[1] /= state->aspect;
-
- uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
- uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
-
- uv2[1] /= state->aspect;
-
- normalize_v2(uv1);
- normalize_v2(uv2);
-
- edgecos = dot_v2v2(uv1, uv2);
- edgesin = cross_v2v2(uv1, uv2);
- rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
-
- if (edgesin > 0.0f) {
- island_stitch_data[element1->island].num_rot_elements++;
- island_stitch_data[element1->island].rotation += rotation;
- }
- else {
- island_stitch_data[element1->island].num_rot_elements_neg++;
- island_stitch_data[element1->island].rotation_neg += rotation;
- }
+ BMesh *bm = state->em->bm;
+ UvElement *element1, *element2;
+ float uv1[2], uv2[2];
+ float edgecos, edgesin;
+ int index1, index2;
+ float rotation;
+ MLoopUV *luv1, *luv2;
+
+ element1 = state->uvs[edge->uv1];
+ element2 = state->uvs[edge->uv2];
+
+ luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
+
+ if (ssc->mode == STITCH_VERT) {
+ index1 = uvfinal_map[element1 - state->element_map->buf];
+ index2 = uvfinal_map[element2 - state->element_map->buf];
+ }
+ else {
+ index1 = edge->uv1;
+ index2 = edge->uv2;
+ }
+ /* the idea here is to take the directions of the edges and find the rotation between
+ * final and initial direction. This, using inner and outer vector products,
+ * gives the angle. Directions are differences so... */
+ uv1[0] = luv2->uv[0] - luv1->uv[0];
+ uv1[1] = luv2->uv[1] - luv1->uv[1];
+
+ uv1[1] /= state->aspect;
+
+ uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
+ uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
+
+ uv2[1] /= state->aspect;
+
+ normalize_v2(uv1);
+ normalize_v2(uv2);
+
+ edgecos = dot_v2v2(uv1, uv2);
+ edgesin = cross_v2v2(uv1, uv2);
+ rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
+
+ if (edgesin > 0.0f) {
+ island_stitch_data[element1->island].num_rot_elements++;
+ island_stitch_data[element1->island].rotation += rotation;
+ }
+ else {
+ island_stitch_data[element1->island].num_rot_elements_neg++;
+ island_stitch_data[element1->island].rotation_neg += rotation;
+ }
}
-
-static void stitch_island_calculate_vert_rotation(
- UvElement *element, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data)
+static void stitch_island_calculate_vert_rotation(UvElement *element,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data)
{
- float edgecos = 1.0f, edgesin = 0.0f;
- int index;
- UvElement *element_iter;
- float rotation = 0, rotation_neg = 0;
- int rot_elem = 0, rot_elem_neg = 0;
- BMLoop *l;
-
- if (element->island == ssc->static_island && !ssc->midpoints)
- return;
-
- l = element->l;
-
- index = BM_elem_index_get(l->v);
-
- element_iter = state->element_map->vert[index];
-
- for (; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
- int index_tmp1, index_tmp2;
- float normal[2];
-
- /* only calculate rotation against static island uv verts */
- if (!ssc->midpoints && element_iter->island != ssc->static_island)
- continue;
-
- index_tmp1 = element_iter - state->element_map->buf;
- index_tmp1 = state->map[index_tmp1];
- index_tmp2 = element - state->element_map->buf;
- index_tmp2 = state->map[index_tmp2];
-
- negate_v2_v2(normal, state->normals + index_tmp2 * 2);
- edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
- edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
- if (edgesin > 0.0f) {
- rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
- rot_elem++;
- }
- else {
- rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
- rot_elem_neg++;
- }
- }
- }
-
- if (ssc->midpoints) {
- rotation /= 2.0f;
- rotation_neg /= 2.0f;
- }
- island_stitch_data[element->island].num_rot_elements += rot_elem;
- island_stitch_data[element->island].rotation += rotation;
- island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg;
- island_stitch_data[element->island].rotation_neg += rotation_neg;
+ float edgecos = 1.0f, edgesin = 0.0f;
+ int index;
+ UvElement *element_iter;
+ float rotation = 0, rotation_neg = 0;
+ int rot_elem = 0, rot_elem_neg = 0;
+ BMLoop *l;
+
+ if (element->island == ssc->static_island && !ssc->midpoints)
+ return;
+
+ l = element->l;
+
+ index = BM_elem_index_get(l->v);
+
+ element_iter = state->element_map->vert[index];
+
+ for (; element_iter; element_iter = element_iter->next) {
+ if (element_iter->separate &&
+ stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
+ int index_tmp1, index_tmp2;
+ float normal[2];
+
+ /* only calculate rotation against static island uv verts */
+ if (!ssc->midpoints && element_iter->island != ssc->static_island)
+ continue;
+
+ index_tmp1 = element_iter - state->element_map->buf;
+ index_tmp1 = state->map[index_tmp1];
+ index_tmp2 = element - state->element_map->buf;
+ index_tmp2 = state->map[index_tmp2];
+
+ negate_v2_v2(normal, state->normals + index_tmp2 * 2);
+ edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
+ edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
+ if (edgesin > 0.0f) {
+ rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
+ rot_elem++;
+ }
+ else {
+ rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
+ rot_elem_neg++;
+ }
+ }
+ }
+
+ if (ssc->midpoints) {
+ rotation /= 2.0f;
+ rotation_neg /= 2.0f;
+ }
+ island_stitch_data[element->island].num_rot_elements += rot_elem;
+ island_stitch_data[element->island].rotation += rotation;
+ island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg;
+ island_stitch_data[element->island].rotation_neg += rotation_neg;
}
-
static void state_delete(StitchState *state)
{
- if (state) {
- if (state->island_is_stitchable) {
- MEM_freeN(state->island_is_stitchable);
- }
- if (state->element_map) {
- BM_uv_element_map_free(state->element_map);
- }
- if (state->uvs) {
- MEM_freeN(state->uvs);
- }
- if (state->selection_stack) {
- MEM_freeN(state->selection_stack);
- }
- if (state->tris_per_island) {
- MEM_freeN(state->tris_per_island);
- }
- if (state->map) {
- MEM_freeN(state->map);
- }
- if (state->normals) {
- MEM_freeN(state->normals);
- }
- if (state->edges) {
- MEM_freeN(state->edges);
- }
- if (state->stitch_preview) {
- stitch_preview_delete(state->stitch_preview);
- }
- if (state->edge_hash) {
- BLI_ghash_free(state->edge_hash, NULL, NULL);
- }
- MEM_freeN(state);
- }
+ if (state) {
+ if (state->island_is_stitchable) {
+ MEM_freeN(state->island_is_stitchable);
+ }
+ if (state->element_map) {
+ BM_uv_element_map_free(state->element_map);
+ }
+ if (state->uvs) {
+ MEM_freeN(state->uvs);
+ }
+ if (state->selection_stack) {
+ MEM_freeN(state->selection_stack);
+ }
+ if (state->tris_per_island) {
+ MEM_freeN(state->tris_per_island);
+ }
+ if (state->map) {
+ MEM_freeN(state->map);
+ }
+ if (state->normals) {
+ MEM_freeN(state->normals);
+ }
+ if (state->edges) {
+ MEM_freeN(state->edges);
+ }
+ if (state->stitch_preview) {
+ stitch_preview_delete(state->stitch_preview);
+ }
+ if (state->edge_hash) {
+ BLI_ghash_free(state->edge_hash, NULL, NULL);
+ }
+ MEM_freeN(state);
+ }
}
static void state_delete_all(StitchStateContainer *ssc)
{
- if (ssc) {
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- state_delete(ssc->states[ob_index]);
- }
- MEM_freeN(ssc->states);
- MEM_freeN(ssc->objects);
- MEM_freeN(ssc);
- }
+ if (ssc) {
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ state_delete(ssc->states[ob_index]);
+ }
+ MEM_freeN(ssc->states);
+ MEM_freeN(ssc->objects);
+ MEM_freeN(ssc);
+ }
}
static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
{
- UvEdge *edges = state->edges;
- const int *map = state->map;
- UvElementMap *element_map = state->element_map;
- UvElement *first_element = element_map->buf;
- int i;
-
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = edges + i;
-
- if (edge->first)
- continue;
-
- /* only boundary edges can be stitched. Yes. Sorry about that :p */
- if (edge->flag & STITCH_BOUNDARY) {
- UvElement *element1 = state->uvs[edge->uv1];
- UvElement *element2 = state->uvs[edge->uv2];
-
- /* Now iterate through all faces and try to find edges sharing the same vertices */
- UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
- UvEdge *last_set = edge;
- int elemindex2 = BM_elem_index_get(element2->l->v);
-
- edge->first = edge;
-
- for (; iter1; iter1 = iter1->next) {
- UvElement *iter2 = NULL;
-
- /* check to see if other vertex of edge belongs to same vertex as */
- if (BM_elem_index_get(iter1->l->next->v) == elemindex2)
- iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next);
- else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2)
- iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev);
-
- if (iter2) {
- int index1 = map[iter1 - first_element];
- int index2 = map[iter2 - first_element];
- UvEdge edgetmp;
- UvEdge *edge2, *eiter;
- bool valid = true;
-
- /* make sure the indices are well behaved */
- if (index1 > index2) {
- SWAP(int, index1, index2);
- }
-
- edgetmp.uv1 = index1;
- edgetmp.uv2 = index2;
-
- /* get the edge from the hash */
- edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
-
- /* more iteration to make sure non-manifold case is handled nicely */
- for (eiter = edge; eiter; eiter = eiter->next) {
- if (edge2 == eiter) {
- valid = false;
- break;
- }
- }
-
- if (valid) {
- /* here I am taking care of non manifold case, assuming more than two matching edges.
- * I am not too sure we want this though */
- last_set->next = edge2;
- last_set = edge2;
- /* set first, similarly to uv elements.
- * Now we can iterate among common edges easily */
- edge2->first = edge;
- }
- }
- }
- }
- else {
- /* so stitchability code works */
- edge->first = edge;
- }
- }
+ UvEdge *edges = state->edges;
+ const int *map = state->map;
+ UvElementMap *element_map = state->element_map;
+ UvElement *first_element = element_map->buf;
+ int i;
+
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = edges + i;
+
+ if (edge->first)
+ continue;
+
+ /* only boundary edges can be stitched. Yes. Sorry about that :p */
+ if (edge->flag & STITCH_BOUNDARY) {
+ UvElement *element1 = state->uvs[edge->uv1];
+ UvElement *element2 = state->uvs[edge->uv2];
+
+ /* Now iterate through all faces and try to find edges sharing the same vertices */
+ UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
+ UvEdge *last_set = edge;
+ int elemindex2 = BM_elem_index_get(element2->l->v);
+
+ edge->first = edge;
+
+ for (; iter1; iter1 = iter1->next) {
+ UvElement *iter2 = NULL;
+
+ /* check to see if other vertex of edge belongs to same vertex as */
+ if (BM_elem_index_get(iter1->l->next->v) == elemindex2)
+ iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next);
+ else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2)
+ iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev);
+
+ if (iter2) {
+ int index1 = map[iter1 - first_element];
+ int index2 = map[iter2 - first_element];
+ UvEdge edgetmp;
+ UvEdge *edge2, *eiter;
+ bool valid = true;
+
+ /* make sure the indices are well behaved */
+ if (index1 > index2) {
+ SWAP(int, index1, index2);
+ }
+
+ edgetmp.uv1 = index1;
+ edgetmp.uv2 = index2;
+
+ /* get the edge from the hash */
+ edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
+
+ /* more iteration to make sure non-manifold case is handled nicely */
+ for (eiter = edge; eiter; eiter = eiter->next) {
+ if (edge2 == eiter) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ /* here I am taking care of non manifold case, assuming more than two matching edges.
+ * I am not too sure we want this though */
+ last_set->next = edge2;
+ last_set = edge2;
+ /* set first, similarly to uv elements.
+ * Now we can iterate among common edges easily */
+ edge2->first = edge;
+ }
+ }
+ }
+ }
+ else {
+ /* so stitchability code works */
+ edge->first = edge;
+ }
+ }
}
-
/* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
-static void determine_uv_stitchability(
- UvElement *element, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data)
+static void determine_uv_stitchability(UvElement *element,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data)
{
- int vert_index;
- UvElement *element_iter;
- BMLoop *l;
-
- l = element->l;
-
- vert_index = BM_elem_index_get(l->v);
- element_iter = state->element_map->vert[vert_index];
-
- for (; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate) {
- if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) {
- island_stitch_data[element_iter->island].stitchableCandidate = 1;
- island_stitch_data[element->island].stitchableCandidate = 1;
- element->flag |= STITCH_STITCHABLE_CANDIDATE;
- }
- }
- }
+ int vert_index;
+ UvElement *element_iter;
+ BMLoop *l;
+
+ l = element->l;
+
+ vert_index = BM_elem_index_get(l->v);
+ element_iter = state->element_map->vert[vert_index];
+
+ for (; element_iter; element_iter = element_iter->next) {
+ if (element_iter->separate) {
+ if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) {
+ island_stitch_data[element_iter->island].stitchableCandidate = 1;
+ island_stitch_data[element->island].stitchableCandidate = 1;
+ element->flag |= STITCH_STITCHABLE_CANDIDATE;
+ }
+ }
+ }
}
-static void determine_uv_edge_stitchability(
- UvEdge *edge, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data)
+static void determine_uv_edge_stitchability(UvEdge *edge,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data)
{
- UvEdge *edge_iter = edge->first;
-
- for (; edge_iter; edge_iter = edge_iter->next) {
- if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) {
- island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
- island_stitch_data[edge->element->island].stitchableCandidate = 1;
- edge->flag |= STITCH_STITCHABLE_CANDIDATE;
- }
- }
+ UvEdge *edge_iter = edge->first;
+
+ for (; edge_iter; edge_iter = edge_iter->next) {
+ if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) {
+ island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
+ island_stitch_data[edge->element->island].stitchableCandidate = 1;
+ edge->flag |= STITCH_STITCHABLE_CANDIDATE;
+ }
+ }
}
-
/* set preview buffer position of UV face in editface->tmp.l */
-static void stitch_set_face_preview_buffer_position(
- BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
+static void stitch_set_face_preview_buffer_position(BMFace *efa,
+ StitchPreviewer *preview,
+ PreviewPosition *preview_position)
{
- int index = BM_elem_index_get(efa);
+ int index = BM_elem_index_get(efa);
- if (preview_position[index].data_position == STITCH_NO_PREVIEW) {
- preview_position[index].data_position = preview->preview_uvs * 2;
- preview_position[index].polycount_position = preview->num_polys++;
- preview->preview_uvs += efa->len;
- }
+ if (preview_position[index].data_position == STITCH_NO_PREVIEW) {
+ preview_position[index].data_position = preview->preview_uvs * 2;
+ preview_position[index].polycount_position = preview->num_polys++;
+ preview->preview_uvs += efa->len;
+ }
}
-
/* setup face preview for all coincident uvs and their faces */
-static void stitch_setup_face_preview_for_uv_group(
- UvElement *element, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
+static void stitch_setup_face_preview_for_uv_group(UvElement *element,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
- StitchPreviewer *preview = state->stitch_preview;
+ StitchPreviewer *preview = state->stitch_preview;
- /* static island does not change so returning immediately */
- if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island)
- return;
+ /* static island does not change so returning immediately */
+ if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island)
+ return;
- if (ssc->snap_islands) {
- island_stitch_data[element->island].addedForPreview = 1;
- }
+ if (ssc->snap_islands) {
+ island_stitch_data[element->island].addedForPreview = 1;
+ }
- do {
- stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
- element = element->next;
- } while (element && !element->separate);
+ do {
+ stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
+ element = element->next;
+ } while (element && !element->separate);
}
-
/* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
-static void stitch_validate_uv_stitchability(
- UvElement *element, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
+static void stitch_validate_uv_stitchability(UvElement *element,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
- StitchPreviewer *preview = state->stitch_preview;
-
- /* If not the active object, then it's unstitchable */
- if (ssc->states[ssc->active_object_index] != state) {
- preview->num_unstitchable++;
- return;
- }
-
- UvElement *element_iter;
- int vert_index;
- BMLoop *l;
-
- l = element->l;
-
- vert_index = BM_elem_index_get(l->v);
-
- element_iter = state->element_map->vert[vert_index];
-
- for (; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate) {
- if (element_iter == element)
- continue;
- if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
- if ((element_iter->island == ssc->static_island) || (element->island == ssc->static_island)) {
- element->flag |= STITCH_STITCHABLE;
- preview->num_stitchable++;
- stitch_setup_face_preview_for_uv_group(element, ssc, state, island_stitch_data, preview_position);
- return;
- }
- }
- }
- }
-
- /* this can happen if the uvs to be stitched are not on a stitchable island */
- if (!(element->flag & STITCH_STITCHABLE)) {
- preview->num_unstitchable++;
- }
+ StitchPreviewer *preview = state->stitch_preview;
+
+ /* If not the active object, then it's unstitchable */
+ if (ssc->states[ssc->active_object_index] != state) {
+ preview->num_unstitchable++;
+ return;
+ }
+
+ UvElement *element_iter;
+ int vert_index;
+ BMLoop *l;
+
+ l = element->l;
+
+ vert_index = BM_elem_index_get(l->v);
+
+ element_iter = state->element_map->vert[vert_index];
+
+ for (; element_iter; element_iter = element_iter->next) {
+ if (element_iter->separate) {
+ if (element_iter == element)
+ continue;
+ if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
+ if ((element_iter->island == ssc->static_island) ||
+ (element->island == ssc->static_island)) {
+ element->flag |= STITCH_STITCHABLE;
+ preview->num_stitchable++;
+ stitch_setup_face_preview_for_uv_group(
+ element, ssc, state, island_stitch_data, preview_position);
+ return;
+ }
+ }
+ }
+ }
+
+ /* this can happen if the uvs to be stitched are not on a stitchable island */
+ if (!(element->flag & STITCH_STITCHABLE)) {
+ preview->num_unstitchable++;
+ }
}
-
-static void stitch_validate_edge_stitchability(
- UvEdge *edge, StitchStateContainer *ssc, StitchState *state,
- IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
+static void stitch_validate_edge_stitchability(UvEdge *edge,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
- StitchPreviewer *preview = state->stitch_preview;
-
- /* If not the active object, then it's unstitchable */
- if (ssc->states[ssc->active_object_index] != state) {
- preview->num_unstitchable++;
- return;
- }
-
- UvEdge *edge_iter = edge->first;
-
- for (; edge_iter; edge_iter = edge_iter->next) {
- if (edge_iter == edge)
- continue;
- if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
- if ((edge_iter->element->island == ssc->static_island) || (edge->element->island == ssc->static_island)) {
- edge->flag |= STITCH_STITCHABLE;
- preview->num_stitchable++;
- stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1],
- ssc,
- state,
- island_stitch_data,
- preview_position);
- stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2],
- ssc,
- state,
- island_stitch_data,
- preview_position);
- return;
- }
- }
- }
-
- /* this can happen if the uvs to be stitched are not on a stitchable island */
- if (!(edge->flag & STITCH_STITCHABLE)) {
- preview->num_unstitchable++;
- }
+ StitchPreviewer *preview = state->stitch_preview;
+
+ /* If not the active object, then it's unstitchable */
+ if (ssc->states[ssc->active_object_index] != state) {
+ preview->num_unstitchable++;
+ return;
+ }
+
+ UvEdge *edge_iter = edge->first;
+
+ for (; edge_iter; edge_iter = edge_iter->next) {
+ if (edge_iter == edge)
+ continue;
+ if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
+ if ((edge_iter->element->island == ssc->static_island) ||
+ (edge->element->island == ssc->static_island)) {
+ edge->flag |= STITCH_STITCHABLE;
+ preview->num_stitchable++;
+ stitch_setup_face_preview_for_uv_group(
+ state->uvs[edge->uv1], ssc, state, island_stitch_data, preview_position);
+ stitch_setup_face_preview_for_uv_group(
+ state->uvs[edge->uv2], ssc, state, island_stitch_data, preview_position);
+ return;
+ }
+ }
+ }
+
+ /* this can happen if the uvs to be stitched are not on a stitchable island */
+ if (!(edge->flag & STITCH_STITCHABLE)) {
+ preview->num_unstitchable++;
+ }
}
-
-static void stitch_propagate_uv_final_position(
- Scene *scene,
- UvElement *element, int index, PreviewPosition *preview_position,
- UVVertAverage *final_position, StitchStateContainer *ssc, StitchState *state,
- const bool final)
+static void stitch_propagate_uv_final_position(Scene *scene,
+ UvElement *element,
+ int index,
+ PreviewPosition *preview_position,
+ UVVertAverage *final_position,
+ StitchStateContainer *ssc,
+ StitchState *state,
+ const bool final)
{
- BMesh *bm = state->em->bm;
- StitchPreviewer *preview = state->stitch_preview;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (element->flag & STITCH_STITCHABLE) {
- UvElement *element_iter = element;
- /* propagate to coincident uvs */
- do {
- BMLoop *l;
- MLoopUV *luv;
-
- l = element_iter->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- element_iter->flag |= STITCH_PROCESSED;
- /* either flush to preview or to the MTFace, if final */
- if (final) {
- copy_v2_v2(luv->uv, final_position[index].uv);
-
- uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset);
- }
- else {
- int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
- if (face_preview_pos != STITCH_NO_PREVIEW) {
- copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->loop_of_poly_index,
- final_position[index].uv);
- }
- }
-
- /* end of calculations, keep only the selection flag */
- if ((!ssc->snap_islands) || ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) {
- element_iter->flag &= STITCH_SELECTED;
- }
-
- element_iter = element_iter->next;
- } while (element_iter && !element_iter->separate);
- }
+ BMesh *bm = state->em->bm;
+ StitchPreviewer *preview = state->stitch_preview;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ if (element->flag & STITCH_STITCHABLE) {
+ UvElement *element_iter = element;
+ /* propagate to coincident uvs */
+ do {
+ BMLoop *l;
+ MLoopUV *luv;
+
+ l = element_iter->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ element_iter->flag |= STITCH_PROCESSED;
+ /* either flush to preview or to the MTFace, if final */
+ if (final) {
+ copy_v2_v2(luv->uv, final_position[index].uv);
+
+ uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset);
+ }
+ else {
+ int face_preview_pos =
+ preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
+ if (face_preview_pos != STITCH_NO_PREVIEW) {
+ copy_v2_v2(preview->preview_polys + face_preview_pos +
+ 2 * element_iter->loop_of_poly_index,
+ final_position[index].uv);
+ }
+ }
+
+ /* end of calculations, keep only the selection flag */
+ if ((!ssc->snap_islands) ||
+ ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) {
+ element_iter->flag &= STITCH_SELECTED;
+ }
+
+ element_iter = element_iter->next;
+ } while (element_iter && !element_iter->separate);
+ }
}
/* main processing function. It calculates preview and final positions. */
-static int stitch_process_data(
- StitchStateContainer *ssc, StitchState *state, Scene *scene, int final)
+static int stitch_process_data(StitchStateContainer *ssc,
+ StitchState *state,
+ Scene *scene,
+ int final)
{
- int i;
- StitchPreviewer *preview;
- IslandStitchData *island_stitch_data = NULL;
- int previous_island = ssc->static_island;
- BMesh *bm = state->em->bm;
- BMFace *efa;
- BMIter iter;
- UVVertAverage *final_position = NULL;
- bool is_active_state = (state == ssc->states[ssc->active_object_index]);
-
- char stitch_midpoints = ssc->midpoints;
- /* used to map uv indices to uvaverage indices for selection */
- unsigned int *uvfinal_map = NULL;
- /* per face preview position in preview buffer */
- PreviewPosition *preview_position = NULL;
-
- /* cleanup previous preview */
- stitch_preview_delete(state->stitch_preview);
- preview = state->stitch_preview = stitch_preview_init();
- if (preview == NULL)
- return 0;
-
- preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), "stitch_face_preview_position");
- /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
- for (i = 0; i < bm->totface; i++) {
- preview_position[i].data_position = STITCH_NO_PREVIEW;
- }
-
- island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands,
- "stitch_island_data");
- if (!island_stitch_data) {
- return 0;
- }
-
- /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
-
- /****************************************
- * First determine stitchability of uvs *
- ****************************************/
-
- for (i = 0; i < state->selection_size; i++) {
- if (ssc->mode == STITCH_VERT) {
- UvElement *element = (UvElement *)state->selection_stack[i];
- determine_uv_stitchability(element, ssc, state, island_stitch_data);
- }
- else {
- UvEdge *edge = (UvEdge *)state->selection_stack[i];
- determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data);
- }
- }
-
- /* remember stitchable candidates as places the 'I' button */
- /* will stop at. */
- for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) {
- state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? true : false;
- }
-
- if (is_active_state) {
- /* set static island to one that is added for preview */
- ssc->static_island %= state->element_map->totalIslands;
- while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) {
- ssc->static_island++;
- ssc->static_island %= state->element_map->totalIslands;
- /* this is entirely possible if for example limit stitching
- * with no stitchable verts or no selection */
- if (ssc->static_island == previous_island) {
- break;
- }
- }
- }
-
- for (i = 0; i < state->selection_size; i++) {
- if (ssc->mode == STITCH_VERT) {
- UvElement *element = (UvElement *)state->selection_stack[i];
- if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
- element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_uv_stitchability(element, ssc, state, island_stitch_data, preview_position);
- }
- else {
- /* add to preview for unstitchable */
- preview->num_unstitchable++;
- }
- }
- else {
- UvEdge *edge = (UvEdge *)state->selection_stack[i];
- if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
- edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position);
- }
- else {
- preview->num_unstitchable++;
- }
- }
- }
-
- /*********************************************************************
- * Setup the stitchable & unstitchable preview buffers and fill *
- * them with the appropriate data *
- *********************************************************************/
- if (!final) {
- BMLoop *l;
- MLoopUV *luv;
- int stitchBufferIndex = 0, unstitchBufferIndex = 0;
- int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4;
- /* initialize the preview buffers */
- preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size,
- "stitch_preview_stitchable_data");
- preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size,
- "stitch_preview_unstitchable_data");
-
- /* will cause cancel and freeing of all data structures so OK */
- if (!preview->preview_stitchable || !preview->preview_unstitchable) {
- return 0;
- }
-
- /* fill the appropriate preview buffers */
- if (ssc->mode == STITCH_VERT) {
- for (i = 0; i < state->total_separate_uvs; i++) {
- UvElement *element = (UvElement *)state->uvs[i];
- if (element->flag & STITCH_STITCHABLE) {
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
-
- stitchBufferIndex++;
- }
- else if (element->flag & STITCH_SELECTED) {
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
- unstitchBufferIndex++;
- }
- }
- }
- else {
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = state->edges + i;
- UvElement *element1 = state->uvs[edge->uv1];
- UvElement *element2 = state->uvs[edge->uv2];
-
- if (edge->flag & STITCH_STITCHABLE) {
- l = element1->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
-
- l = element2->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
-
- stitchBufferIndex++;
- BLI_assert(stitchBufferIndex <= preview->num_stitchable);
- }
- else if (edge->flag & STITCH_SELECTED) {
- l = element1->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
-
- l = element2->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
-
- unstitchBufferIndex++;
- BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
- }
- }
- }
- }
-
- if (ssc->states[ssc->active_object_index] != state) {
- /* This is not the active object/state, exit here */
- MEM_freeN(island_stitch_data);
- MEM_freeN(preview_position);
- return 1;
- }
-
- /****************************************
- * Setup preview for stitchable islands *
- ****************************************/
- if (ssc->snap_islands) {
- for (i = 0; i < state->element_map->totalIslands; i++) {
- if (island_stitch_data[i].addedForPreview) {
- int numOfIslandUVs = 0, j;
- UvElement *element;
- numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
- element = &state->element_map->buf[state->element_map->islandIndices[i]];
- for (j = 0; j < numOfIslandUVs; j++, element++) {
- stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
- }
- }
- }
- }
-
- /*********************************************************************
- * Setup the remaining preview buffers and fill them with the *
- * appropriate data *
- *********************************************************************/
- if (!final) {
- BMIter liter;
- BMLoop *l;
- MLoopUV *luv;
- unsigned int buffer_index = 0;
-
- /* initialize the preview buffers */
- preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
- preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon),
- "tri_uv_stitch_prev");
-
- preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * 6,
- "static_island_preview_tris");
-
- preview->num_static_tris = state->tris_per_island[ssc->static_island];
- /* will cause cancel and freeing of all data structures so OK */
- if (!preview->preview_polys) {
- return 0;
- }
-
- /* copy data from MLoopUVs to the preview display buffers */
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* just to test if face was added for processing.
- * uvs of unselected vertices will return NULL */
- UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
-
- if (element) {
- int numoftris = efa->len - 2;
- int index = BM_elem_index_get(efa);
- int face_preview_pos = preview_position[index].data_position;
- if (face_preview_pos != STITCH_NO_PREVIEW) {
- preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv);
- }
- }
-
- /* if this is the static_island on the active object */
- if (element->island == ssc->static_island) {
- BMLoop *fl = BM_FACE_FIRST_LOOP(efa);
- MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- if (i < numoftris) {
- /* using next since the first uv is already accounted for */
- BMLoop *lnext = l->next;
- MLoopUV *luvnext = CustomData_bmesh_get(&bm->ldata, lnext->next->head.data, CD_MLOOPUV);
- luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV);
-
- memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float));
- memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float));
- memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float));
- buffer_index += 6;
- }
- else {
- break;
- }
- }
- }
- }
- }
- }
-
- /******************************************************
- * Here we calculate the final coordinates of the uvs *
- ******************************************************/
-
- if (ssc->mode == STITCH_VERT) {
- final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average");
- uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map");
- }
- else {
- final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), "stitch_uv_average");
- }
-
- /* first pass, calculate final position for stitchable uvs of the static island */
- for (i = 0; i < state->selection_size; i++) {
- if (ssc->mode == STITCH_VERT) {
- UvElement *element = state->selection_stack[i];
-
- if (element->flag & STITCH_STITCHABLE) {
- BMLoop *l;
- MLoopUV *luv;
- UvElement *element_iter;
-
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- uvfinal_map[element - state->element_map->buf] = i;
-
- copy_v2_v2(final_position[i].uv, luv->uv);
- final_position[i].count = 1;
-
- if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints)
- continue;
-
- element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
-
- for ( ; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate) {
- if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
- l = element_iter->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- if (stitch_midpoints) {
- add_v2_v2(final_position[i].uv, luv->uv);
- final_position[i].count++;
- }
- else if (element_iter->island == ssc->static_island) {
- /* if multiple uvs on the static island exist,
- * last checked remains. to disambiguate we need to limit or use
- * edge stitch */
- copy_v2_v2(final_position[i].uv, luv->uv);
- }
- }
- }
- }
- }
- if (stitch_midpoints) {
- final_position[i].uv[0] /= final_position[i].count;
- final_position[i].uv[1] /= final_position[i].count;
- }
- }
- else {
- UvEdge *edge = state->selection_stack[i];
-
- if (edge->flag & STITCH_STITCHABLE) {
- MLoopUV *luv2, *luv1;
- BMLoop *l;
- UvEdge *edge_iter;
-
- l = state->uvs[edge->uv1]->l;
- luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- l = state->uvs[edge->uv2]->l;
- luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
- copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
- final_position[edge->uv1].count = 1;
- final_position[edge->uv2].count = 1;
-
- state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
- state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
-
- if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints)
- continue;
-
- for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
- if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
- l = state->uvs[edge_iter->uv1]->l;
- luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- l = state->uvs[edge_iter->uv2]->l;
- luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- if (stitch_midpoints) {
- add_v2_v2(final_position[edge->uv1].uv, luv1->uv);
- final_position[edge->uv1].count++;
- add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
- final_position[edge->uv2].count++;
- }
- else if (edge_iter->element->island == ssc->static_island) {
- copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
- copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
- }
- }
- }
- }
- }
- }
-
- /* take mean position here.
- * For edge case, this can't be done inside the loop for shared uvverts */
- if (ssc->mode == STITCH_EDGE && stitch_midpoints) {
- for (i = 0; i < state->total_separate_uvs; i++) {
- final_position[i].uv[0] /= final_position[i].count;
- final_position[i].uv[1] /= final_position[i].count;
- }
- }
-
- /* second pass, calculate island rotation and translation before modifying any uvs */
- if (ssc->snap_islands) {
- if (ssc->mode == STITCH_VERT) {
- for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
-
- if (element->flag & STITCH_STITCHABLE) {
- BMLoop *l;
- MLoopUV *luv;
-
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- /* accumulate each islands' translation from stitchable elements. it is important to do here
- * because in final pass MTFaces get modified and result is zero. */
- island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
- island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
- island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
- island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
- island_stitch_data[element->island].numOfElements++;
- }
- }
-
- /* only calculate rotation when an edge has been fully selected */
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = state->edges + i;
- if ((edge->flag & STITCH_BOUNDARY) &&
- (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
- (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
- {
- stitch_island_calculate_edge_rotation(edge,
- ssc,
- state,
- final_position,
- uvfinal_map,
- island_stitch_data);
- island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
- }
- }
-
- /* clear seams of stitched edges */
- if (final && ssc->clear_seams) {
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = state->edges + i;
- if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
- (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
- {
- BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
- }
- }
- }
-
- for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
- if (!island_stitch_data[element->island].use_edge_rotation) {
- if (element->flag & STITCH_STITCHABLE) {
- stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data);
- }
- }
- }
- }
- else {
- for (i = 0; i < state->total_separate_uvs; i++) {
- UvElement *element = state->uvs[i];
-
- if (element->flag & STITCH_STITCHABLE) {
- BMLoop *l;
- MLoopUV *luv;
-
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- /* accumulate each islands' translation from stitchable elements. it is important to do here
- * because in final pass MTFaces get modified and result is zero. */
- island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
- island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
- island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
- island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
- island_stitch_data[element->island].numOfElements++;
- }
- }
-
- for (i = 0; i < state->selection_size; i++) {
- UvEdge *edge = state->selection_stack[i];
-
- if (edge->flag & STITCH_STITCHABLE) {
- stitch_island_calculate_edge_rotation(edge, ssc, state, final_position, NULL, island_stitch_data);
- island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
- }
- }
-
- /* clear seams of stitched edges */
- if (final && ssc->clear_seams) {
- for (i = 0; i < state->selection_size; i++) {
- UvEdge *edge = state->selection_stack[i];
- if (edge->flag & STITCH_STITCHABLE) {
- BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
- }
- }
- }
- }
- }
-
- /* third pass, propagate changes to coincident uvs */
- for (i = 0; i < state->selection_size; i++) {
- if (ssc->mode == STITCH_VERT) {
- UvElement *element = state->selection_stack[i];
-
- stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, ssc, state, final);
- }
- else {
- UvEdge *edge = state->selection_stack[i];
-
- stitch_propagate_uv_final_position(
- scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, ssc, state, final);
- stitch_propagate_uv_final_position(
- scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, ssc, state, final);
-
- edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
- }
- }
-
- /* final pass, calculate Island translation/rotation if needed */
- if (ssc->snap_islands) {
- stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final);
- }
-
- MEM_freeN(final_position);
- if (ssc->mode == STITCH_VERT) {
- MEM_freeN(uvfinal_map);
- }
- MEM_freeN(island_stitch_data);
- MEM_freeN(preview_position);
-
- return 1;
+ int i;
+ StitchPreviewer *preview;
+ IslandStitchData *island_stitch_data = NULL;
+ int previous_island = ssc->static_island;
+ BMesh *bm = state->em->bm;
+ BMFace *efa;
+ BMIter iter;
+ UVVertAverage *final_position = NULL;
+ bool is_active_state = (state == ssc->states[ssc->active_object_index]);
+
+ char stitch_midpoints = ssc->midpoints;
+ /* used to map uv indices to uvaverage indices for selection */
+ unsigned int *uvfinal_map = NULL;
+ /* per face preview position in preview buffer */
+ PreviewPosition *preview_position = NULL;
+
+ /* cleanup previous preview */
+ stitch_preview_delete(state->stitch_preview);
+ preview = state->stitch_preview = stitch_preview_init();
+ if (preview == NULL)
+ return 0;
+
+ preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position),
+ "stitch_face_preview_position");
+ /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
+ for (i = 0; i < bm->totface; i++) {
+ preview_position[i].data_position = STITCH_NO_PREVIEW;
+ }
+
+ island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands,
+ "stitch_island_data");
+ if (!island_stitch_data) {
+ return 0;
+ }
+
+ /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+
+ /****************************************
+ * First determine stitchability of uvs *
+ ****************************************/
+
+ for (i = 0; i < state->selection_size; i++) {
+ if (ssc->mode == STITCH_VERT) {
+ UvElement *element = (UvElement *)state->selection_stack[i];
+ determine_uv_stitchability(element, ssc, state, island_stitch_data);
+ }
+ else {
+ UvEdge *edge = (UvEdge *)state->selection_stack[i];
+ determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data);
+ }
+ }
+
+ /* remember stitchable candidates as places the 'I' button */
+ /* will stop at. */
+ for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) {
+ state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ?
+ true :
+ false;
+ }
+
+ if (is_active_state) {
+ /* set static island to one that is added for preview */
+ ssc->static_island %= state->element_map->totalIslands;
+ while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) {
+ ssc->static_island++;
+ ssc->static_island %= state->element_map->totalIslands;
+ /* this is entirely possible if for example limit stitching
+ * with no stitchable verts or no selection */
+ if (ssc->static_island == previous_island) {
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < state->selection_size; i++) {
+ if (ssc->mode == STITCH_VERT) {
+ UvElement *element = (UvElement *)state->selection_stack[i];
+ if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
+ element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+ stitch_validate_uv_stitchability(
+ element, ssc, state, island_stitch_data, preview_position);
+ }
+ else {
+ /* add to preview for unstitchable */
+ preview->num_unstitchable++;
+ }
+ }
+ else {
+ UvEdge *edge = (UvEdge *)state->selection_stack[i];
+ if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
+ edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+ stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position);
+ }
+ else {
+ preview->num_unstitchable++;
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Setup the stitchable & unstitchable preview buffers and fill *
+ * them with the appropriate data *
+ *********************************************************************/
+ if (!final) {
+ BMLoop *l;
+ MLoopUV *luv;
+ int stitchBufferIndex = 0, unstitchBufferIndex = 0;
+ int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4;
+ /* initialize the preview buffers */
+ preview->preview_stitchable = (float *)MEM_mallocN(
+ preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data");
+ preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable *
+ sizeof(float) * preview_size,
+ "stitch_preview_unstitchable_data");
+
+ /* will cause cancel and freeing of all data structures so OK */
+ if (!preview->preview_stitchable || !preview->preview_unstitchable) {
+ return 0;
+ }
+
+ /* fill the appropriate preview buffers */
+ if (ssc->mode == STITCH_VERT) {
+ for (i = 0; i < state->total_separate_uvs; i++) {
+ UvElement *element = (UvElement *)state->uvs[i];
+ if (element->flag & STITCH_STITCHABLE) {
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
+
+ stitchBufferIndex++;
+ }
+ else if (element->flag & STITCH_SELECTED) {
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
+ unstitchBufferIndex++;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = state->edges + i;
+ UvElement *element1 = state->uvs[edge->uv1];
+ UvElement *element2 = state->uvs[edge->uv2];
+
+ if (edge->flag & STITCH_STITCHABLE) {
+ l = element1->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
+
+ l = element2->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
+
+ stitchBufferIndex++;
+ BLI_assert(stitchBufferIndex <= preview->num_stitchable);
+ }
+ else if (edge->flag & STITCH_SELECTED) {
+ l = element1->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
+
+ l = element2->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
+
+ unstitchBufferIndex++;
+ BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
+ }
+ }
+ }
+ }
+
+ if (ssc->states[ssc->active_object_index] != state) {
+ /* This is not the active object/state, exit here */
+ MEM_freeN(island_stitch_data);
+ MEM_freeN(preview_position);
+ return 1;
+ }
+
+ /****************************************
+ * Setup preview for stitchable islands *
+ ****************************************/
+ if (ssc->snap_islands) {
+ for (i = 0; i < state->element_map->totalIslands; i++) {
+ if (island_stitch_data[i].addedForPreview) {
+ int numOfIslandUVs = 0, j;
+ UvElement *element;
+ numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
+ element = &state->element_map->buf[state->element_map->islandIndices[i]];
+ for (j = 0; j < numOfIslandUVs; j++, element++) {
+ stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
+ }
+ }
+ }
+ }
+
+ /*********************************************************************
+ * Setup the remaining preview buffers and fill them with the *
+ * appropriate data *
+ *********************************************************************/
+ if (!final) {
+ BMIter liter;
+ BMLoop *l;
+ MLoopUV *luv;
+ unsigned int buffer_index = 0;
+
+ /* initialize the preview buffers */
+ preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2,
+ "tri_uv_stitch_prev");
+ preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon),
+ "tri_uv_stitch_prev");
+
+ preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) *
+ 6,
+ "static_island_preview_tris");
+
+ preview->num_static_tris = state->tris_per_island[ssc->static_island];
+ /* will cause cancel and freeing of all data structures so OK */
+ if (!preview->preview_polys) {
+ return 0;
+ }
+
+ /* copy data from MLoopUVs to the preview display buffers */
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ /* just to test if face was added for processing.
+ * uvs of unselected vertices will return NULL */
+ UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
+
+ if (element) {
+ int numoftris = efa->len - 2;
+ int index = BM_elem_index_get(efa);
+ int face_preview_pos = preview_position[index].data_position;
+ if (face_preview_pos != STITCH_NO_PREVIEW) {
+ preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len;
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv);
+ }
+ }
+
+ /* if this is the static_island on the active object */
+ if (element->island == ssc->static_island) {
+ BMLoop *fl = BM_FACE_FIRST_LOOP(efa);
+ MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV);
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ if (i < numoftris) {
+ /* using next since the first uv is already accounted for */
+ BMLoop *lnext = l->next;
+ MLoopUV *luvnext = CustomData_bmesh_get(
+ &bm->ldata, lnext->next->head.data, CD_MLOOPUV);
+ luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV);
+
+ memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float));
+ memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float));
+ memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float));
+ buffer_index += 6;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /******************************************************
+ * Here we calculate the final coordinates of the uvs *
+ ******************************************************/
+
+ if (ssc->mode == STITCH_VERT) {
+ final_position = MEM_callocN(state->selection_size * sizeof(*final_position),
+ "stitch_uv_average");
+ uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map),
+ "stitch_uv_final_map");
+ }
+ else {
+ final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position),
+ "stitch_uv_average");
+ }
+
+ /* first pass, calculate final position for stitchable uvs of the static island */
+ for (i = 0; i < state->selection_size; i++) {
+ if (ssc->mode == STITCH_VERT) {
+ UvElement *element = state->selection_stack[i];
+
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
+ UvElement *element_iter;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ uvfinal_map[element - state->element_map->buf] = i;
+
+ copy_v2_v2(final_position[i].uv, luv->uv);
+ final_position[i].count = 1;
+
+ if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints)
+ continue;
+
+ element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+
+ for (; element_iter; element_iter = element_iter->next) {
+ if (element_iter->separate) {
+ if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
+ l = element_iter->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ if (stitch_midpoints) {
+ add_v2_v2(final_position[i].uv, luv->uv);
+ final_position[i].count++;
+ }
+ else if (element_iter->island == ssc->static_island) {
+ /* if multiple uvs on the static island exist,
+ * last checked remains. to disambiguate we need to limit or use
+ * edge stitch */
+ copy_v2_v2(final_position[i].uv, luv->uv);
+ }
+ }
+ }
+ }
+ }
+ if (stitch_midpoints) {
+ final_position[i].uv[0] /= final_position[i].count;
+ final_position[i].uv[1] /= final_position[i].count;
+ }
+ }
+ else {
+ UvEdge *edge = state->selection_stack[i];
+
+ if (edge->flag & STITCH_STITCHABLE) {
+ MLoopUV *luv2, *luv1;
+ BMLoop *l;
+ UvEdge *edge_iter;
+
+ l = state->uvs[edge->uv1]->l;
+ luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge->uv2]->l;
+ luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+ copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
+ final_position[edge->uv1].count = 1;
+ final_position[edge->uv2].count = 1;
+
+ state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
+ state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
+
+ if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints)
+ continue;
+
+ for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
+ if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
+ l = state->uvs[edge_iter->uv1]->l;
+ luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv2]->l;
+ luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (stitch_midpoints) {
+ add_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+ final_position[edge->uv1].count++;
+ add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
+ final_position[edge->uv2].count++;
+ }
+ else if (edge_iter->element->island == ssc->static_island) {
+ copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+ copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* take mean position here.
+ * For edge case, this can't be done inside the loop for shared uvverts */
+ if (ssc->mode == STITCH_EDGE && stitch_midpoints) {
+ for (i = 0; i < state->total_separate_uvs; i++) {
+ final_position[i].uv[0] /= final_position[i].count;
+ final_position[i].uv[1] /= final_position[i].count;
+ }
+ }
+
+ /* second pass, calculate island rotation and translation before modifying any uvs */
+ if (ssc->snap_islands) {
+ if (ssc->mode == STITCH_VERT) {
+ for (i = 0; i < state->selection_size; i++) {
+ UvElement *element = state->selection_stack[i];
+
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ /* accumulate each islands' translation from stitchable elements. it is important to do here
+ * because in final pass MTFaces get modified and result is zero. */
+ island_stitch_data[element->island].translation[0] += final_position[i].uv[0] -
+ luv->uv[0];
+ island_stitch_data[element->island].translation[1] += final_position[i].uv[1] -
+ luv->uv[1];
+ island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
+ island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
+ island_stitch_data[element->island].numOfElements++;
+ }
+ }
+
+ /* only calculate rotation when an edge has been fully selected */
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = state->edges + i;
+ if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
+ (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
+ stitch_island_calculate_edge_rotation(
+ edge, ssc, state, final_position, uvfinal_map, island_stitch_data);
+ island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
+ }
+ }
+
+ /* clear seams of stitched edges */
+ if (final && ssc->clear_seams) {
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = state->edges + i;
+ if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
+ (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
+ BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
+ }
+ }
+ }
+
+ for (i = 0; i < state->selection_size; i++) {
+ UvElement *element = state->selection_stack[i];
+ if (!island_stitch_data[element->island].use_edge_rotation) {
+ if (element->flag & STITCH_STITCHABLE) {
+ stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data);
+ }
+ }
+ }
+ }
+ else {
+ for (i = 0; i < state->total_separate_uvs; i++) {
+ UvElement *element = state->uvs[i];
+
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
+
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ /* accumulate each islands' translation from stitchable elements. it is important to do here
+ * because in final pass MTFaces get modified and result is zero. */
+ island_stitch_data[element->island].translation[0] += final_position[i].uv[0] -
+ luv->uv[0];
+ island_stitch_data[element->island].translation[1] += final_position[i].uv[1] -
+ luv->uv[1];
+ island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
+ island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
+ island_stitch_data[element->island].numOfElements++;
+ }
+ }
+
+ for (i = 0; i < state->selection_size; i++) {
+ UvEdge *edge = state->selection_stack[i];
+
+ if (edge->flag & STITCH_STITCHABLE) {
+ stitch_island_calculate_edge_rotation(
+ edge, ssc, state, final_position, NULL, island_stitch_data);
+ island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
+ }
+ }
+
+ /* clear seams of stitched edges */
+ if (final && ssc->clear_seams) {
+ for (i = 0; i < state->selection_size; i++) {
+ UvEdge *edge = state->selection_stack[i];
+ if (edge->flag & STITCH_STITCHABLE) {
+ BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
+ }
+ }
+ }
+ }
+ }
+
+ /* third pass, propagate changes to coincident uvs */
+ for (i = 0; i < state->selection_size; i++) {
+ if (ssc->mode == STITCH_VERT) {
+ UvElement *element = state->selection_stack[i];
+
+ stitch_propagate_uv_final_position(
+ scene, element, i, preview_position, final_position, ssc, state, final);
+ }
+ else {
+ UvEdge *edge = state->selection_stack[i];
+
+ stitch_propagate_uv_final_position(scene,
+ state->uvs[edge->uv1],
+ edge->uv1,
+ preview_position,
+ final_position,
+ ssc,
+ state,
+ final);
+ stitch_propagate_uv_final_position(scene,
+ state->uvs[edge->uv2],
+ edge->uv2,
+ preview_position,
+ final_position,
+ ssc,
+ state,
+ final);
+
+ edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
+ }
+ }
+
+ /* final pass, calculate Island translation/rotation if needed */
+ if (ssc->snap_islands) {
+ stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final);
+ }
+
+ MEM_freeN(final_position);
+ if (ssc->mode == STITCH_VERT) {
+ MEM_freeN(uvfinal_map);
+ }
+ MEM_freeN(island_stitch_data);
+ MEM_freeN(preview_position);
+
+ return 1;
}
static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int final)
{
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) {
- return 0;
- }
- }
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) {
+ return 0;
+ }
+ }
- return 1;
+ return 1;
}
/* Stitch hash initialization functions */
static unsigned int uv_edge_hash(const void *key)
{
- const UvEdge *edge = key;
- return (BLI_ghashutil_uinthash(edge->uv2) +
- BLI_ghashutil_uinthash(edge->uv1));
+ const UvEdge *edge = key;
+ return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
}
static bool uv_edge_compare(const void *a, const void *b)
{
- const UvEdge *edge1 = a;
- const UvEdge *edge2 = b;
+ const UvEdge *edge1 = a;
+ const UvEdge *edge2 = b;
- if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
- return 0;
- }
- return 1;
+ if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
+ return 0;
+ }
+ return 1;
}
/* select all common edges */
static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select)
{
- UvEdge *eiter;
- UvEdge **selection_stack = (UvEdge **)state->selection_stack;
-
- for (eiter = edge->first; eiter; eiter = eiter->next) {
- if (eiter->flag & STITCH_SELECTED) {
- int i;
- if (always_select)
- continue;
-
- eiter->flag &= ~STITCH_SELECTED;
- for (i = 0; i < state->selection_size; i++) {
- if (selection_stack[i] == eiter) {
- (state->selection_size)--;
- selection_stack[i] = selection_stack[state->selection_size];
- break;
- }
- }
- }
- else {
- eiter->flag |= STITCH_SELECTED;
- selection_stack[state->selection_size++] = eiter;
- }
- }
+ UvEdge *eiter;
+ UvEdge **selection_stack = (UvEdge **)state->selection_stack;
+
+ for (eiter = edge->first; eiter; eiter = eiter->next) {
+ if (eiter->flag & STITCH_SELECTED) {
+ int i;
+ if (always_select)
+ continue;
+
+ eiter->flag &= ~STITCH_SELECTED;
+ for (i = 0; i < state->selection_size; i++) {
+ if (selection_stack[i] == eiter) {
+ (state->selection_size)--;
+ selection_stack[i] = selection_stack[state->selection_size];
+ break;
+ }
+ }
+ }
+ else {
+ eiter->flag |= STITCH_SELECTED;
+ selection_stack[state->selection_size++] = eiter;
+ }
+ }
}
-
/* Select all common uvs */
static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
{
- BMLoop *l;
- UvElement *element_iter;
- UvElement **selection_stack = (UvElement **)state->selection_stack;
-
- l = element->l;
-
- element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
- /* first deselect all common uvs */
- for (; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate) {
- /* only separators go to selection */
- if (element_iter->flag & STITCH_SELECTED) {
- int i;
- if (always_select)
- continue;
-
- element_iter->flag &= ~STITCH_SELECTED;
- for (i = 0; i < state->selection_size; i++) {
- if (selection_stack[i] == element_iter) {
- (state->selection_size)--;
- selection_stack[i] = selection_stack[state->selection_size];
- break;
- }
- }
- }
- else {
- element_iter->flag |= STITCH_SELECTED;
- selection_stack[state->selection_size++] = element_iter;
- }
- }
- }
+ BMLoop *l;
+ UvElement *element_iter;
+ UvElement **selection_stack = (UvElement **)state->selection_stack;
+
+ l = element->l;
+
+ element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+ /* first deselect all common uvs */
+ for (; element_iter; element_iter = element_iter->next) {
+ if (element_iter->separate) {
+ /* only separators go to selection */
+ if (element_iter->flag & STITCH_SELECTED) {
+ int i;
+ if (always_select)
+ continue;
+
+ element_iter->flag &= ~STITCH_SELECTED;
+ for (i = 0; i < state->selection_size; i++) {
+ if (selection_stack[i] == element_iter) {
+ (state->selection_size)--;
+ selection_stack[i] = selection_stack[state->selection_size];
+ break;
+ }
+ }
+ }
+ else {
+ element_iter->flag |= STITCH_SELECTED;
+ selection_stack[state->selection_size++] = element_iter;
+ }
+ }
+ }
}
static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode)
{
- void **old_selection_stack = state->selection_stack;
- int old_selection_size = state->selection_size;
- state->selection_size = 0;
-
- if (from_stitch_mode == STITCH_VERT) {
- int i;
- state->selection_stack = MEM_mallocN(state->total_separate_edges * sizeof(*state->selection_stack),
- "stitch_new_edge_selection_stack");
-
- /* check if both elements of an edge are selected */
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = state->edges + i;
- UvElement *element1 = state->uvs[edge->uv1];
- UvElement *element2 = state->uvs[edge->uv2];
-
- if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED))
- stitch_select_edge(edge, state, true);
- }
-
- /* unselect selected uvelements */
- for (i = 0; i < old_selection_size; i++) {
- UvElement *element = old_selection_stack[i];
-
- element->flag &= ~STITCH_SELECTED;
- }
- }
- else {
- int i;
- state->selection_stack = MEM_mallocN(state->total_separate_uvs * sizeof(*state->selection_stack),
- "stitch_new_vert_selection_stack");
-
- for (i = 0; i < old_selection_size; i++) {
- UvEdge *edge = old_selection_stack[i];
- UvElement *element1 = state->uvs[edge->uv1];
- UvElement *element2 = state->uvs[edge->uv2];
-
- stitch_select_uv(element1, state, true);
- stitch_select_uv(element2, state, true);
-
- edge->flag &= ~STITCH_SELECTED;
- }
- }
- MEM_freeN(old_selection_stack);
+ void **old_selection_stack = state->selection_stack;
+ int old_selection_size = state->selection_size;
+ state->selection_size = 0;
+
+ if (from_stitch_mode == STITCH_VERT) {
+ int i;
+ state->selection_stack = MEM_mallocN(state->total_separate_edges *
+ sizeof(*state->selection_stack),
+ "stitch_new_edge_selection_stack");
+
+ /* check if both elements of an edge are selected */
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = state->edges + i;
+ UvElement *element1 = state->uvs[edge->uv1];
+ UvElement *element2 = state->uvs[edge->uv2];
+
+ if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED))
+ stitch_select_edge(edge, state, true);
+ }
+
+ /* unselect selected uvelements */
+ for (i = 0; i < old_selection_size; i++) {
+ UvElement *element = old_selection_stack[i];
+
+ element->flag &= ~STITCH_SELECTED;
+ }
+ }
+ else {
+ int i;
+ state->selection_stack = MEM_mallocN(state->total_separate_uvs *
+ sizeof(*state->selection_stack),
+ "stitch_new_vert_selection_stack");
+
+ for (i = 0; i < old_selection_size; i++) {
+ UvEdge *edge = old_selection_stack[i];
+ UvElement *element1 = state->uvs[edge->uv1];
+ UvElement *element2 = state->uvs[edge->uv2];
+
+ stitch_select_uv(element1, state, true);
+ stitch_select_uv(element2, state, true);
+
+ edge->flag &= ~STITCH_SELECTED;
+ }
+ }
+ MEM_freeN(old_selection_stack);
}
static void stitch_switch_selection_mode_all(StitchStateContainer *ssc)
{
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- stitch_set_selection_mode(ssc->states[ob_index], ssc->mode);
- }
-
- if (ssc->mode == STITCH_VERT) {
- ssc->mode = STITCH_EDGE;
- }
- else {
- ssc->mode = STITCH_VERT;
- }
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ stitch_set_selection_mode(ssc->states[ob_index], ssc->mode);
+ }
+
+ if (ssc->mode == STITCH_VERT) {
+ ssc->mode = STITCH_EDGE;
+ }
+ else {
+ ssc->mode = STITCH_VERT;
+ }
}
-static void stitch_calculate_edge_normal(
- BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
+static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
{
- BMLoop *l1 = edge->element->l;
- MLoopUV *luv1, *luv2;
- float tangent[2];
+ BMLoop *l1 = edge->element->l;
+ MLoopUV *luv1, *luv2;
+ float tangent[2];
- luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
- luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
+ luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
+ luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
- sub_v2_v2v2(tangent, luv2->uv, luv1->uv);
+ sub_v2_v2v2(tangent, luv2->uv, luv1->uv);
- tangent[1] /= aspect;
+ tangent[1] /= aspect;
- normal[0] = tangent[1];
- normal[1] = -tangent[0];
+ normal[0] = tangent[1];
+ normal[1] = -tangent[0];
- normalize_v2(normal);
+ normalize_v2(normal);
}
/**
*/
static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4])
{
- GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_batch_uniform_4fv(batch, "color", col);
- GPU_batch_draw(batch);
- GPU_batch_discard(batch);
+ GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(batch, "color", col);
+ GPU_batch_draw(batch);
+ GPU_batch_discard(batch);
}
/* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
- StitchStateContainer *ssc = (StitchStateContainer *)arg;
-
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- int j, index = 0;
- unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
- StitchState *state = ssc->states[ob_index];
- StitchPreviewer *stitch_preview = state->stitch_preview;
- GPUVertBuf *vbo, *vbo_line;
- float col[4];
-
- static GPUVertFormat format = { 0 };
- static unsigned int pos_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-
- GPU_blend(true);
-
- /* Static Tris */
- if (stitch_preview->static_tris) {
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col);
- vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
- for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]);
- }
- stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
- }
-
- /* Preview Polys */
- if (stitch_preview->preview_polys) {
- for (int i = 0; i < stitch_preview->num_polys; i++)
- num_line += stitch_preview->uvs_per_polygon[i];
-
- num_tri = num_line - 2 * stitch_preview->num_polys;
-
- /* we need to convert the polys into triangles / lines */
- vbo = GPU_vertbuf_create_with_format(&format);
- vbo_line = GPU_vertbuf_create_with_format(&format);
-
- GPU_vertbuf_data_alloc(vbo, num_tri * 3);
- GPU_vertbuf_data_alloc(vbo_line, num_line * 2);
-
-
- for (int i = 0; i < stitch_preview->num_polys; i++) {
- BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3);
-
- /* Start line */
- GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
- GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
-
- for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
- GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
- GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
- GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
-
- GPU_vertbuf_attr_set(vbo_line,
- pos_id,
- line_idx++,
- &stitch_preview->preview_polys[index + (j + 0) * 2]);
- GPU_vertbuf_attr_set(vbo_line,
- pos_id,
- line_idx++,
- &stitch_preview->preview_polys[index + (j + 1) * 2]);
- }
-
- /* Closing line */
- GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
- /* j = uvs_per_polygon[i] - 1*/
- GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]);
-
- index += stitch_preview->uvs_per_polygon[i] * 2;
- }
-
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col);
- stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col);
- stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col);
- }
-
- GPU_blend(false);
-
- /* draw stitch vert/lines preview */
- if (ssc->mode == STITCH_VERT) {
- GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
-
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
- vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
- for (int i = 0; i < stitch_preview->num_stitchable; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
- }
- stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
-
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
- vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
- for (int i = 0; i < stitch_preview->num_unstitchable; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
- }
- stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
- }
- else {
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
- vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
- for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
- }
- stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
-
- UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
- vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
- for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) {
- GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
- }
- stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
- }
- }
+ StitchStateContainer *ssc = (StitchStateContainer *)arg;
+
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ int j, index = 0;
+ unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
+ StitchState *state = ssc->states[ob_index];
+ StitchPreviewer *stitch_preview = state->stitch_preview;
+ GPUVertBuf *vbo, *vbo_line;
+ float col[4];
+
+ static GPUVertFormat format = {0};
+ static unsigned int pos_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPU_blend(true);
+
+ /* Static Tris */
+ if (stitch_preview->static_tris) {
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
+ for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
+ }
+
+ /* Preview Polys */
+ if (stitch_preview->preview_polys) {
+ for (int i = 0; i < stitch_preview->num_polys; i++)
+ num_line += stitch_preview->uvs_per_polygon[i];
+
+ num_tri = num_line - 2 * stitch_preview->num_polys;
+
+ /* we need to convert the polys into triangles / lines */
+ vbo = GPU_vertbuf_create_with_format(&format);
+ vbo_line = GPU_vertbuf_create_with_format(&format);
+
+ GPU_vertbuf_data_alloc(vbo, num_tri * 3);
+ GPU_vertbuf_data_alloc(vbo_line, num_line * 2);
+
+ for (int i = 0; i < stitch_preview->num_polys; i++) {
+ BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3);
+
+ /* Start line */
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ GPU_vertbuf_attr_set(
+ vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
+
+ for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
+ GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
+ GPU_vertbuf_attr_set(
+ vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
+ GPU_vertbuf_attr_set(
+ vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
+
+ GPU_vertbuf_attr_set(
+ vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
+ GPU_vertbuf_attr_set(
+ vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
+ }
+
+ /* Closing line */
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ /* j = uvs_per_polygon[i] - 1*/
+ GPU_vertbuf_attr_set(
+ vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]);
+
+ index += stitch_preview->uvs_per_polygon[i] * 2;
+ }
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col);
+ stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col);
+ stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col);
+ }
+
+ GPU_blend(false);
+
+ /* draw stitch vert/lines preview */
+ if (ssc->mode == STITCH_VERT) {
+ GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
+ for (int i = 0; i < stitch_preview->num_stitchable; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
+ for (int i = 0; i < stitch_preview->num_unstitchable; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
+ for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
+ for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
+ }
+ }
}
static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
{
- UvEdge tmp_edge;
+ UvEdge tmp_edge;
- UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l);
- UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next);
+ UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l);
+ UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next);
- int uv1 = state->map[element1 - state->element_map->buf];
- int uv2 = state->map[element2 - state->element_map->buf];
+ int uv1 = state->map[element1 - state->element_map->buf];
+ int uv2 = state->map[element2 - state->element_map->buf];
- if (uv1 < uv2) {
- tmp_edge.uv1 = uv1;
- tmp_edge.uv2 = uv2;
- }
- else {
- tmp_edge.uv1 = uv2;
- tmp_edge.uv2 = uv1;
- }
+ if (uv1 < uv2) {
+ tmp_edge.uv1 = uv1;
+ tmp_edge.uv2 = uv2;
+ }
+ else {
+ tmp_edge.uv1 = uv2;
+ tmp_edge.uv2 = uv1;
+ }
- return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
+ return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
}
-static StitchState *stitch_init(
- bContext *C, wmOperator *op,
- StitchStateContainer *ssc, Object *obedit, StitchStateInit *state_init)
+static StitchState *stitch_init(bContext *C,
+ wmOperator *op,
+ StitchStateContainer *ssc,
+ Object *obedit,
+ StitchStateInit *state_init)
{
- /* for fast edge lookup... */
- GHash *edge_hash;
- /* ...and actual edge storage */
- UvEdge *edges;
- int total_edges;
- /* maps uvelements to their first coincident uv */
- int *map;
- int counter = 0, i;
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- GHashIterator gh_iter;
- UvEdge *all_edges;
- StitchState *state;
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- float aspx, aspy;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- state = MEM_callocN(sizeof(StitchState), "stitch state obj");
-
- /* initialize state */
- state->obedit = obedit;
- state->em = em;
-
- /* in uv synch selection, all uv's are visible */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
- }
- else {
- state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
- }
- if (!state->element_map) {
- state_delete(state);
- return NULL;
- }
-
- ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
- state->aspect = aspx / aspy;
-
- /* Count 'unique' uvs */
- for (i = 0; i < state->element_map->totalUVs; i++) {
- if (state->element_map->buf[i].separate) {
- counter++;
- }
- }
-
- /* explicitly set preview to NULL,
- * to avoid deleting an invalid pointer on stitch_process_data */
- state->stitch_preview = NULL;
- /* Allocate the unique uv buffers */
- state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
- /* internal uvs need no normals but it is hard and slow to keep a map of
- * normals only for boundary uvs, so allocating for all uvs */
- state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
- state->total_separate_uvs = counter;
- state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map");
- /* Allocate the edge stack */
- edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
- all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges");
-
- if (!state->uvs || !map || !edge_hash || !all_edges) {
- state_delete(state);
- return NULL;
- }
-
- /* So that we can use this as index for the UvElements */
- counter = -1;
- /* initialize the unique UVs and map */
- for (i = 0; i < em->bm->totvert; i++) {
- UvElement *element = state->element_map->vert[i];
- for (; element; element = element->next) {
- if (element->separate) {
- counter++;
- state->uvs[counter] = element;
- }
- /* pointer arithmetic to the rescue, as always :)*/
- map[element - state->element_map->buf] = counter;
- }
- }
-
- counter = 0;
- /* Now, on to generate our uv connectivity data */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
- ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
- {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- UvElement *element = BM_uv_element_get(state->element_map, efa, l);
- int offset1, itmp1 = element - state->element_map->buf;
- int offset2, itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf;
- UvEdge *edge;
-
- offset1 = map[itmp1];
- offset2 = map[itmp2];
-
- all_edges[counter].next = NULL;
- all_edges[counter].first = NULL;
- all_edges[counter].flag = 0;
- all_edges[counter].element = element;
- /* using an order policy, sort uvs according to address space. This avoids
- * Having two different UvEdges with the same uvs on different positions */
- if (offset1 < offset2) {
- all_edges[counter].uv1 = offset1;
- all_edges[counter].uv2 = offset2;
- }
- else {
- all_edges[counter].uv1 = offset2;
- all_edges[counter].uv2 = offset1;
- }
-
- edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
- if (edge) {
- edge->flag = 0;
- }
- else {
- BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
- all_edges[counter].flag = STITCH_BOUNDARY;
- }
- counter++;
- }
- }
-
- total_edges = BLI_ghash_len(edge_hash);
- state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
-
- /* I assume any system will be able to at least allocate an iterator :p */
- if (!edges) {
- state_delete(state);
- return NULL;
- }
-
- state->total_separate_edges = total_edges;
-
- /* fill the edges with data */
- i = 0;
- GHASH_ITER (gh_iter, edge_hash) {
- edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
- }
-
- /* cleanup temporary stuff */
- MEM_freeN(all_edges);
-
- BLI_ghash_free(edge_hash, NULL, NULL);
-
- /* refill an edge hash to create edge connnectivity data */
- state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
- for (i = 0; i < total_edges; i++) {
- BLI_ghash_insert(edge_hash, edges + i, edges + i);
- }
- stitch_uv_edge_generate_linked_edges(edge_hash, state);
-
- /***** calculate 2D normals for boundary uvs *****/
-
- /* we use boundary edges to calculate 2D normals.
- * to disambiguate the direction of the normal, we also need
- * a point "inside" the island, that can be provided by
- * the winding of the polygon (assuming counter-clockwise flow). */
-
- for (i = 0; i < total_edges; i++) {
- UvEdge *edge = edges + i;
- float normal[2];
- if (edge->flag & STITCH_BOUNDARY) {
- stitch_calculate_edge_normal(em, edge, normal, state->aspect);
-
- add_v2_v2(state->normals + edge->uv1 * 2, normal);
- add_v2_v2(state->normals + edge->uv2 * 2, normal);
-
- normalize_v2(state->normals + edge->uv1 * 2);
- normalize_v2(state->normals + edge->uv2 * 2);
- }
- }
-
-
- /***** fill selection stack *******/
-
- state->selection_size = 0;
-
- /* Load old selection if redoing operator with different settings */
- if (state_init != NULL) {
- int faceIndex, elementIndex;
- UvElement *element;
- enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
-
- int selected_count = state_init->uv_selected_count;
-
- if (stored_mode == STITCH_VERT) {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs,
- "uv_stitch_selection_stack");
-
- while (selected_count--) {
- faceIndex = state_init->to_select[selected_count].faceIndex;
- elementIndex = state_init->to_select[selected_count].elementIndex;
- efa = BM_face_at_index(em->bm, faceIndex);
- element = BM_uv_element_get(state->element_map,
- efa,
- BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
- stitch_select_uv(element, state, 1);
- }
- }
- else {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges,
- "uv_stitch_selection_stack");
-
- while (selected_count--) {
- UvEdge tmp_edge, *edge;
- int uv1, uv2;
- faceIndex = state_init->to_select[selected_count].faceIndex;
- elementIndex = state_init->to_select[selected_count].elementIndex;
- efa = BM_face_at_index(em->bm, faceIndex);
- element = BM_uv_element_get(state->element_map,
- efa,
- BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
- uv1 = map[element - state->element_map->buf];
-
- element = BM_uv_element_get(state->element_map,
- efa,
- BM_iter_at_index(NULL,
- BM_LOOPS_OF_FACE,
- efa,
- (elementIndex + 1) % efa->len));
- uv2 = map[element - state->element_map->buf];
-
- if (uv1 < uv2) {
- tmp_edge.uv1 = uv1;
- tmp_edge.uv2 = uv2;
- }
- else {
- tmp_edge.uv1 = uv2;
- tmp_edge.uv2 = uv1;
- }
-
- edge = BLI_ghash_lookup(edge_hash, &tmp_edge);
-
- stitch_select_edge(edge, state, true);
- }
- }
- /* if user has switched the operator mode after operation, we need to convert
- * the stored format */
- if (ssc->mode != stored_mode) {
- stitch_set_selection_mode(state, stored_mode);
- }
- }
- else {
- if (ssc->mode == STITCH_VERT) {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs,
- "uv_stitch_selection_stack");
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- UvElement *element = BM_uv_element_get(state->element_map, efa, l);
- if (element) {
- stitch_select_uv(element, state, 1);
- }
- }
- }
- }
- }
- else {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges,
- "uv_stitch_selection_stack");
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
- ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
- {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
- UvEdge *edge = uv_edge_get(l, state);
- if (edge) {
- stitch_select_edge(edge, state, true);
- }
- }
- }
- }
- }
- }
-
- /***** initialize static island preview data *****/
-
- state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island) * state->element_map->totalIslands,
- "stitch island tris");
- for (i = 0; i < state->element_map->totalIslands; i++) {
- state->tris_per_island[i] = 0;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
-
- if (element) {
- state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0;
- }
- }
-
- state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, "stitch I stops");
- if (!state->island_is_stitchable) {
- state_delete(state);
- return NULL;
- }
-
- if (!stitch_process_data(ssc, state, scene, false)) {
- state_delete(state);
- return NULL;
- }
-
- return state;
+ /* for fast edge lookup... */
+ GHash *edge_hash;
+ /* ...and actual edge storage */
+ UvEdge *edges;
+ int total_edges;
+ /* maps uvelements to their first coincident uv */
+ int *map;
+ int counter = 0, i;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ GHashIterator gh_iter;
+ UvEdge *all_edges;
+ StitchState *state;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ float aspx, aspy;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ state = MEM_callocN(sizeof(StitchState), "stitch state obj");
+
+ /* initialize state */
+ state->obedit = obedit;
+ state->em = em;
+
+ /* in uv synch selection, all uv's are visible */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
+ }
+ else {
+ state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
+ }
+ if (!state->element_map) {
+ state_delete(state);
+ return NULL;
+ }
+
+ ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
+ state->aspect = aspx / aspy;
+
+ /* Count 'unique' uvs */
+ for (i = 0; i < state->element_map->totalUVs; i++) {
+ if (state->element_map->buf[i].separate) {
+ counter++;
+ }
+ }
+
+ /* explicitly set preview to NULL,
+ * to avoid deleting an invalid pointer on stitch_process_data */
+ state->stitch_preview = NULL;
+ /* Allocate the unique uv buffers */
+ state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
+ /* internal uvs need no normals but it is hard and slow to keep a map of
+ * normals only for boundary uvs, so allocating for all uvs */
+ state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
+ state->total_separate_uvs = counter;
+ state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs,
+ "uv_stitch_unique_map");
+ /* Allocate the edge stack */
+ edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+ all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges");
+
+ if (!state->uvs || !map || !edge_hash || !all_edges) {
+ state_delete(state);
+ return NULL;
+ }
+
+ /* So that we can use this as index for the UvElements */
+ counter = -1;
+ /* initialize the unique UVs and map */
+ for (i = 0; i < em->bm->totvert; i++) {
+ UvElement *element = state->element_map->vert[i];
+ for (; element; element = element->next) {
+ if (element->separate) {
+ counter++;
+ state->uvs[counter] = element;
+ }
+ /* pointer arithmetic to the rescue, as always :)*/
+ map[element - state->element_map->buf] = counter;
+ }
+ }
+
+ counter = 0;
+ /* Now, on to generate our uv connectivity data */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
+ ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ UvElement *element = BM_uv_element_get(state->element_map, efa, l);
+ int offset1, itmp1 = element - state->element_map->buf;
+ int offset2,
+ itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf;
+ UvEdge *edge;
+
+ offset1 = map[itmp1];
+ offset2 = map[itmp2];
+
+ all_edges[counter].next = NULL;
+ all_edges[counter].first = NULL;
+ all_edges[counter].flag = 0;
+ all_edges[counter].element = element;
+ /* using an order policy, sort uvs according to address space. This avoids
+ * Having two different UvEdges with the same uvs on different positions */
+ if (offset1 < offset2) {
+ all_edges[counter].uv1 = offset1;
+ all_edges[counter].uv2 = offset2;
+ }
+ else {
+ all_edges[counter].uv1 = offset2;
+ all_edges[counter].uv2 = offset1;
+ }
+
+ edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
+ if (edge) {
+ edge->flag = 0;
+ }
+ else {
+ BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
+ all_edges[counter].flag = STITCH_BOUNDARY;
+ }
+ counter++;
+ }
+ }
+
+ total_edges = BLI_ghash_len(edge_hash);
+ state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
+
+ /* I assume any system will be able to at least allocate an iterator :p */
+ if (!edges) {
+ state_delete(state);
+ return NULL;
+ }
+
+ state->total_separate_edges = total_edges;
+
+ /* fill the edges with data */
+ i = 0;
+ GHASH_ITER (gh_iter, edge_hash) {
+ edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
+ }
+
+ /* cleanup temporary stuff */
+ MEM_freeN(all_edges);
+
+ BLI_ghash_free(edge_hash, NULL, NULL);
+
+ /* refill an edge hash to create edge connnectivity data */
+ state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+ for (i = 0; i < total_edges; i++) {
+ BLI_ghash_insert(edge_hash, edges + i, edges + i);
+ }
+ stitch_uv_edge_generate_linked_edges(edge_hash, state);
+
+ /***** calculate 2D normals for boundary uvs *****/
+
+ /* we use boundary edges to calculate 2D normals.
+ * to disambiguate the direction of the normal, we also need
+ * a point "inside" the island, that can be provided by
+ * the winding of the polygon (assuming counter-clockwise flow). */
+
+ for (i = 0; i < total_edges; i++) {
+ UvEdge *edge = edges + i;
+ float normal[2];
+ if (edge->flag & STITCH_BOUNDARY) {
+ stitch_calculate_edge_normal(em, edge, normal, state->aspect);
+
+ add_v2_v2(state->normals + edge->uv1 * 2, normal);
+ add_v2_v2(state->normals + edge->uv2 * 2, normal);
+
+ normalize_v2(state->normals + edge->uv1 * 2);
+ normalize_v2(state->normals + edge->uv2 * 2);
+ }
+ }
+
+ /***** fill selection stack *******/
+
+ state->selection_size = 0;
+
+ /* Load old selection if redoing operator with different settings */
+ if (state_init != NULL) {
+ int faceIndex, elementIndex;
+ UvElement *element;
+ enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+
+ int selected_count = state_init->uv_selected_count;
+
+ if (stored_mode == STITCH_VERT) {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
+ state->total_separate_uvs,
+ "uv_stitch_selection_stack");
+
+ while (selected_count--) {
+ faceIndex = state_init->to_select[selected_count].faceIndex;
+ elementIndex = state_init->to_select[selected_count].elementIndex;
+ efa = BM_face_at_index(em->bm, faceIndex);
+ element = BM_uv_element_get(
+ state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+ stitch_select_uv(element, state, 1);
+ }
+ }
+ else {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
+ state->total_separate_edges,
+ "uv_stitch_selection_stack");
+
+ while (selected_count--) {
+ UvEdge tmp_edge, *edge;
+ int uv1, uv2;
+ faceIndex = state_init->to_select[selected_count].faceIndex;
+ elementIndex = state_init->to_select[selected_count].elementIndex;
+ efa = BM_face_at_index(em->bm, faceIndex);
+ element = BM_uv_element_get(
+ state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+ uv1 = map[element - state->element_map->buf];
+
+ element = BM_uv_element_get(
+ state->element_map,
+ efa,
+ BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len));
+ uv2 = map[element - state->element_map->buf];
+
+ if (uv1 < uv2) {
+ tmp_edge.uv1 = uv1;
+ tmp_edge.uv2 = uv2;
+ }
+ else {
+ tmp_edge.uv1 = uv2;
+ tmp_edge.uv2 = uv1;
+ }
+
+ edge = BLI_ghash_lookup(edge_hash, &tmp_edge);
+
+ stitch_select_edge(edge, state, true);
+ }
+ }
+ /* if user has switched the operator mode after operation, we need to convert
+ * the stored format */
+ if (ssc->mode != stored_mode) {
+ stitch_set_selection_mode(state, stored_mode);
+ }
+ }
+ else {
+ if (ssc->mode == STITCH_VERT) {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
+ state->total_separate_uvs,
+ "uv_stitch_selection_stack");
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ UvElement *element = BM_uv_element_get(state->element_map, efa, l);
+ if (element) {
+ stitch_select_uv(element, state, 1);
+ }
+ }
+ }
+ }
+ }
+ else {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
+ state->total_separate_edges,
+ "uv_stitch_selection_stack");
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
+ !BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ UvEdge *edge = uv_edge_get(l, state);
+ if (edge) {
+ stitch_select_edge(edge, state, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /***** initialize static island preview data *****/
+
+ state->tris_per_island = MEM_mallocN(
+ sizeof(*state->tris_per_island) * state->element_map->totalIslands, "stitch island tris");
+ for (i = 0; i < state->element_map->totalIslands; i++) {
+ state->tris_per_island[i] = 0;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
+
+ if (element) {
+ state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0;
+ }
+ }
+
+ state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands,
+ "stitch I stops");
+ if (!state->island_is_stitchable) {
+ state_delete(state);
+ return NULL;
+ }
+
+ if (!stitch_process_data(ssc, state, scene, false)) {
+ state_delete(state);
+ return NULL;
+ }
+
+ return state;
}
static bool goto_next_island(StitchStateContainer *ssc)
{
- StitchState *active_state = ssc->states[ssc->active_object_index];
- StitchState *original_active_state = active_state;
-
- int original_island = ssc->static_island;
-
- do {
- ssc->static_island++;
- if (ssc->static_island >= active_state->element_map->totalIslands) {
- /* go to next object */
- ssc->active_object_index++;
- ssc->active_object_index %= ssc->objects_len;
-
- active_state = ssc->states[ssc->active_object_index];
- ssc->static_island = 0;
- }
-
- if (active_state->island_is_stitchable[ssc->static_island]) {
- /* We're at an island to make active */
- return true;
- }
- } while (!(active_state == original_active_state &&
- ssc->static_island == original_island));
-
- return false;
+ StitchState *active_state = ssc->states[ssc->active_object_index];
+ StitchState *original_active_state = active_state;
+
+ int original_island = ssc->static_island;
+
+ do {
+ ssc->static_island++;
+ if (ssc->static_island >= active_state->element_map->totalIslands) {
+ /* go to next object */
+ ssc->active_object_index++;
+ ssc->active_object_index %= ssc->objects_len;
+
+ active_state = ssc->states[ssc->active_object_index];
+ ssc->static_island = 0;
+ }
+
+ if (active_state->island_is_stitchable[ssc->static_island]) {
+ /* We're at an island to make active */
+ return true;
+ }
+ } while (!(active_state == original_active_state && ssc->static_island == original_island));
+
+ return false;
}
static int stitch_init_all(bContext *C, wmOperator *op)
{
- ARegion *ar = CTX_wm_region(C);
- if (!ar)
- return 0;
-
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
-
- StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection");
-
- op->customdata = ssc;
-
- ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit");
- ssc->limit_dist = RNA_float_get(op->ptr, "limit");
- ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
- ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
- ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
- ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index");
- ssc->static_island = 0;
-
- if (RNA_struct_property_is_set(op->ptr, "mode")) {
- ssc->mode = RNA_enum_get(op->ptr, "mode");
- }
- else {
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_VERTEX)
- ssc->mode = STITCH_VERT;
- else
- ssc->mode = STITCH_EDGE;
- }
- else {
- if (ts->uv_selectmode & UV_SELECT_VERTEX) {
- ssc->mode = STITCH_VERT;
- }
- else {
- ssc->mode = STITCH_EDGE;
- }
- }
- }
-
- ssc->objects_len = 0;
- ssc->states = NULL;
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, &objects_len);
-
- if (objects_len == 0) {
- MEM_freeN(objects);
- state_delete_all(ssc);
- return 0;
- }
-
- ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects");
- ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState");
- ssc->objects_len = 0;
-
- int *objs_selection_count = NULL;
- UvElementID *selected_uvs_arr = NULL;
- StitchStateInit *state_init = NULL;
-
- if (RNA_struct_property_is_set(op->ptr, "selection") &&
- RNA_struct_property_is_set(op->ptr, "objects_selection_count"))
- {
- /* Retrieve list of selected UVs, one list contains all selected UVs
- * for all objects. */
-
- objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count");
- RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count);
-
- int total_selected = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- total_selected += objs_selection_count[ob_index];
- }
-
- selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr");
- int sel_idx = 0;
- RNA_BEGIN (op->ptr, itemptr, "selection")
- {
- BLI_assert(sel_idx < total_selected);
- selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index");
- selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index");
- sel_idx++;
- }
- RNA_END;
-
- RNA_collection_clear(op->ptr, "selection");
-
- state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected");
- state_init->to_select = selected_uvs_arr;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
-
- if (state_init != NULL) {
- state_init->uv_selected_count = objs_selection_count[ob_index];
- }
-
- StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init);
-
- if (state_init != NULL) {
- /* Move pointer to beginning of next object's data. */
- state_init->to_select += state_init->uv_selected_count;
- }
-
- if (stitch_state_ob) {
- ssc->objects[ssc->objects_len] = obedit;
- ssc->states[ssc->objects_len] = stitch_state_ob;
- ssc->objects_len++;
- }
- }
-
- MEM_freeN(objects);
- MEM_SAFE_FREE(selected_uvs_arr);
- MEM_SAFE_FREE(objs_selection_count);
- MEM_SAFE_FREE(state_init);
-
- if (ssc->objects_len == 0) {
- state_delete_all(ssc);
- return 0;
- }
-
- ssc->active_object_index %= ssc->objects_len;
-
- ssc->static_island = RNA_int_get(op->ptr, "static_island");
-
- StitchState *state = ssc->states[ssc->active_object_index];
- ssc->static_island %= state->element_map->totalIslands;
-
- /* If the initial active object doesn't have any stitchable islands */
- /* then no active island will be seen in the UI. Make sure we're on */
- /* a stitchable object and island. */
- if (!state->island_is_stitchable[ssc->static_island]) {
- goto_next_island(ssc);
- state = ssc->states[ssc->active_object_index];
- }
-
- /* process active stitchobj again now that it can detect it's the active stitchobj */
- stitch_process_data(ssc, state, scene, false);
-
- stitch_update_header(ssc, C);
-
- ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW);
-
- return 1;
+ ARegion *ar = CTX_wm_region(C);
+ if (!ar)
+ return 0;
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection");
+
+ op->customdata = ssc;
+
+ ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit");
+ ssc->limit_dist = RNA_float_get(op->ptr, "limit");
+ ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
+ ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
+ ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
+ ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index");
+ ssc->static_island = 0;
+
+ if (RNA_struct_property_is_set(op->ptr, "mode")) {
+ ssc->mode = RNA_enum_get(op->ptr, "mode");
+ }
+ else {
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_VERTEX)
+ ssc->mode = STITCH_VERT;
+ else
+ ssc->mode = STITCH_EDGE;
+ }
+ else {
+ if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+ ssc->mode = STITCH_VERT;
+ }
+ else {
+ ssc->mode = STITCH_EDGE;
+ }
+ }
+ }
+
+ ssc->objects_len = 0;
+ ssc->states = NULL;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, v3d, &objects_len);
+
+ if (objects_len == 0) {
+ MEM_freeN(objects);
+ state_delete_all(ssc);
+ return 0;
+ }
+
+ ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects");
+ ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState");
+ ssc->objects_len = 0;
+
+ int *objs_selection_count = NULL;
+ UvElementID *selected_uvs_arr = NULL;
+ StitchStateInit *state_init = NULL;
+
+ if (RNA_struct_property_is_set(op->ptr, "selection") &&
+ RNA_struct_property_is_set(op->ptr, "objects_selection_count")) {
+ /* Retrieve list of selected UVs, one list contains all selected UVs
+ * for all objects. */
+
+ objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count");
+ RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count);
+
+ int total_selected = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ total_selected += objs_selection_count[ob_index];
+ }
+
+ selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr");
+ int sel_idx = 0;
+ RNA_BEGIN (op->ptr, itemptr, "selection") {
+ BLI_assert(sel_idx < total_selected);
+ selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index");
+ selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index");
+ sel_idx++;
+ }
+ RNA_END;
+
+ RNA_collection_clear(op->ptr, "selection");
+
+ state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected");
+ state_init->to_select = selected_uvs_arr;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ if (state_init != NULL) {
+ state_init->uv_selected_count = objs_selection_count[ob_index];
+ }
+
+ StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init);
+
+ if (state_init != NULL) {
+ /* Move pointer to beginning of next object's data. */
+ state_init->to_select += state_init->uv_selected_count;
+ }
+
+ if (stitch_state_ob) {
+ ssc->objects[ssc->objects_len] = obedit;
+ ssc->states[ssc->objects_len] = stitch_state_ob;
+ ssc->objects_len++;
+ }
+ }
+
+ MEM_freeN(objects);
+ MEM_SAFE_FREE(selected_uvs_arr);
+ MEM_SAFE_FREE(objs_selection_count);
+ MEM_SAFE_FREE(state_init);
+
+ if (ssc->objects_len == 0) {
+ state_delete_all(ssc);
+ return 0;
+ }
+
+ ssc->active_object_index %= ssc->objects_len;
+
+ ssc->static_island = RNA_int_get(op->ptr, "static_island");
+
+ StitchState *state = ssc->states[ssc->active_object_index];
+ ssc->static_island %= state->element_map->totalIslands;
+
+ /* If the initial active object doesn't have any stitchable islands */
+ /* then no active island will be seen in the UI. Make sure we're on */
+ /* a stitchable object and island. */
+ if (!state->island_is_stitchable[ssc->static_island]) {
+ goto_next_island(ssc);
+ state = ssc->states[ssc->active_object_index];
+ }
+
+ /* process active stitchobj again now that it can detect it's the active stitchobj */
+ stitch_process_data(ssc, state, scene, false);
+
+ stitch_update_header(ssc, C);
+
+ ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW);
+
+ return 1;
}
static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!stitch_init_all(C, op))
- return OPERATOR_CANCELLED;
+ if (!stitch_init_all(C, op))
+ return OPERATOR_CANCELLED;
- WM_event_add_modal_handler(C, op);
+ WM_event_add_modal_handler(C, op);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
+ StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- StitchState *state = ssc->states[ob_index];
- Object *obedit = state->obedit;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static void stitch_exit(bContext *C, wmOperator *op, int finished)
{
- Scene *scene = CTX_data_scene(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- ScrArea *sa = CTX_wm_area(C);
-
- StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
-
- if (finished) {
- RNA_float_set(op->ptr, "limit", ssc->limit_dist);
- RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit);
- RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands);
- RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints);
- RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams);
- RNA_enum_set(op->ptr, "mode", ssc->mode);
- RNA_enum_set(op->ptr, "stored_mode", ssc->mode);
- RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index);
-
- RNA_int_set(op->ptr, "static_island", ssc->static_island);
-
- int *objs_selection_count = NULL;
- objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, "objects_selection_count");
-
- /* Store selection for re-execution of stitch
- * - Store all selected UVs in "selection"
- * - Store how many each object has in "objects_selection_count". */
- RNA_collection_clear(op->ptr, "selection");
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- StitchState *state = ssc->states[ob_index];
- Object *obedit = state->obedit;
-
- PointerRNA itemptr;
- for (int i = 0; i < state->selection_size; i++) {
- UvElement *element;
-
- if (ssc->mode == STITCH_VERT) {
- element = state->selection_stack[i];
- }
- else {
- element = ((UvEdge *)state->selection_stack[i])->element;
- }
- RNA_collection_add(op->ptr, "selection", &itemptr);
-
- RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
- RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index);
- }
- uvedit_live_unwrap_update(sima, scene, obedit);
-
- objs_selection_count[ob_index] = state->selection_size;
- }
-
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count");
- RNA_def_property_array(prop, ssc->objects_len);
- RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count);
- MEM_freeN(objs_selection_count);
- }
-
- if (sa)
- ED_workspace_status_text(C, NULL);
-
- ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle);
-
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
-
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- StitchState *state = ssc->states[ob_index];
- Object *obedit = state->obedit;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- DEG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
-
- state_delete_all(ssc);
-
- op->customdata = NULL;
+ Scene *scene = CTX_data_scene(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
+
+ if (finished) {
+ RNA_float_set(op->ptr, "limit", ssc->limit_dist);
+ RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit);
+ RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands);
+ RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints);
+ RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams);
+ RNA_enum_set(op->ptr, "mode", ssc->mode);
+ RNA_enum_set(op->ptr, "stored_mode", ssc->mode);
+ RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index);
+
+ RNA_int_set(op->ptr, "static_island", ssc->static_island);
+
+ int *objs_selection_count = NULL;
+ objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len,
+ "objects_selection_count");
+
+ /* Store selection for re-execution of stitch
+ * - Store all selected UVs in "selection"
+ * - Store how many each object has in "objects_selection_count". */
+ RNA_collection_clear(op->ptr, "selection");
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+
+ PointerRNA itemptr;
+ for (int i = 0; i < state->selection_size; i++) {
+ UvElement *element;
+
+ if (ssc->mode == STITCH_VERT) {
+ element = state->selection_stack[i];
+ }
+ else {
+ element = ((UvEdge *)state->selection_stack[i])->element;
+ }
+ RNA_collection_add(op->ptr, "selection", &itemptr);
+
+ RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
+ RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index);
+ }
+ uvedit_live_unwrap_update(sima, scene, obedit);
+
+ objs_selection_count[ob_index] = state->selection_size;
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count");
+ RNA_def_property_array(prop, ssc->objects_len);
+ RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count);
+ MEM_freeN(objs_selection_count);
+ }
+
+ if (sa)
+ ED_workspace_status_text(C, NULL);
+
+ ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle);
+
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
+ state_delete_all(ssc);
+
+ op->customdata = NULL;
}
-
static void stitch_cancel(bContext *C, wmOperator *op)
{
- stitch_exit(C, op, 0);
+ stitch_exit(C, op, 0);
}
-
static int stitch_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
-
- if (!stitch_init_all(C, op))
- return OPERATOR_CANCELLED;
- if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) {
- stitch_exit(C, op, 1);
- return OPERATOR_FINISHED;
- }
- else {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ Scene *scene = CTX_data_scene(C);
+
+ if (!stitch_init_all(C, op))
+ return OPERATOR_CANCELLED;
+ if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) {
+ stitch_exit(C, op, 1);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
}
-static StitchState *stitch_select(
- bContext *C, Scene *scene, const wmEvent *event, StitchStateContainer *ssc)
+static StitchState *stitch_select(bContext *C,
+ Scene *scene,
+ const wmEvent *event,
+ StitchStateContainer *ssc)
{
- /* add uv under mouse to processed uv's */
- float co[2];
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- ARegion *ar = CTX_wm_region(C);
- Image *ima = CTX_data_edit_image(C);
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
-
- if (ssc->mode == STITCH_VERT) {
- if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
- /* Add vertex to selection, deselect all common uv's of vert other than selected and
- * update the preview. This behavior was decided so that you can do stuff like deselect
- * the opposite stitchable vertex and the initial still gets deselected */
-
- /* find StitchState from hit->ob */
- StitchState *state = NULL;
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- if (hit.ob == ssc->objects[ob_index]) {
- state = ssc->states[ob_index];
- break;
- }
- }
-
- /* This works due to setting of tmp in find nearest uv vert */
- UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l);
- stitch_select_uv(element, state, false);
-
- return state;
- }
- }
- else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
- /* find StitchState from hit->ob */
- StitchState *state = NULL;
- for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
- if (hit.ob == ssc->objects[ob_index]) {
- state = ssc->states[ob_index];
- break;
- }
- }
-
- UvEdge *edge = uv_edge_get(hit.l, state);
- stitch_select_edge(edge, state, false);
-
- return state;
- }
-
- return NULL;
+ /* add uv under mouse to processed uv's */
+ float co[2];
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ ARegion *ar = CTX_wm_region(C);
+ Image *ima = CTX_data_edit_image(C);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+
+ if (ssc->mode == STITCH_VERT) {
+ if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
+ /* Add vertex to selection, deselect all common uv's of vert other than selected and
+ * update the preview. This behavior was decided so that you can do stuff like deselect
+ * the opposite stitchable vertex and the initial still gets deselected */
+
+ /* find StitchState from hit->ob */
+ StitchState *state = NULL;
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (hit.ob == ssc->objects[ob_index]) {
+ state = ssc->states[ob_index];
+ break;
+ }
+ }
+
+ /* This works due to setting of tmp in find nearest uv vert */
+ UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l);
+ stitch_select_uv(element, state, false);
+
+ return state;
+ }
+ }
+ else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
+ /* find StitchState from hit->ob */
+ StitchState *state = NULL;
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (hit.ob == ssc->objects[ob_index]) {
+ state = ssc->states[ob_index];
+ break;
+ }
+ }
+
+ UvEdge *edge = uv_edge_get(hit.l, state);
+ stitch_select_edge(edge, state, false);
+
+ return state;
+ }
+
+ return NULL;
}
static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- StitchStateContainer *ssc;
- Scene *scene = CTX_data_scene(C);
-
- ssc = op->customdata;
- StitchState *active_state = ssc->states[ssc->active_object_index];
-
- switch (event->type) {
- case MIDDLEMOUSE:
- return OPERATOR_PASS_THROUGH;
-
- /* Cancel */
- case ESCKEY:
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
-
- case LEFTMOUSE:
- case PADENTER:
- case RETKEY:
- if (event->val == KM_PRESS) {
- if (stitch_process_data(ssc, active_state, scene, true)) {
- stitch_exit(C, op, 1);
- return OPERATOR_FINISHED;
- }
- else {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
- else {
- return OPERATOR_PASS_THROUGH;
- }
- /* Increase limit */
- case PADPLUSKEY:
- case WHEELUPMOUSE:
- if (event->val == KM_PRESS && event->alt) {
- ssc->limit_dist += 0.01f;
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- }
- else {
- return OPERATOR_PASS_THROUGH;
- }
- /* Decrease limit */
- case PADMINUS:
- case WHEELDOWNMOUSE:
- if (event->val == KM_PRESS && event->alt) {
- ssc->limit_dist -= 0.01f;
- ssc->limit_dist = MAX2(0.01f, ssc->limit_dist);
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- }
- else {
- return OPERATOR_PASS_THROUGH;
- }
-
- /* Use Limit (Default off) */
- case LKEY:
- if (event->val == KM_PRESS) {
- ssc->use_limit = !ssc->use_limit;
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- }
- return OPERATOR_RUNNING_MODAL;
-
- case IKEY:
- if (event->val == KM_PRESS) {
- /* Move to next island and maybe next object */
-
- if (goto_next_island(ssc)) {
- StitchState *new_active_state = ssc->states[ssc->active_object_index];
-
- /* active_state is the original active state */
- if (active_state != new_active_state) {
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
-
- if (!stitch_process_data(ssc, new_active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
- break;
- }
- return OPERATOR_RUNNING_MODAL;
-
- case MKEY:
- if (event->val == KM_PRESS) {
- ssc->midpoints = !ssc->midpoints;
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
- break;
-
- /* Select geometry */
- case RIGHTMOUSE:
- if (!event->shift) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- if (event->val == KM_PRESS) {
- StitchState *selected_state = stitch_select(C, scene, event, ssc);
-
- if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- }
- return OPERATOR_RUNNING_MODAL;
-
- /* snap islands on/off */
- case SKEY:
- if (event->val == KM_PRESS) {
- ssc->snap_islands = !ssc->snap_islands;
- if (!stitch_process_data(ssc, active_state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- }
- else {
- return OPERATOR_RUNNING_MODAL;
- }
-
- /* switch between edge/vertex mode */
- case TABKEY:
- if (event->val == KM_PRESS) {
- stitch_switch_selection_mode_all(ssc);
-
- if (!stitch_process_data_all(ssc, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
- break;
-
- default:
- return OPERATOR_RUNNING_MODAL;
- }
-
- /* if updated settings, renew feedback message */
- stitch_update_header(ssc, C);
- ED_region_tag_redraw(CTX_wm_region(C));
-
- return OPERATOR_RUNNING_MODAL;
+ StitchStateContainer *ssc;
+ Scene *scene = CTX_data_scene(C);
+
+ ssc = op->customdata;
+ StitchState *active_state = ssc->states[ssc->active_object_index];
+
+ switch (event->type) {
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Cancel */
+ case ESCKEY:
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+
+ case LEFTMOUSE:
+ case PADENTER:
+ case RETKEY:
+ if (event->val == KM_PRESS) {
+ if (stitch_process_data(ssc, active_state, scene, true)) {
+ stitch_exit(C, op, 1);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+ /* Increase limit */
+ case PADPLUSKEY:
+ case WHEELUPMOUSE:
+ if (event->val == KM_PRESS && event->alt) {
+ ssc->limit_dist += 0.01f;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+ /* Decrease limit */
+ case PADMINUS:
+ case WHEELDOWNMOUSE:
+ if (event->val == KM_PRESS && event->alt) {
+ ssc->limit_dist -= 0.01f;
+ ssc->limit_dist = MAX2(0.01f, ssc->limit_dist);
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ /* Use Limit (Default off) */
+ case LKEY:
+ if (event->val == KM_PRESS) {
+ ssc->use_limit = !ssc->use_limit;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ return OPERATOR_RUNNING_MODAL;
+
+ case IKEY:
+ if (event->val == KM_PRESS) {
+ /* Move to next island and maybe next object */
+
+ if (goto_next_island(ssc)) {
+ StitchState *new_active_state = ssc->states[ssc->active_object_index];
+
+ /* active_state is the original active state */
+ if (active_state != new_active_state) {
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!stitch_process_data(ssc, new_active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ break;
+ }
+ return OPERATOR_RUNNING_MODAL;
+
+ case MKEY:
+ if (event->val == KM_PRESS) {
+ ssc->midpoints = !ssc->midpoints;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ break;
+
+ /* Select geometry */
+ case RIGHTMOUSE:
+ if (!event->shift) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ if (event->val == KM_PRESS) {
+ StitchState *selected_state = stitch_select(C, scene, event, ssc);
+
+ if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ return OPERATOR_RUNNING_MODAL;
+
+ /* snap islands on/off */
+ case SKEY:
+ if (event->val == KM_PRESS) {
+ ssc->snap_islands = !ssc->snap_islands;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ else {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* switch between edge/vertex mode */
+ case TABKEY:
+ if (event->val == KM_PRESS) {
+ stitch_switch_selection_mode_all(ssc);
+
+ if (!stitch_process_data_all(ssc, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ break;
+
+ default:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* if updated settings, renew feedback message */
+ stitch_update_header(ssc, C);
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ return OPERATOR_RUNNING_MODAL;
}
void UV_OT_stitch(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- static const EnumPropertyItem stitch_modes[] = {
- {STITCH_VERT, "VERTEX", 0, "Vertex", ""},
- {STITCH_EDGE, "EDGE", 0, "Edge", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Stitch";
- ot->description = "Stitch selected UV vertices by proximity";
- ot->idname = "UV_OT_stitch";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = stitch_invoke;
- ot->modal = stitch_modal;
- ot->exec = stitch_exec;
- ot->cancel = stitch_cancel;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance");
- RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands",
- "Snap islands together (on edge stitch mode, rotates the islands too)");
-
- RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit",
- "Limit distance in normalized coordinates", 0.0, FLT_MAX);
- RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island",
- "Island that stays in place when stitching islands", 0, INT_MAX);
- RNA_def_int(ot->srna, "active_object_index", 0, 0, INT_MAX, "Active Object",
- "Index of the active object", 0, INT_MAX);
- RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint",
- "UVs are stitched at midpoint instead of at static island");
- RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams",
- "Clear seams of stitched edges");
- RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode",
- "Use vertex or edge stitching");
- prop = RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode",
- "Use vertex or edge stitching");
- RNA_def_property_flag(prop, PROP_HIDDEN);
- prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
- /* Selection should not be editable or viewed in toolbar */
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- /* test should not be editable or viewed in toolbar */
- prop = RNA_def_int_array(ot->srna, "objects_selection_count", 1, NULL, 0, INT_MAX, "Objects Selection Count",
- "", 0, INT_MAX);
- RNA_def_property_array(prop, 6);
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem stitch_modes[] = {
+ {STITCH_VERT, "VERTEX", 0, "Vertex", ""},
+ {STITCH_EDGE, "EDGE", 0, "Edge", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Stitch";
+ ot->description = "Stitch selected UV vertices by proximity";
+ ot->idname = "UV_OT_stitch";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = stitch_invoke;
+ ot->modal = stitch_modal;
+ ot->exec = stitch_exec;
+ ot->cancel = stitch_cancel;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance");
+ RNA_def_boolean(ot->srna,
+ "snap_islands",
+ 1,
+ "Snap Islands",
+ "Snap islands together (on edge stitch mode, rotates the islands too)");
+
+ RNA_def_float(ot->srna,
+ "limit",
+ 0.01f,
+ 0.0f,
+ FLT_MAX,
+ "Limit",
+ "Limit distance in normalized coordinates",
+ 0.0,
+ FLT_MAX);
+ RNA_def_int(ot->srna,
+ "static_island",
+ 0,
+ 0,
+ INT_MAX,
+ "Static Island",
+ "Island that stays in place when stitching islands",
+ 0,
+ INT_MAX);
+ RNA_def_int(ot->srna,
+ "active_object_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Active Object",
+ "Index of the active object",
+ 0,
+ INT_MAX);
+ RNA_def_boolean(ot->srna,
+ "midpoint_snap",
+ 0,
+ "Snap At Midpoint",
+ "UVs are stitched at midpoint instead of at static island");
+ RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges");
+ RNA_def_enum(ot->srna,
+ "mode",
+ stitch_modes,
+ STITCH_VERT,
+ "Operation Mode",
+ "Use vertex or edge stitching");
+ prop = RNA_def_enum(ot->srna,
+ "stored_mode",
+ stitch_modes,
+ STITCH_VERT,
+ "Stored Operation Mode",
+ "Use vertex or edge stitching");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_collection_runtime(
+ ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
+ /* Selection should not be editable or viewed in toolbar */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* test should not be editable or viewed in toolbar */
+ prop = RNA_def_int_array(ot->srna,
+ "objects_selection_count",
+ 1,
+ NULL,
+ 0,
+ INT_MAX,
+ "Objects Selection Count",
+ "",
+ 0,
+ INT_MAX);
+ RNA_def_property_array(prop, 6);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 19925c2fcd7..0caa478ffa9 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -21,7 +21,6 @@
* \ingroup eduv
*/
-
#include <string.h>
#include <stdlib.h>
#include <math.h>
@@ -70,7 +69,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -79,1333 +77,1432 @@
static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
{
- ModifierData *md;
- bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
+ ModifierData *md;
+ bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
- md = obedit->modifiers.first;
+ md = obedit->modifiers.first;
- /* subsurf will take the modifier settings only if modifier is first or right after mirror */
- if (subsurf) {
- if (md && md->type == eModifierType_Subsurf)
- subsurf = true;
- else
- subsurf = false;
- }
+ /* subsurf will take the modifier settings only if modifier is first or right after mirror */
+ if (subsurf) {
+ if (md && md->type == eModifierType_Subsurf)
+ subsurf = true;
+ else
+ subsurf = false;
+ }
- *r_use_subsurf = subsurf;
+ *r_use_subsurf = subsurf;
}
static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
- Image *ima;
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *slink;
- SpaceImage *sima;
- int cd_loop_uv_offset;
-
- if (ED_uvedit_test(obedit))
- return 1;
-
- if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
- ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
-
- if (!ED_uvedit_test(obedit))
- return 0;
-
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- ima = CTX_data_edit_image(C);
-
- if (!ima) {
- /* no image in context in the 3d view, we find first image window .. */
- sc = CTX_wm_screen(C);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- slink = sa->spacedata.first;
- if (slink->spacetype == SPACE_IMAGE) {
- sima = (SpaceImage *)slink;
-
- ima = sima->image;
- if (ima) {
- if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)
- ima = NULL;
- else
- break;
- }
- }
- }
- }
-
- /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMIter liter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
- }
-
- return 1;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
+ Image *ima;
+ bScreen *sc;
+ ScrArea *sa;
+ SpaceLink *slink;
+ SpaceImage *sima;
+ int cd_loop_uv_offset;
+
+ if (ED_uvedit_test(obedit))
+ return 1;
+
+ if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
+ ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
+
+ if (!ED_uvedit_test(obedit))
+ return 0;
+
+ cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ ima = CTX_data_edit_image(C);
+
+ if (!ima) {
+ /* no image in context in the 3d view, we find first image window .. */
+ sc = CTX_wm_screen(C);
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ slink = sa->spacedata.first;
+ if (slink->spacetype == SPACE_IMAGE) {
+ sima = (SpaceImage *)slink;
+
+ ima = sima->image;
+ if (ima) {
+ if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)
+ ima = NULL;
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+
+ return 1;
}
/****************** Parametrizer Conversion ***************/
typedef struct UnwrapOptions {
- bool topology_from_uvs; /* Connectivity based on UV coordinates instead of seams. */
- bool only_selected; /* Only affect selected faces. */
- bool fill_holes; /* Fill holes to better preserve shape. */
- bool correct_aspect; /* Correct for mapped image texture aspect ratio. */
+ bool topology_from_uvs; /* Connectivity based on UV coordinates instead of seams. */
+ bool only_selected; /* Only affect selected faces. */
+ bool fill_holes; /* Fill holes to better preserve shape. */
+ bool correct_aspect; /* Correct for mapped image texture aspect ratio. */
} UnwrapOptions;
static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (cd_loop_uv_offset == -1) {
- return (em->bm->totfacesel != 0);
- }
-
- /* verify if we have any selected uv's before unwrapping,
- * so we can cancel the operator early */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
- continue;
- }
- else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- break;
- }
-
- if (options->topology_from_uvs && !l)
- continue;
-
- return true;
- }
-
- return false;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (cd_loop_uv_offset == -1) {
+ return (em->bm->totfacesel != 0);
+ }
+
+ /* verify if we have any selected uv's before unwrapping,
+ * so we can cancel the operator early */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ continue;
+ }
+ else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ break;
+ }
+
+ if (options->topology_from_uvs && !l)
+ continue;
+
+ return true;
+ }
+
+ return false;
}
-static bool uvedit_have_selection_multi(
- Scene *scene, Object **objects, const uint objects_len,
- const UnwrapOptions *options)
+static bool uvedit_have_selection_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const UnwrapOptions *options)
{
- bool have_select = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (uvedit_have_selection(scene, em, options)) {
- have_select = true;
- break;
- }
- }
- return have_select;
+ bool have_select = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (uvedit_have_selection(scene, em, options)) {
+ have_select = true;
+ break;
+ }
+ }
+ return have_select;
}
void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
{
- bool sloppy = true;
- bool selected = false;
- BMFace *efa;
- Image *ima;
-
- efa = BM_mesh_active_face_get(bm, sloppy, selected);
-
- if (efa) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
-
- ED_image_get_uv_aspect(ima, NULL, aspx, aspy);
- }
- else {
- *aspx = 1.0f;
- *aspy = 1.0f;
- }
+ bool sloppy = true;
+ bool selected = false;
+ BMFace *efa;
+ Image *ima;
+
+ efa = BM_mesh_active_face_get(bm, sloppy, selected);
+
+ if (efa) {
+ ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
+
+ ED_image_get_uv_aspect(ima, NULL, aspx, aspy);
+ }
+ else {
+ *aspx = 1.0f;
+ *aspy = 1.0f;
+ }
}
-static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
- BMFace *efa, int face_index, const int cd_loop_uv_offset)
+static void construct_param_handle_face_add(
+ ParamHandle *handle, Scene *scene, BMFace *efa, int face_index, const int cd_loop_uv_offset)
{
- ParamKey key;
- ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
- ParamBool *pin = BLI_array_alloca(pin, efa->len);
- ParamBool *select = BLI_array_alloca(select, efa->len);
- float **co = BLI_array_alloca(co, efa->len);
- float **uv = BLI_array_alloca(uv, efa->len);
- int i;
-
- BMIter liter;
- BMLoop *l;
-
- key = (ParamKey)face_index;
-
- /* let parametrizer split the ngon, it can make better decisions
- * about which split is best for unwrapping than scanfill */
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
- co[i] = l->v->co;
- uv[i] = luv->uv;
- pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
- select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- }
-
- param_face_add(handle, key, i, vkeys, co, uv, pin, select);
+ ParamKey key;
+ ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
+ ParamBool *pin = BLI_array_alloca(pin, efa->len);
+ ParamBool *select = BLI_array_alloca(select, efa->len);
+ float **co = BLI_array_alloca(co, efa->len);
+ float **uv = BLI_array_alloca(uv, efa->len);
+ int i;
+
+ BMIter liter;
+ BMLoop *l;
+
+ key = (ParamKey)face_index;
+
+ /* let parametrizer split the ngon, it can make better decisions
+ * about which split is best for unwrapping than scanfill */
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
+ co[i] = l->v->co;
+ uv[i] = luv->uv;
+ pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
+ select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ }
+
+ param_face_add(handle, key, i, vkeys, co, uv, pin, select);
}
/* See: construct_param_handle_multi to handle multiple objects at once. */
-static ParamHandle *construct_param_handle(
- Scene *scene, Object *ob, BMesh *bm,
- const UnwrapOptions *options)
+static ParamHandle *construct_param_handle(Scene *scene,
+ Object *ob,
+ BMesh *bm,
+ const UnwrapOptions *options)
{
- ParamHandle *handle;
- BMFace *efa;
- BMLoop *l;
- BMEdge *eed;
- BMIter iter, liter;
- int i;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- handle = param_construct_begin();
-
- if (options->correct_aspect) {
- float aspx, aspy;
-
- ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
-
- if (aspx != aspy)
- param_aspect_ratio(handle, aspx, aspy);
- }
-
- /* we need the vert indices */
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
- (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0))
- {
- continue;
- }
-
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- is_loopsel = true;
- break;
- }
- }
- if (is_loopsel == false) {
- continue;
- }
- }
-
- construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
- }
-
- if (!options->topology_from_uvs) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- param_edge_set_seam(handle, vkeys);
- }
- }
- }
-
- param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
-
- return handle;
+ ParamHandle *handle;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMIter iter, liter;
+ int i;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ handle = param_construct_begin();
+
+ if (options->correct_aspect) {
+ float aspx, aspy;
+
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+
+ if (aspx != aspy)
+ param_aspect_ratio(handle, aspx, aspy);
+ }
+
+ /* we need the vert indices */
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+
+ if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
+ (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ continue;
+ }
+
+ if (options->topology_from_uvs) {
+ bool is_loopsel = false;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ is_loopsel = true;
+ break;
+ }
+ }
+ if (is_loopsel == false) {
+ continue;
+ }
+ }
+
+ construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
+ }
+
+ if (!options->topology_from_uvs) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
+ vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+ }
+
+ param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
+
+ return handle;
}
/**
* Version of #construct_param_handle_single that handles multiple objects.
*/
-static ParamHandle *construct_param_handle_multi(
- Scene *scene, Object **objects, const uint objects_len,
- const UnwrapOptions *options)
+static ParamHandle *construct_param_handle_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const UnwrapOptions *options)
{
- ParamHandle *handle;
- BMFace *efa;
- BMLoop *l;
- BMEdge *eed;
- BMIter iter, liter;
- int i;
-
- handle = param_construct_begin();
-
- if (options->correct_aspect) {
- Object *ob = objects[0];
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMesh *bm = em->bm;
- float aspx, aspy;
-
- ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
- if (aspx != aspy) {
- param_aspect_ratio(handle, aspx, aspy);
- }
- }
-
- /* we need the vert indices */
- EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
-
- int offset = 0;
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
- (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0))
- {
- continue;
- }
-
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- is_loopsel = true;
- break;
- }
- }
- if (is_loopsel == false) {
- continue;
- }
- }
-
- construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
- }
-
- if (!options->topology_from_uvs) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- param_edge_set_seam(handle, vkeys);
- }
- }
- }
- offset += bm->totface;
- }
-
- param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
-
- return handle;
+ ParamHandle *handle;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMIter iter, liter;
+ int i;
+
+ handle = param_construct_begin();
+
+ if (options->correct_aspect) {
+ Object *ob = objects[0];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ float aspx, aspy;
+
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ if (aspx != aspy) {
+ param_aspect_ratio(handle, aspx, aspy);
+ }
+ }
+
+ /* we need the vert indices */
+ EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
+
+ int offset = 0;
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+
+ if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
+ (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ continue;
+ }
+
+ if (options->topology_from_uvs) {
+ bool is_loopsel = false;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ is_loopsel = true;
+ break;
+ }
+ }
+ if (is_loopsel == false) {
+ continue;
+ }
+ }
+
+ construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
+ }
+
+ if (!options->topology_from_uvs) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
+ vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+ }
+ offset += bm->totface;
+ }
+
+ param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
+
+ return handle;
}
-
-static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select,
- Scene *scene, const int cd_loop_uv_offset)
+static void texface_from_original_index(BMFace *efa,
+ int index,
+ float **uv,
+ ParamBool *pin,
+ ParamBool *select,
+ Scene *scene,
+ const int cd_loop_uv_offset)
{
- BMLoop *l;
- BMIter liter;
- MLoopUV *luv;
-
- *uv = NULL;
- *pin = 0;
- *select = 1;
-
- if (index == ORIGINDEX_NONE)
- return;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_index_get(l->v) == index) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- *uv = luv->uv;
- *pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
- *select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- break;
- }
- }
+ BMLoop *l;
+ BMIter liter;
+ MLoopUV *luv;
+
+ *uv = NULL;
+ *pin = 0;
+ *select = 1;
+
+ if (index == ORIGINDEX_NONE)
+ return;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_index_get(l->v) == index) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ *uv = luv->uv;
+ *pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
+ *select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ break;
+ }
+ }
}
/* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
* work justified the existence of a new function. */
-static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, BMEditMesh *em, const UnwrapOptions *options)
+static ParamHandle *construct_param_handle_subsurfed(Scene *scene,
+ Object *ob,
+ BMEditMesh *em,
+ const UnwrapOptions *options)
{
- ParamHandle *handle;
- /* index pointers */
- MPoly *mpoly;
- MLoop *mloop;
- MEdge *edge;
- int i;
-
- /* pointers to modifier data for unwrap control */
- ModifierData *md;
- SubsurfModifierData *smd_real;
- /* modifier initialization data, will control what type of subdivision will happen*/
- SubsurfModifierData smd = {{NULL}};
- /* Used to hold subsurfed Mesh */
- DerivedMesh *derivedMesh, *initialDerived;
- /* holds original indices for subsurfed mesh */
- const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
- /* Holds vertices of subsurfed mesh */
- MVert *subsurfedVerts;
- MEdge *subsurfedEdges;
- MPoly *subsurfedPolys;
- MLoop *subsurfedLoops;
- /* number of vertices and faces for subsurfed mesh*/
- int numOfEdges, numOfFaces;
-
- /* holds a map to editfaces for every subsurfed MFace.
- * These will be used to get hidden/ selected flags etc. */
- BMFace **faceMap;
- /* similar to the above, we need a way to map edges to their original ones */
- BMEdge **edgeMap;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- handle = param_construct_begin();
-
- if (options->correct_aspect) {
- float aspx, aspy;
-
- ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
-
- if (aspx != aspy)
- param_aspect_ratio(handle, aspx, aspy);
- }
-
- /* number of subdivisions to perform */
- md = ob->modifiers.first;
- smd_real = (SubsurfModifierData *)md;
-
- smd.levels = smd_real->levels;
- smd.subdivType = smd_real->subdivType;
-
- initialDerived = CDDM_from_editbmesh(em, false, false);
- derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, scene,
- NULL, SUBSURF_IN_EDIT_MODE);
-
- initialDerived->release(initialDerived);
-
- /* get the derived data */
- subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
- subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
- subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
- subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
-
- origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
- origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
- origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
-
- numOfEdges = derivedMesh->getNumEdges(derivedMesh);
- numOfFaces = derivedMesh->getNumPolys(derivedMesh);
-
- faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_FACE);
-
- /* map subsurfed faces to original editFaces */
- for (i = 0; i < numOfFaces; i++)
- faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
-
- edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
-
- /* map subsurfed edges to original editEdges */
- for (i = 0; i < numOfEdges; i++) {
- /* not all edges correspond to an old edge */
- edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ?
- BM_edge_at_index(em->bm, origEdgeIndices[i]) : NULL;
- }
-
- /* Prepare and feed faces to the solver */
- for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
- ParamKey key, vkeys[4];
- ParamBool pin[4], select[4];
- float *co[4];
- float *uv[4];
- BMFace *origFace = faceMap[i];
-
- if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
- if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
- continue;
- }
- else {
- if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) ||
- (options->only_selected && !BM_elem_flag_test(origFace, BM_ELEM_SELECT)))
- {
- continue;
- }
- }
-
- mloop = &subsurfedLoops[mpoly->loopstart];
-
- /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
- BLI_assert(mpoly->totloop == 4);
- key = (ParamKey)i;
- vkeys[0] = (ParamKey)mloop[0].v;
- vkeys[1] = (ParamKey)mloop[1].v;
- vkeys[2] = (ParamKey)mloop[2].v;
- vkeys[3] = (ParamKey)mloop[3].v;
-
- co[0] = subsurfedVerts[mloop[0].v].co;
- co[1] = subsurfedVerts[mloop[1].v].co;
- co[2] = subsurfedVerts[mloop[2].v].co;
- co[3] = subsurfedVerts[mloop[3].v].co;
-
- /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
- * flushing the solution to the edit mesh. */
- texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
-
- param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
- }
-
- /* these are calculated from original mesh too */
- for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
- if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)edge->v1;
- vkeys[1] = (ParamKey)edge->v2;
- param_edge_set_seam(handle, vkeys);
- }
- }
-
- param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
-
- /* cleanup */
- MEM_freeN(faceMap);
- MEM_freeN(edgeMap);
- derivedMesh->release(derivedMesh);
-
- return handle;
+ ParamHandle *handle;
+ /* index pointers */
+ MPoly *mpoly;
+ MLoop *mloop;
+ MEdge *edge;
+ int i;
+
+ /* pointers to modifier data for unwrap control */
+ ModifierData *md;
+ SubsurfModifierData *smd_real;
+ /* modifier initialization data, will control what type of subdivision will happen*/
+ SubsurfModifierData smd = {{NULL}};
+ /* Used to hold subsurfed Mesh */
+ DerivedMesh *derivedMesh, *initialDerived;
+ /* holds original indices for subsurfed mesh */
+ const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
+ /* Holds vertices of subsurfed mesh */
+ MVert *subsurfedVerts;
+ MEdge *subsurfedEdges;
+ MPoly *subsurfedPolys;
+ MLoop *subsurfedLoops;
+ /* number of vertices and faces for subsurfed mesh*/
+ int numOfEdges, numOfFaces;
+
+ /* holds a map to editfaces for every subsurfed MFace.
+ * These will be used to get hidden/ selected flags etc. */
+ BMFace **faceMap;
+ /* similar to the above, we need a way to map edges to their original ones */
+ BMEdge **edgeMap;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ handle = param_construct_begin();
+
+ if (options->correct_aspect) {
+ float aspx, aspy;
+
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
+
+ if (aspx != aspy)
+ param_aspect_ratio(handle, aspx, aspy);
+ }
+
+ /* number of subdivisions to perform */
+ md = ob->modifiers.first;
+ smd_real = (SubsurfModifierData *)md;
+
+ smd.levels = smd_real->levels;
+ smd.subdivType = smd_real->subdivType;
+
+ initialDerived = CDDM_from_editbmesh(em, false, false);
+ derivedMesh = subsurf_make_derived_from_derived(
+ initialDerived, &smd, scene, NULL, SUBSURF_IN_EDIT_MODE);
+
+ initialDerived->release(initialDerived);
+
+ /* get the derived data */
+ subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
+ subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
+ subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
+ subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
+
+ origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
+ origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
+ origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
+
+ numOfEdges = derivedMesh->getNumEdges(derivedMesh);
+ numOfFaces = derivedMesh->getNumPolys(derivedMesh);
+
+ faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_FACE);
+
+ /* map subsurfed faces to original editFaces */
+ for (i = 0; i < numOfFaces; i++)
+ faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
+
+ edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
+
+ /* map subsurfed edges to original editEdges */
+ for (i = 0; i < numOfEdges; i++) {
+ /* not all edges correspond to an old edge */
+ edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ?
+ BM_edge_at_index(em->bm, origEdgeIndices[i]) :
+ NULL;
+ }
+
+ /* Prepare and feed faces to the solver */
+ for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
+ ParamKey key, vkeys[4];
+ ParamBool pin[4], select[4];
+ float *co[4];
+ float *uv[4];
+ BMFace *origFace = faceMap[i];
+
+ if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+ if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
+ continue;
+ }
+ else {
+ if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) ||
+ (options->only_selected && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) {
+ continue;
+ }
+ }
+
+ mloop = &subsurfedLoops[mpoly->loopstart];
+
+ /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
+ BLI_assert(mpoly->totloop == 4);
+ key = (ParamKey)i;
+ vkeys[0] = (ParamKey)mloop[0].v;
+ vkeys[1] = (ParamKey)mloop[1].v;
+ vkeys[2] = (ParamKey)mloop[2].v;
+ vkeys[3] = (ParamKey)mloop[3].v;
+
+ co[0] = subsurfedVerts[mloop[0].v].co;
+ co[1] = subsurfedVerts[mloop[1].v].co;
+ co[2] = subsurfedVerts[mloop[2].v].co;
+ co[3] = subsurfedVerts[mloop[3].v].co;
+
+ /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
+ * flushing the solution to the edit mesh. */
+ texface_from_original_index(origFace,
+ origVertIndices[mloop[0].v],
+ &uv[0],
+ &pin[0],
+ &select[0],
+ scene,
+ cd_loop_uv_offset);
+ texface_from_original_index(origFace,
+ origVertIndices[mloop[1].v],
+ &uv[1],
+ &pin[1],
+ &select[1],
+ scene,
+ cd_loop_uv_offset);
+ texface_from_original_index(origFace,
+ origVertIndices[mloop[2].v],
+ &uv[2],
+ &pin[2],
+ &select[2],
+ scene,
+ cd_loop_uv_offset);
+ texface_from_original_index(origFace,
+ origVertIndices[mloop[3].v],
+ &uv[3],
+ &pin[3],
+ &select[3],
+ scene,
+ cd_loop_uv_offset);
+
+ param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
+ }
+
+ /* these are calculated from original mesh too */
+ for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
+ if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)edge->v1;
+ vkeys[1] = (ParamKey)edge->v2;
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+
+ param_construct_end(handle, options->fill_holes, options->topology_from_uvs);
+
+ /* cleanup */
+ MEM_freeN(faceMap);
+ MEM_freeN(edgeMap);
+ derivedMesh->release(derivedMesh);
+
+ return handle;
}
/* ******************** Minimize Stretch operator **************** */
typedef struct MinStretch {
- Scene *scene;
- Object **objects_edit;
- uint objects_len;
- ParamHandle *handle;
- float blend;
- double lasttime;
- int i, iterations;
- wmTimer *timer;
+ Scene *scene;
+ Object **objects_edit;
+ uint objects_len;
+ ParamHandle *handle;
+ float blend;
+ double lasttime;
+ int i, iterations;
+ wmTimer *timer;
} MinStretch;
static bool minimize_stretch_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
- .only_selected = true,
- .correct_aspect = true,
- };
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
-
- if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
- MEM_freeN(objects);
- return false;
- }
-
- MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
- ms->scene = scene;
- ms->objects_edit = objects;
- ms->objects_len = objects_len;
- ms->blend = RNA_float_get(op->ptr, "blend");
- ms->iterations = RNA_int_get(op->ptr, "iterations");
- ms->i = 0;
- ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
- ms->lasttime = PIL_check_seconds_timer();
-
- param_stretch_begin(ms->handle);
- if (ms->blend != 0.0f)
- param_stretch_blend(ms->handle, ms->blend);
-
- op->customdata = ms;
-
- return true;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ const UnwrapOptions options = {
+ .topology_from_uvs = true,
+ .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
+ .only_selected = true,
+ .correct_aspect = true,
+ };
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
+ MEM_freeN(objects);
+ return false;
+ }
+
+ MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
+ ms->scene = scene;
+ ms->objects_edit = objects;
+ ms->objects_len = objects_len;
+ ms->blend = RNA_float_get(op->ptr, "blend");
+ ms->iterations = RNA_int_get(op->ptr, "iterations");
+ ms->i = 0;
+ ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
+ ms->lasttime = PIL_check_seconds_timer();
+
+ param_stretch_begin(ms->handle);
+ if (ms->blend != 0.0f)
+ param_stretch_blend(ms->handle, ms->blend);
+
+ op->customdata = ms;
+
+ return true;
}
static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
{
- MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ MinStretch *ms = op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- param_stretch_blend(ms->handle, ms->blend);
- param_stretch_iter(ms->handle);
+ param_stretch_blend(ms->handle, ms->blend);
+ param_stretch_iter(ms->handle);
- ms->i++;
- RNA_int_set(op->ptr, "iterations", ms->i);
+ ms->i++;
+ RNA_int_set(op->ptr, "iterations", ms->i);
- if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
- char str[UI_MAX_DRAW_STR];
+ if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
+ char str[UI_MAX_DRAW_STR];
- param_flush(ms->handle);
+ param_flush(ms->handle);
- if (sa) {
- BLI_snprintf(str, sizeof(str), IFACE_("Minimize Stretch. Blend %.2f"), ms->blend);
- ED_area_status_text(sa, str);
- ED_workspace_status_text(C, IFACE_("Press + and -, or scroll wheel to set blending"));
- }
+ if (sa) {
+ BLI_snprintf(str, sizeof(str), IFACE_("Minimize Stretch. Blend %.2f"), ms->blend);
+ ED_area_status_text(sa, str);
+ ED_workspace_status_text(C, IFACE_("Press + and -, or scroll wheel to set blending"));
+ }
- ms->lasttime = PIL_check_seconds_timer();
+ ms->lasttime = PIL_check_seconds_timer();
- for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
- Object *obedit = ms->objects_edit[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
+ Object *obedit = ms->objects_edit[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (synced_selection && (em->bm->totfacesel == 0)) {
- continue;
- }
+ if (synced_selection && (em->bm->totfacesel == 0)) {
+ continue;
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- }
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
}
static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
- MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ MinStretch *ms = op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- ED_area_status_text(sa, NULL);
- ED_workspace_status_text(C, NULL);
+ ED_area_status_text(sa, NULL);
+ ED_workspace_status_text(C, NULL);
- if (ms->timer)
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
+ if (ms->timer)
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
- if (cancel)
- param_flush_restore(ms->handle);
- else
- param_flush(ms->handle);
+ if (cancel)
+ param_flush_restore(ms->handle);
+ else
+ param_flush(ms->handle);
- param_stretch_end(ms->handle);
- param_delete(ms->handle);
+ param_stretch_end(ms->handle);
+ param_delete(ms->handle);
- for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
- Object *obedit = ms->objects_edit[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
+ Object *obedit = ms->objects_edit[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (synced_selection && (em->bm->totfacesel == 0)) {
- continue;
- }
+ if (synced_selection && (em->bm->totfacesel == 0)) {
+ continue;
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
- MEM_freeN(ms->objects_edit);
- MEM_freeN(ms);
- op->customdata = NULL;
+ MEM_freeN(ms->objects_edit);
+ MEM_freeN(ms);
+ op->customdata = NULL;
}
static int minimize_stretch_exec(bContext *C, wmOperator *op)
{
- int i, iterations;
+ int i, iterations;
- if (!minimize_stretch_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!minimize_stretch_init(C, op))
+ return OPERATOR_CANCELLED;
- iterations = RNA_int_get(op->ptr, "iterations");
- for (i = 0; i < iterations; i++)
- minimize_stretch_iteration(C, op, false);
- minimize_stretch_exit(C, op, false);
+ iterations = RNA_int_get(op->ptr, "iterations");
+ for (i = 0; i < iterations; i++)
+ minimize_stretch_iteration(C, op, false);
+ minimize_stretch_exit(C, op, false);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- MinStretch *ms;
+ MinStretch *ms;
- if (!minimize_stretch_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!minimize_stretch_init(C, op))
+ return OPERATOR_CANCELLED;
- minimize_stretch_iteration(C, op, true);
+ minimize_stretch_iteration(C, op, true);
- ms = op->customdata;
- WM_event_add_modal_handler(C, op);
- ms->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+ ms = op->customdata;
+ WM_event_add_modal_handler(C, op);
+ ms->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- MinStretch *ms = op->customdata;
-
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- minimize_stretch_exit(C, op, true);
- return OPERATOR_CANCELLED;
- case RETKEY:
- case PADENTER:
- case LEFTMOUSE:
- minimize_stretch_exit(C, op, false);
- return OPERATOR_FINISHED;
- case PADPLUSKEY:
- case WHEELUPMOUSE:
- if (event->val == KM_PRESS) {
- if (ms->blend < 0.95f) {
- ms->blend += 0.1f;
- ms->lasttime = 0.0f;
- RNA_float_set(op->ptr, "blend", ms->blend);
- minimize_stretch_iteration(C, op, true);
- }
- }
- break;
- case PADMINUS:
- case WHEELDOWNMOUSE:
- if (event->val == KM_PRESS) {
- if (ms->blend > 0.05f) {
- ms->blend -= 0.1f;
- ms->lasttime = 0.0f;
- RNA_float_set(op->ptr, "blend", ms->blend);
- minimize_stretch_iteration(C, op, true);
- }
- }
- break;
- case TIMER:
- if (ms->timer == event->customdata) {
- double start = PIL_check_seconds_timer();
-
- do {
- minimize_stretch_iteration(C, op, true);
- } while (PIL_check_seconds_timer() - start < 0.01);
- }
- break;
- }
-
- if (ms->iterations && ms->i >= ms->iterations) {
- minimize_stretch_exit(C, op, false);
- return OPERATOR_FINISHED;
- }
-
- return OPERATOR_RUNNING_MODAL;
+ MinStretch *ms = op->customdata;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ minimize_stretch_exit(C, op, true);
+ return OPERATOR_CANCELLED;
+ case RETKEY:
+ case PADENTER:
+ case LEFTMOUSE:
+ minimize_stretch_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ case PADPLUSKEY:
+ case WHEELUPMOUSE:
+ if (event->val == KM_PRESS) {
+ if (ms->blend < 0.95f) {
+ ms->blend += 0.1f;
+ ms->lasttime = 0.0f;
+ RNA_float_set(op->ptr, "blend", ms->blend);
+ minimize_stretch_iteration(C, op, true);
+ }
+ }
+ break;
+ case PADMINUS:
+ case WHEELDOWNMOUSE:
+ if (event->val == KM_PRESS) {
+ if (ms->blend > 0.05f) {
+ ms->blend -= 0.1f;
+ ms->lasttime = 0.0f;
+ RNA_float_set(op->ptr, "blend", ms->blend);
+ minimize_stretch_iteration(C, op, true);
+ }
+ }
+ break;
+ case TIMER:
+ if (ms->timer == event->customdata) {
+ double start = PIL_check_seconds_timer();
+
+ do {
+ minimize_stretch_iteration(C, op, true);
+ } while (PIL_check_seconds_timer() - start < 0.01);
+ }
+ break;
+ }
+
+ if (ms->iterations && ms->i >= ms->iterations) {
+ minimize_stretch_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
static void minimize_stretch_cancel(bContext *C, wmOperator *op)
{
- minimize_stretch_exit(C, op, true);
+ minimize_stretch_exit(C, op, true);
}
void UV_OT_minimize_stretch(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Minimize Stretch";
- ot->idname = "UV_OT_minimize_stretch";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
- ot->description = "Reduce UV stretching by relaxing angles";
-
- /* api callbacks */
- ot->exec = minimize_stretch_exec;
- ot->invoke = minimize_stretch_invoke;
- ot->modal = minimize_stretch_modal;
- ot->cancel = minimize_stretch_cancel;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
- RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
+ /* identifiers */
+ ot->name = "Minimize Stretch";
+ ot->idname = "UV_OT_minimize_stretch";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
+ ot->description = "Reduce UV stretching by relaxing angles";
+
+ /* api callbacks */
+ ot->exec = minimize_stretch_exec;
+ ot->invoke = minimize_stretch_invoke;
+ ot->modal = minimize_stretch_modal;
+ ot->cancel = minimize_stretch_cancel;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "fill_holes",
+ 1,
+ "Fill Holes",
+ "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
+ "preserve symmetry");
+ RNA_def_float_factor(ot->srna,
+ "blend",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Blend",
+ "Blend factor between stretch minimized and original",
+ 0.0f,
+ 1.0f);
+ RNA_def_int(ot->srna,
+ "iterations",
+ 0,
+ 0,
+ INT_MAX,
+ "Iterations",
+ "Number of iterations to run, 0 is unlimited when run interactively",
+ 0,
+ 100);
}
/* ******************** Pack Islands operator **************** */
static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm)
{
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .only_selected = false,
- .fill_holes = false,
- .correct_aspect = false,
- };
-
- bool rotate = true;
- bool ignore_pinned = false;
-
- ParamHandle *handle;
- handle = construct_param_handle(scene, ob, bm, &options);
- param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- param_flush(handle);
- param_delete(handle);
+ const UnwrapOptions options = {
+ .topology_from_uvs = true,
+ .only_selected = false,
+ .fill_holes = false,
+ .correct_aspect = false,
+ };
+
+ bool rotate = true;
+ bool ignore_pinned = false;
+
+ ParamHandle *handle;
+ handle = construct_param_handle(scene, ob, bm, &options);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
+ param_flush(handle);
+ param_delete(handle);
}
-static void uvedit_pack_islands_multi(
- Scene *scene, Object **objects, const uint objects_len,
- const UnwrapOptions *options, bool rotate, bool ignore_pinned)
+static void uvedit_pack_islands_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const UnwrapOptions *options,
+ bool rotate,
+ bool ignore_pinned)
{
- ParamHandle *handle;
- handle = construct_param_handle_multi(scene, objects, objects_len, options);
- param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
- param_flush(handle);
- param_delete(handle);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
- }
+ ParamHandle *handle;
+ handle = construct_param_handle_multi(scene, objects, objects_len, options);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
+ param_flush(handle);
+ param_delete(handle);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
+ }
}
static int pack_islands_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .only_selected = true,
- .fill_holes = false,
- .correct_aspect = true,
- };
+ const UnwrapOptions options = {
+ .topology_from_uvs = true,
+ .only_selected = true,
+ .fill_holes = false,
+ .correct_aspect = true,
+ };
- bool rotate = RNA_boolean_get(op->ptr, "rotate");
- bool ignore_pinned = false;
+ bool rotate = RNA_boolean_get(op->ptr, "rotate");
+ bool ignore_pinned = false;
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
- if (RNA_struct_property_is_set(op->ptr, "margin"))
- scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
- else
- RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
+ if (RNA_struct_property_is_set(op->ptr, "margin"))
+ scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
+ else
+ RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+ uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
- MEM_freeN(objects);
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void UV_OT_pack_islands(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Pack Islands";
- ot->idname = "UV_OT_pack_islands";
- ot->description = "Transform all islands so that they fill up the UV space as much as possible";
+ /* identifiers */
+ ot->name = "Pack Islands";
+ ot->idname = "UV_OT_pack_islands";
+ ot->description = "Transform all islands so that they fill up the UV space as much as possible";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = pack_islands_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = pack_islands_exec;
+ ot->poll = ED_operator_uvedit;
- /* properties */
- RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
- RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
+ /* properties */
+ RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
+ RNA_def_float_factor(
+ ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
/* ******************** Average Islands Scale operator **************** */
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- ToolSettings *ts = scene->toolsettings;
- const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
-
- const UnwrapOptions options = {
- .topology_from_uvs = true,
- .only_selected = true,
- .fill_holes = false,
- .correct_aspect = true,
- };
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
-
- if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
-
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
- param_average(handle, false);
- param_flush(handle);
- param_delete(handle);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (synced_selection && (em->bm->totvertsel == 0)) {
- continue;
- }
-
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ const UnwrapOptions options = {
+ .topology_from_uvs = true,
+ .only_selected = true,
+ .fill_holes = false,
+ .correct_aspect = true,
+ };
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
+ param_average(handle, false);
+ param_flush(handle);
+ param_delete(handle);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void UV_OT_average_islands_scale(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Average Islands Scale";
- ot->idname = "UV_OT_average_islands_scale";
- ot->description = "Average the size of separate UV islands, based on their area in 3D space";
+ /* identifiers */
+ ot->name = "Average Islands Scale";
+ ot->idname = "UV_OT_average_islands_scale";
+ ot->description = "Average the size of separate UV islands, based on their area in 3D space";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = average_islands_scale_exec;
- ot->poll = ED_operator_uvedit;
+ /* api callbacks */
+ ot->exec = average_islands_scale_exec;
+ ot->poll = ED_operator_uvedit;
}
/**************** Live Unwrap *****************/
static struct {
- ParamHandle **handles;
- uint len, len_alloc;
+ ParamHandle **handles;
+ uint len, len_alloc;
} g_live_unwrap = {NULL};
void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
{
- ParamHandle *handle = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const bool abf = (scene->toolsettings->unwrapper == 0);
- bool use_subsurf;
-
- modifier_unwrap_state(obedit, scene, &use_subsurf);
-
- if (!ED_uvedit_test(obedit)) {
- return;
- }
-
- const UnwrapOptions options = {
- .topology_from_uvs = false,
- .only_selected = false,
- .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
- .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
- };
-
- if (use_subsurf)
- handle = construct_param_handle_subsurfed(scene, obedit, em, &options);
- else
- handle = construct_param_handle(scene, obedit, em->bm, &options);
-
- param_lscm_begin(handle, PARAM_TRUE, abf);
-
- /* Create or increase size of g_live_unwrap.handles array */
- if (g_live_unwrap.handles == NULL) {
- g_live_unwrap.len_alloc = 32;
- g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, "uvedit_live_unwrap_liveHandles");
- g_live_unwrap.len = 0;
- }
- if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
- g_live_unwrap.len_alloc *= 2;
- g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
- }
- g_live_unwrap.handles[g_live_unwrap.len] = handle;
- g_live_unwrap.len++;
+ ParamHandle *handle = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const bool abf = (scene->toolsettings->unwrapper == 0);
+ bool use_subsurf;
+
+ modifier_unwrap_state(obedit, scene, &use_subsurf);
+
+ if (!ED_uvedit_test(obedit)) {
+ return;
+ }
+
+ const UnwrapOptions options = {
+ .topology_from_uvs = false,
+ .only_selected = false,
+ .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
+ .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
+ };
+
+ if (use_subsurf)
+ handle = construct_param_handle_subsurfed(scene, obedit, em, &options);
+ else
+ handle = construct_param_handle(scene, obedit, em->bm, &options);
+
+ param_lscm_begin(handle, PARAM_TRUE, abf);
+
+ /* Create or increase size of g_live_unwrap.handles array */
+ if (g_live_unwrap.handles == NULL) {
+ g_live_unwrap.len_alloc = 32;
+ g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc,
+ "uvedit_live_unwrap_liveHandles");
+ g_live_unwrap.len = 0;
+ }
+ if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
+ g_live_unwrap.len_alloc *= 2;
+ g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles,
+ sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
+ }
+ g_live_unwrap.handles[g_live_unwrap.len] = handle;
+ g_live_unwrap.len++;
}
void ED_uvedit_live_unwrap_re_solve(void)
{
- if (g_live_unwrap.handles) {
- for (int i = 0; i < g_live_unwrap.len; i++) {
- param_lscm_solve(g_live_unwrap.handles[i]);
- param_flush(g_live_unwrap.handles[i]);
- }
- }
+ if (g_live_unwrap.handles) {
+ for (int i = 0; i < g_live_unwrap.len; i++) {
+ param_lscm_solve(g_live_unwrap.handles[i]);
+ param_flush(g_live_unwrap.handles[i]);
+ }
+ }
}
void ED_uvedit_live_unwrap_end(short cancel)
{
- if (g_live_unwrap.handles) {
- for (int i = 0; i < g_live_unwrap.len; i++) {
- param_lscm_end(g_live_unwrap.handles[i]);
- if (cancel)
- param_flush_restore(g_live_unwrap.handles[i]);
- param_delete(g_live_unwrap.handles[i]);
- }
- MEM_freeN(g_live_unwrap.handles);
- g_live_unwrap.handles = NULL;
- g_live_unwrap.len = 0;
- g_live_unwrap.len_alloc = 0;
- }
+ if (g_live_unwrap.handles) {
+ for (int i = 0; i < g_live_unwrap.len; i++) {
+ param_lscm_end(g_live_unwrap.handles[i]);
+ if (cancel)
+ param_flush_restore(g_live_unwrap.handles[i]);
+ param_delete(g_live_unwrap.handles[i]);
+ }
+ MEM_freeN(g_live_unwrap.handles);
+ g_live_unwrap.handles = NULL;
+ g_live_unwrap.len = 0;
+ g_live_unwrap.len_alloc = 0;
+ }
}
/*************** UV Map Common Transforms *****************/
#define VIEW_ON_EQUATOR 0
-#define VIEW_ON_POLES 1
+#define VIEW_ON_POLES 1
#define ALIGN_TO_OBJECT 2
-#define POLAR_ZX 0
-#define POLAR_ZY 1
+#define POLAR_ZX 0
+#define POLAR_ZY 1
static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3])
{
- BMFace *efa;
- BMIter iter;
- INIT_MINMAX(r_min, r_max);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_face_calc_bounds_expand(efa, r_min, r_max);
- }
- }
+ BMFace *efa;
+ BMIter iter;
+ INIT_MINMAX(r_min, r_max);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_face_calc_bounds_expand(efa, r_min, r_max);
+ }
+ }
}
static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3])
{
- BMFace *efa;
- BMIter iter;
- uint center_accum_num = 0;
- zero_v3(r_center);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- float center[3];
- BM_face_calc_center_median(efa, center);
- add_v3_v3(r_center, center);
- center_accum_num += 1;
- }
- }
- mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
+ BMFace *efa;
+ BMIter iter;
+ uint center_accum_num = 0;
+ zero_v3(r_center);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ float center[3];
+ BM_face_calc_center_median(efa, center);
+ add_v3_v3(r_center, center);
+ center_accum_num += 1;
+ }
+ }
+ mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
}
static void uv_map_transform_center(
- Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em,
- float r_center[3],
- float r_bounds[2][3])
+ Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, float r_center[3], float r_bounds[2][3])
{
- /* only operates on the edit object - this is all that's needed now */
- const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
-
- float bounds[2][3];
- INIT_MINMAX(bounds[0], bounds[1]);
- bool is_minmax_set = false;
-
- switch (around) {
- case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
- {
- uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
- is_minmax_set = true;
- mid_v3_v3v3(r_center, bounds[0], bounds[1]);
- break;
- }
- case V3D_AROUND_CENTER_MEDIAN:
- {
- uv_map_transform_calc_center_median(em, r_center);
- break;
- }
- case V3D_AROUND_CURSOR: /* cursor center */
- {
- invert_m4_m4(ob->imat, ob->obmat);
- mul_v3_m4v3(r_center, ob->imat, scene->cursor.location);
- break;
- }
- case V3D_AROUND_ACTIVE:
- {
- BMEditSelection ese;
- if (BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_center(&ese, r_center);
- break;
- }
- ATTR_FALLTHROUGH;
- }
- case V3D_AROUND_LOCAL_ORIGINS: /* object center */
- default:
- zero_v3(r_center);
- break;
- }
-
- /* if this is passed, always set! */
- if (r_bounds) {
- if (!is_minmax_set) {
- uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
- }
- copy_v3_v3(r_bounds[0], bounds[0]);
- copy_v3_v3(r_bounds[1], bounds[1]);
- }
+ /* only operates on the edit object - this is all that's needed now */
+ const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
+
+ float bounds[2][3];
+ INIT_MINMAX(bounds[0], bounds[1]);
+ bool is_minmax_set = false;
+
+ switch (around) {
+ case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
+ {
+ uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
+ is_minmax_set = true;
+ mid_v3_v3v3(r_center, bounds[0], bounds[1]);
+ break;
+ }
+ case V3D_AROUND_CENTER_MEDIAN: {
+ uv_map_transform_calc_center_median(em, r_center);
+ break;
+ }
+ case V3D_AROUND_CURSOR: /* cursor center */
+ {
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_v3_m4v3(r_center, ob->imat, scene->cursor.location);
+ break;
+ }
+ case V3D_AROUND_ACTIVE: {
+ BMEditSelection ese;
+ if (BM_select_history_active_get(em->bm, &ese)) {
+ BM_editselection_center(&ese, r_center);
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_AROUND_LOCAL_ORIGINS: /* object center */
+ default:
+ zero_v3(r_center);
+ break;
+ }
+
+ /* if this is passed, always set! */
+ if (r_bounds) {
+ if (!is_minmax_set) {
+ uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
+ }
+ copy_v3_v3(r_bounds[0], bounds[0]);
+ copy_v3_v3(r_bounds[1], bounds[1]);
+ }
}
-static void uv_map_rotation_matrix_ex(
- float result[4][4], RegionView3D *rv3d, Object *ob,
- float upangledeg, float sideangledeg, float radius, float offset[4])
+static void uv_map_rotation_matrix_ex(float result[4][4],
+ RegionView3D *rv3d,
+ Object *ob,
+ float upangledeg,
+ float sideangledeg,
+ float radius,
+ float offset[4])
{
- float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
- float sideangle = 0.0f, upangle = 0.0f;
-
- /* get rotation of the current view matrix */
- if (rv3d)
- copy_m4_m4(viewmatrix, rv3d->viewmat);
- else
- unit_m4(viewmatrix);
-
- /* but shifting */
- copy_v4_fl(viewmatrix[3], 0.0f);
-
- /* get rotation of the current object matrix */
- copy_m4_m4(rotobj, ob->obmat);
-
- /* but shifting */
- add_v4_v4(rotobj[3], offset);
- rotobj[3][3] = 0.0f;
-
- zero_m4(rotup);
- zero_m4(rotside);
-
- /* compensate front/side.. against opengl x,y,z world definition */
- /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
- /* i wanted to keep the reason here, so we're rotating*/
- sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f;
- rotside[0][0] = cosf(sideangle);
- rotside[0][1] = -sinf(sideangle);
- rotside[1][0] = sinf(sideangle);
- rotside[1][1] = cosf(sideangle);
- rotside[2][2] = 1.0f;
-
- upangle = (float)M_PI * upangledeg / 180.0f;
- rotup[1][1] = cosf(upangle) / radius;
- rotup[1][2] = -sinf(upangle) / radius;
- rotup[2][1] = sinf(upangle) / radius;
- rotup[2][2] = cosf(upangle) / radius;
- rotup[0][0] = 1.0f / radius;
-
- /* calculate transforms*/
- mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
+ float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
+ float sideangle = 0.0f, upangle = 0.0f;
+
+ /* get rotation of the current view matrix */
+ if (rv3d)
+ copy_m4_m4(viewmatrix, rv3d->viewmat);
+ else
+ unit_m4(viewmatrix);
+
+ /* but shifting */
+ copy_v4_fl(viewmatrix[3], 0.0f);
+
+ /* get rotation of the current object matrix */
+ copy_m4_m4(rotobj, ob->obmat);
+
+ /* but shifting */
+ add_v4_v4(rotobj[3], offset);
+ rotobj[3][3] = 0.0f;
+
+ zero_m4(rotup);
+ zero_m4(rotside);
+
+ /* compensate front/side.. against opengl x,y,z world definition */
+ /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
+ /* i wanted to keep the reason here, so we're rotating*/
+ sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f;
+ rotside[0][0] = cosf(sideangle);
+ rotside[0][1] = -sinf(sideangle);
+ rotside[1][0] = sinf(sideangle);
+ rotside[1][1] = cosf(sideangle);
+ rotside[2][2] = 1.0f;
+
+ upangle = (float)M_PI * upangledeg / 180.0f;
+ rotup[1][1] = cosf(upangle) / radius;
+ rotup[1][2] = -sinf(upangle) / radius;
+ rotup[2][1] = sinf(upangle) / radius;
+ rotup[2][2] = cosf(upangle) / radius;
+ rotup[0][0] = 1.0f / radius;
+
+ /* calculate transforms*/
+ mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
}
-static void uv_map_rotation_matrix(
- float result[4][4], RegionView3D *rv3d, Object *ob,
- float upangledeg, float sideangledeg, float radius)
+static void uv_map_rotation_matrix(float result[4][4],
+ RegionView3D *rv3d,
+ Object *ob,
+ float upangledeg,
+ float sideangledeg,
+ float radius)
{
- float offset[4] = {0};
- uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
+ float offset[4] = {0};
+ uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
}
static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
{
- /* context checks are messy here, making it work in both 3d view and uv editor */
- Object *obedit = CTX_data_edit_object(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- /* common operator properties */
- int align = RNA_enum_get(op->ptr, "align");
- int direction = RNA_enum_get(op->ptr, "direction");
- float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") : 1.0f;
- float upangledeg, sideangledeg;
-
- if (direction == VIEW_ON_EQUATOR) {
- upangledeg = 90.0f;
- sideangledeg = 0.0f;
- }
- else {
- upangledeg = 0.0f;
- if (align == POLAR_ZY) sideangledeg = 0.0f;
- else sideangledeg = 90.0f;
- }
-
- /* be compatible to the "old" sphere/cylinder mode */
- if (direction == ALIGN_TO_OBJECT)
- unit_m4(rotmat);
- else
- uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
-
+ /* context checks are messy here, making it work in both 3d view and uv editor */
+ Object *obedit = CTX_data_edit_object(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ /* common operator properties */
+ int align = RNA_enum_get(op->ptr, "align");
+ int direction = RNA_enum_get(op->ptr, "direction");
+ float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") :
+ 1.0f;
+ float upangledeg, sideangledeg;
+
+ if (direction == VIEW_ON_EQUATOR) {
+ upangledeg = 90.0f;
+ sideangledeg = 0.0f;
+ }
+ else {
+ upangledeg = 0.0f;
+ if (align == POLAR_ZY)
+ sideangledeg = 0.0f;
+ else
+ sideangledeg = 90.0f;
+ }
+
+ /* be compatible to the "old" sphere/cylinder mode */
+ if (direction == ALIGN_TO_OBJECT)
+ unit_m4(rotmat);
+ else
+ uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
}
static void uv_transform_properties(wmOperatorType *ot, int radius)
{
- static const EnumPropertyItem direction_items[] = {
- {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
- {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
- {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"},
- {0, NULL, 0, NULL, NULL},
- };
- static const EnumPropertyItem align_items[] = {
- {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
- {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
- {0, NULL, 0, NULL, NULL},
- };
-
- RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction",
- "Direction of the sphere or cylinder");
- RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align",
- "How to determine rotation around the pole");
- if (radius)
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius",
- "Radius of the sphere or cylinder", 0.0001f, 100.0f);
+ static const EnumPropertyItem direction_items[] = {
+ {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
+ {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
+ {ALIGN_TO_OBJECT,
+ "ALIGN_TO_OBJECT",
+ 0,
+ "Align to Object",
+ "Align according to object transform"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ static const EnumPropertyItem align_items[] = {
+ {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
+ {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ direction_items,
+ VIEW_ON_EQUATOR,
+ "Direction",
+ "Direction of the sphere or cylinder");
+ RNA_def_enum(ot->srna,
+ "align",
+ align_items,
+ VIEW_ON_EQUATOR,
+ "Align",
+ "How to determine rotation around the pole");
+ if (radius)
+ RNA_def_float(ot->srna,
+ "radius",
+ 1.0f,
+ 0.0f,
+ FLT_MAX,
+ "Radius",
+ "Radius of the sphere or cylinder",
+ 0.0001f,
+ 100.0f);
}
static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
{
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- BMFace *efa;
- float scale, aspx, aspy;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
-
- if (aspx == aspy)
- return;
-
- if (aspx > aspy) {
- scale = aspy / aspx;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
- }
- }
- }
- else {
- scale = aspx / aspy;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
- }
- }
- }
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ BMFace *efa;
+ float scale, aspx, aspy;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
+
+ if (aspx == aspy)
+ return;
+
+ if (aspx > aspy) {
+ scale = aspy / aspx;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
+ }
+ }
+ }
+ else {
+ scale = aspx / aspy;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
+ }
+ }
+ }
}
/******************** Map Clip & Correct ******************/
static void uv_map_clip_correct_properties(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
- "Map UVs taking image aspect ratio into account");
- RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds",
- "Clip UV coordinates to bounds after unwrapping");
- RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds",
- "Scale UV coordinates to bounds after unwrapping");
+ RNA_def_boolean(ot->srna,
+ "correct_aspect",
+ 1,
+ "Correct Aspect",
+ "Map UVs taking image aspect ratio into account");
+ RNA_def_boolean(ot->srna,
+ "clip_to_bounds",
+ 0,
+ "Clip to Bounds",
+ "Clip UV coordinates to bounds after unwrapping");
+ RNA_def_boolean(ot->srna,
+ "scale_to_bounds",
+ 0,
+ "Scale to Bounds",
+ "Scale UV coordinates to bounds after unwrapping");
}
-static void uv_map_clip_correct_multi(Scene *scene, Object **objects, uint objects_len, wmOperator *op)
+static void uv_map_clip_correct_multi(Scene *scene,
+ Object **objects,
+ uint objects_len,
+ wmOperator *op)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- float dx, dy, min[2], max[2];
- const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
- const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds");
- const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
-
- INIT_MINMAX2(min, max);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* correct for image aspect ratio */
- if (correct_aspect)
- correct_uv_aspect(scene, ob, em);
-
- if (scale_to_bounds) {
- /* find uv limits */
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(min, max, luv->uv);
- }
- }
- }
- else if (clip_to_bounds) {
- /* clipping and wrapping */
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- CLAMP(luv->uv[0], 0.0f, 1.0f);
- CLAMP(luv->uv[1], 0.0f, 1.0f);
- }
- }
- }
- }
-
- if (scale_to_bounds) {
- /* rescale UV to be in 1/1 */
- dx = (max[0] - min[0]);
- dy = (max[1] - min[1]);
-
- if (dx > 0.0f)
- dx = 1.0f / dx;
- if (dy > 0.0f)
- dy = 1.0f / dy;
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->uv[0] = (luv->uv[0] - min[0]) * dx;
- luv->uv[1] = (luv->uv[1] - min[1]) * dy;
- }
- }
- }
- }
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ float dx, dy, min[2], max[2];
+ const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
+ const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds");
+ const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
+
+ INIT_MINMAX2(min, max);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* correct for image aspect ratio */
+ if (correct_aspect)
+ correct_uv_aspect(scene, ob, em);
+
+ if (scale_to_bounds) {
+ /* find uv limits */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(min, max, luv->uv);
+ }
+ }
+ }
+ else if (clip_to_bounds) {
+ /* clipping and wrapping */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ CLAMP(luv->uv[0], 0.0f, 1.0f);
+ CLAMP(luv->uv[1], 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+
+ if (scale_to_bounds) {
+ /* rescale UV to be in 1/1 */
+ dx = (max[0] - min[0]);
+ dy = (max[1] - min[1]);
+
+ if (dx > 0.0f)
+ dx = 1.0f / dx;
+ if (dy > 0.0f)
+ dy = 1.0f / dy;
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->uv[0] = (luv->uv[0] - min[0]) * dx;
+ luv->uv[1] = (luv->uv[1] - min[1]) * dy;
+ }
+ }
+ }
+ }
}
static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
{
- uv_map_clip_correct_multi(scene, &ob, 1, op);
+ uv_map_clip_correct_multi(scene, &ob, 1, op);
}
/* ******************** Unwrap operator **************** */
@@ -1413,195 +1510,228 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
/* Assumes UV Map exists, doesn't run update funcs. */
static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *options)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
- return;
- }
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
+ return;
+ }
- bool use_subsurf;
- modifier_unwrap_state(obedit, scene, &use_subsurf);
+ bool use_subsurf;
+ modifier_unwrap_state(obedit, scene, &use_subsurf);
- ParamHandle *handle;
- if (use_subsurf)
- handle = construct_param_handle_subsurfed(scene, obedit, em, options);
- else
- handle = construct_param_handle(scene, obedit, em->bm, options);
+ ParamHandle *handle;
+ if (use_subsurf)
+ handle = construct_param_handle_subsurfed(scene, obedit, em, options);
+ else
+ handle = construct_param_handle(scene, obedit, em->bm, options);
- param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
- param_lscm_solve(handle);
- param_lscm_end(handle);
+ param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
+ param_lscm_solve(handle);
+ param_lscm_end(handle);
- param_average(handle, true);
+ param_average(handle, true);
- param_flush(handle);
+ param_flush(handle);
- param_delete(handle);
+ param_delete(handle);
}
-static void uvedit_unwrap_multi(Scene *scene, Object **objects, const int objects_len, const UnwrapOptions *options)
+static void uvedit_unwrap_multi(Scene *scene,
+ Object **objects,
+ const int objects_len,
+ const UnwrapOptions *options)
{
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uvedit_unwrap(scene, obedit, options);
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uvedit_unwrap(scene, obedit, options);
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
+ }
}
void ED_uvedit_live_unwrap(Scene *scene, Object **objects, int objects_len)
{
- if (scene->toolsettings->edge_mode_live_unwrap) {
- const UnwrapOptions options = {
- .topology_from_uvs = false,
- .only_selected = false,
- .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
- .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
- };
-
- bool rotate = true;
- bool ignore_pinned = true;
-
- uvedit_unwrap_multi(scene, objects, objects_len, &options);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
- }
+ if (scene->toolsettings->edge_mode_live_unwrap) {
+ const UnwrapOptions options = {
+ .topology_from_uvs = false,
+ .only_selected = false,
+ .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
+ .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
+ };
+
+ bool rotate = true;
+ bool ignore_pinned = true;
+
+ uvedit_unwrap_multi(scene, objects, objects_len, &options);
+ uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+ }
}
enum {
- UNWRAP_ERROR_NONUNIFORM = (1 << 0),
- UNWRAP_ERROR_NEGATIVE = (1 << 1),
+ UNWRAP_ERROR_NONUNIFORM = (1 << 0),
+ UNWRAP_ERROR_NEGATIVE = (1 << 1),
};
static int unwrap_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
- int method = RNA_enum_get(op->ptr, "method");
- const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
- int reported_errors = 0;
- /* We will report an error unless at least one object
- * has the subsurf modifier in the right place. */
- bool subsurf_error = use_subsurf;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
-
- const UnwrapOptions options = {
- .topology_from_uvs = false,
- .only_selected = true,
- .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
- .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
- };
-
- bool rotate = true;
- bool ignore_pinned = true;
-
- if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
-
- /* add uvs if they don't exist yet */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- float obsize[3];
- bool use_subsurf_final;
-
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
-
- if (subsurf_error) {
- /* Double up the check here but better keep uvedit_unwrap interface simple and not
- * pass operator for warning append. */
- modifier_unwrap_state(obedit, scene, &use_subsurf_final);
- if (use_subsurf_final) {
- subsurf_error = false;
- }
- }
-
- if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
- continue;
- }
-
- mat4_to_size(obsize, obedit->obmat);
- if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
- if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
- BKE_report(op->reports, RPT_INFO,
- "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
- reported_errors |= UNWRAP_ERROR_NONUNIFORM;
- }
- }
- else if (is_negative_m4(obedit->obmat)) {
- if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
- BKE_report(op->reports, RPT_INFO,
- "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
- reported_errors |= UNWRAP_ERROR_NEGATIVE;
- }
- }
- }
-
- if (subsurf_error) {
- BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
- }
-
- /* remember last method for live unwrap */
- if (RNA_struct_property_is_set(op->ptr, "method"))
- scene->toolsettings->unwrapper = method;
- else
- RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
-
- /* remember packing margin */
- if (RNA_struct_property_is_set(op->ptr, "margin"))
- scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
- else
- RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
-
- if (options.fill_holes) scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES;
- else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
-
- if (options.correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
- else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT;
-
- if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
- else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
-
- /* execute unwrap */
- uvedit_unwrap_multi(scene, objects, objects_len, &options);
- uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
-
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ int method = RNA_enum_get(op->ptr, "method");
+ const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
+ int reported_errors = 0;
+ /* We will report an error unless at least one object
+ * has the subsurf modifier in the right place. */
+ bool subsurf_error = use_subsurf;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ const UnwrapOptions options = {
+ .topology_from_uvs = false,
+ .only_selected = true,
+ .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
+ .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
+ };
+
+ bool rotate = true;
+ bool ignore_pinned = true;
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* add uvs if they don't exist yet */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ float obsize[3];
+ bool use_subsurf_final;
+
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
+
+ if (subsurf_error) {
+ /* Double up the check here but better keep uvedit_unwrap interface simple and not
+ * pass operator for warning append. */
+ modifier_unwrap_state(obedit, scene, &use_subsurf_final);
+ if (use_subsurf_final) {
+ subsurf_error = false;
+ }
+ }
+
+ if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
+ continue;
+ }
+
+ mat4_to_size(obsize, obedit->obmat);
+ if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
+ if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
+ BKE_report(op->reports,
+ RPT_INFO,
+ "Object has non-uniform scale, unwrap will operate on a non-scaled version of "
+ "the mesh");
+ reported_errors |= UNWRAP_ERROR_NONUNIFORM;
+ }
+ }
+ else if (is_negative_m4(obedit->obmat)) {
+ if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
+ BKE_report(
+ op->reports,
+ RPT_INFO,
+ "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
+ reported_errors |= UNWRAP_ERROR_NEGATIVE;
+ }
+ }
+ }
+
+ if (subsurf_error) {
+ BKE_report(op->reports,
+ RPT_INFO,
+ "Subdivision Surface modifier needs to be first to work with unwrap");
+ }
+
+ /* remember last method for live unwrap */
+ if (RNA_struct_property_is_set(op->ptr, "method"))
+ scene->toolsettings->unwrapper = method;
+ else
+ RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
+
+ /* remember packing margin */
+ if (RNA_struct_property_is_set(op->ptr, "margin"))
+ scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
+ else
+ RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
+
+ if (options.fill_holes)
+ scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES;
+ else
+ scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
+
+ if (options.correct_aspect)
+ scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
+ else
+ scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT;
+
+ if (use_subsurf)
+ scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
+ else
+ scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
+
+ /* execute unwrap */
+ uvedit_unwrap_multi(scene, objects, objects_len, &options);
+ uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void UV_OT_unwrap(wmOperatorType *ot)
{
- static const EnumPropertyItem method_items[] = {
- {0, "ANGLE_BASED", 0, "Angle Based", ""},
- {1, "CONFORMAL", 0, "Conformal", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Unwrap";
- ot->description = "Unwrap the mesh of the object being edited";
- ot->idname = "UV_OT_unwrap";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = unwrap_exec;
- ot->poll = ED_operator_uvmap;
-
- /* properties */
- RNA_def_enum(ot->srna, "method", method_items, 0, "Method",
- "Unwrapping method (Angle Based usually gives better results than Conformal, while being somewhat slower)");
- RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes",
- "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
- RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
- "Map UVs taking image aspect ratio into account");
- RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier",
- "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
- RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
+ static const EnumPropertyItem method_items[] = {
+ {0, "ANGLE_BASED", 0, "Angle Based", ""},
+ {1, "CONFORMAL", 0, "Conformal", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Unwrap";
+ ot->description = "Unwrap the mesh of the object being edited";
+ ot->idname = "UV_OT_unwrap";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = unwrap_exec;
+ ot->poll = ED_operator_uvmap;
+
+ /* properties */
+ RNA_def_enum(ot->srna,
+ "method",
+ method_items,
+ 0,
+ "Method",
+ "Unwrapping method (Angle Based usually gives better results than Conformal, while "
+ "being somewhat slower)");
+ RNA_def_boolean(ot->srna,
+ "fill_holes",
+ 1,
+ "Fill Holes",
+ "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
+ "preserve symmetry");
+ RNA_def_boolean(ot->srna,
+ "correct_aspect",
+ 1,
+ "Correct Aspect",
+ "Map UVs taking image aspect ratio into account");
+ RNA_def_boolean(
+ ot->srna,
+ "use_subsurf_data",
+ 0,
+ "Use Subsurf Modifier",
+ "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
+ RNA_def_float_factor(
+ ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
/**************** Project From View operator **************/
@@ -1609,574 +1739,605 @@ static int uv_from_view_exec(bContext *C, wmOperator *op);
static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
- PropertyRNA *prop;
-
- prop = RNA_struct_find_property(op->ptr, "camera_bounds");
- if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera != NULL));
- prop = RNA_struct_find_property(op->ptr, "correct_aspect");
- if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera == NULL));
-
- return uv_from_view_exec(C, op);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "camera_bounds");
+ if (!RNA_property_is_set(op->ptr, prop))
+ RNA_property_boolean_set(op->ptr, prop, (camera != NULL));
+ prop = RNA_struct_find_property(op->ptr, "correct_aspect");
+ if (!RNA_property_is_set(op->ptr, prop))
+ RNA_property_boolean_set(op->ptr, prop, (camera == NULL));
+
+ return uv_from_view_exec(C, op);
}
static int uv_from_view_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- float rotmat[4][4];
- float objects_pos_offset[4];
- bool changed_multi = false;
-
- const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
-
- /* Note: objects that aren't touched are set to NULL (to skip clipping). */
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
-
- if (use_orthographic) {
- /* Calculate average object position. */
- float objects_pos_avg[4] = {0};
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
- }
-
- mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
- negate_v4_v4(objects_pos_offset, objects_pos_avg);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool changed = false;
-
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (use_orthographic) {
- uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
- }
- changed = true;
- }
- }
- else if (camera) {
- const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
- struct ProjCameraInfo *uci = BLI_uvproject_camera_info(
- v3d->camera, obedit->obmat,
- camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
- camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
-
- if (uci) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
- }
- changed = true;
- }
-
- MEM_freeN(uci);
- }
- }
- else {
- copy_m4_m4(rotmat, obedit->obmat);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
- }
- changed = true;
- }
- }
-
- if (changed) {
- changed_multi = true;
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- else {
- ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
- objects_len -= 1;
- ob_index -= 1;
- }
- }
-
- if (changed_multi) {
- uv_map_clip_correct_multi(scene, objects, objects_len, op);
- }
-
- MEM_freeN(objects);
-
- if (changed_multi) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ float rotmat[4][4];
+ float objects_pos_offset[4];
+ bool changed_multi = false;
+
+ const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
+
+ /* Note: objects that aren't touched are set to NULL (to skip clipping). */
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, v3d, &objects_len);
+
+ if (use_orthographic) {
+ /* Calculate average object position. */
+ float objects_pos_avg[4] = {0};
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
+ }
+
+ mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
+ negate_v4_v4(objects_pos_offset, objects_pos_avg);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_orthographic) {
+ uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
+ }
+ changed = true;
+ }
+ }
+ else if (camera) {
+ const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
+ struct ProjCameraInfo *uci = BLI_uvproject_camera_info(
+ v3d->camera,
+ obedit->obmat,
+ camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
+ camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
+
+ if (uci) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
+ }
+ changed = true;
+ }
+
+ MEM_freeN(uci);
+ }
+ }
+ else {
+ copy_m4_m4(rotmat, obedit->obmat);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ else {
+ ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
+ objects_len -= 1;
+ ob_index -= 1;
+ }
+ }
+
+ if (changed_multi) {
+ uv_map_clip_correct_multi(scene, objects, objects_len, op);
+ }
+
+ MEM_freeN(objects);
+
+ if (changed_multi) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static bool uv_from_view_poll(bContext *C)
{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (!ED_operator_uvmap(C))
- return 0;
+ if (!ED_operator_uvmap(C))
+ return 0;
- return (rv3d != NULL);
+ return (rv3d != NULL);
}
void UV_OT_project_from_view(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Project From View";
- ot->idname = "UV_OT_project_from_view";
- ot->description = "Project the UV vertices of the mesh as seen in current 3D view";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = uv_from_view_invoke;
- ot->exec = uv_from_view_exec;
- ot->poll = uv_from_view_poll;
-
- /* properties */
- RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic",
- "Use orthographic projection");
- RNA_def_boolean(ot->srna, "camera_bounds", 1, "Camera Bounds",
- "Map UVs to the camera region taking resolution and aspect into account");
- uv_map_clip_correct_properties(ot);
+ /* identifiers */
+ ot->name = "Project From View";
+ ot->idname = "UV_OT_project_from_view";
+ ot->description = "Project the UV vertices of the mesh as seen in current 3D view";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = uv_from_view_invoke;
+ ot->exec = uv_from_view_exec;
+ ot->poll = uv_from_view_poll;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection");
+ RNA_def_boolean(ot->srna,
+ "camera_bounds",
+ 1,
+ "Camera Bounds",
+ "Map UVs to the camera region taking resolution and aspect into account");
+ uv_map_clip_correct_properties(ot);
}
/********************** Reset operator ********************/
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- Mesh *me = (Mesh *)obedit->data;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (em->bm->totfacesel == 0) {
- continue;
- }
-
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
-
- ED_mesh_uv_loop_reset(C, me);
-
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Mesh *me = (Mesh *)obedit->data;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
+
+ ED_mesh_uv_loop_reset(C, me);
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void UV_OT_reset(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reset";
- ot->idname = "UV_OT_reset";
- ot->description = "Reset UV projection";
+ /* identifiers */
+ ot->name = "Reset";
+ ot->idname = "UV_OT_reset";
+ ot->description = "Reset UV projection";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = reset_exec;
- ot->poll = ED_operator_uvmap;
+ /* api callbacks */
+ ot->exec = reset_exec;
+ ot->poll = ED_operator_uvmap;
}
/****************** Sphere Project operator ***************/
-static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4])
+static void uv_sphere_project(float target[2],
+ float source[3],
+ float center[3],
+ float rotmat[4][4])
{
- float pv[3];
+ float pv[3];
- sub_v3_v3v3(pv, source, center);
- mul_m4_v3(rotmat, pv);
+ sub_v3_v3v3(pv, source, center);
+ mul_m4_v3(rotmat, pv);
- map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]);
+ map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]);
- /* split line is always zero */
- if (target[0] >= 1.0f)
- target[0] -= 1.0f;
+ /* split line is always zero */
+ if (target[0] >= 1.0f)
+ target[0] -= 1.0f;
}
static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
{
- BMLoop *l;
- BMIter liter;
- MLoopUV *luv;
- float **uvs = BLI_array_alloca(uvs, efa->len);
- float dx;
- int i, mi;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uvs[i] = luv->uv;
- }
-
- mi = 0;
- for (i = 1; i < efa->len; i++)
- if (uvs[i][0] > uvs[mi][0])
- mi = i;
-
- for (i = 0; i < efa->len; i++) {
- if (i != mi) {
- dx = uvs[mi][0] - uvs[i][0];
- if (dx > 0.5f) uvs[i][0] += 1.0f;
- }
- }
+ BMLoop *l;
+ BMIter liter;
+ MLoopUV *luv;
+ float **uvs = BLI_array_alloca(uvs, efa->len);
+ float dx;
+ int i, mi;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i)
+ {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ uvs[i] = luv->uv;
+ }
+
+ mi = 0;
+ for (i = 1; i < efa->len; i++)
+ if (uvs[i][0] > uvs[mi][0])
+ mi = i;
+
+ for (i = 0; i < efa->len; i++) {
+ if (i != mi) {
+ dx = uvs[mi][0] - uvs[i][0];
+ if (dx > 0.5f)
+ uvs[i][0] += 1.0f;
+ }
+ }
}
static int sphere_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- if (em->bm->totfacesel == 0) {
- continue;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- float center[3], rotmat[4][4];
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ float center[3], rotmat[4][4];
- uv_map_transform(C, op, rotmat);
- uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
+ uv_map_transform(C, op, rotmat);
+ uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uv_sphere_project(luv->uv, l->v->co, center, rotmat);
- }
+ uv_sphere_project(luv->uv, l->v->co, center, rotmat);
+ }
- uv_map_mirror(em, efa);
- }
+ uv_map_mirror(em, efa);
+ }
- uv_map_clip_correct(scene, obedit, op);
+ uv_map_clip_correct(scene, obedit, op);
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- MEM_freeN(objects);
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void UV_OT_sphere_project(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sphere Projection";
- ot->idname = "UV_OT_sphere_project";
- ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere";
+ /* identifiers */
+ ot->name = "Sphere Projection";
+ ot->idname = "UV_OT_sphere_project";
+ ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = sphere_project_exec;
- ot->poll = ED_operator_uvmap;
+ /* api callbacks */
+ ot->exec = sphere_project_exec;
+ ot->poll = ED_operator_uvmap;
- /* properties */
- uv_transform_properties(ot, 0);
- uv_map_clip_correct_properties(ot);
+ /* properties */
+ uv_transform_properties(ot, 0);
+ uv_map_clip_correct_properties(ot);
}
/***************** Cylinder Project operator **************/
-static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4])
+static void uv_cylinder_project(float target[2],
+ float source[3],
+ float center[3],
+ float rotmat[4][4])
{
- float pv[3];
+ float pv[3];
- sub_v3_v3v3(pv, source, center);
- mul_m4_v3(rotmat, pv);
+ sub_v3_v3v3(pv, source, center);
+ mul_m4_v3(rotmat, pv);
- map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]);
+ map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]);
- /* split line is always zero */
- if (target[0] >= 1.0f)
- target[0] -= 1.0f;
+ /* split line is always zero */
+ if (target[0] >= 1.0f)
+ target[0] -= 1.0f;
}
static int cylinder_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- if (em->bm->totfacesel == 0) {
- continue;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- float center[3], rotmat[4][4];
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ float center[3], rotmat[4][4];
- uv_map_transform(C, op, rotmat);
- uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
+ uv_map_transform(C, op, rotmat);
+ uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
- }
+ uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
+ }
- uv_map_mirror(em, efa);
- }
+ uv_map_mirror(em, efa);
+ }
- uv_map_clip_correct(scene, obedit, op);
+ uv_map_clip_correct(scene, obedit, op);
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- MEM_freeN(objects);
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void UV_OT_cylinder_project(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Cylinder Projection";
- ot->idname = "UV_OT_cylinder_project";
- ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder";
+ /* identifiers */
+ ot->name = "Cylinder Projection";
+ ot->idname = "UV_OT_cylinder_project";
+ ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* api callbacks */
- ot->exec = cylinder_project_exec;
- ot->poll = ED_operator_uvmap;
+ /* api callbacks */
+ ot->exec = cylinder_project_exec;
+ ot->poll = ED_operator_uvmap;
- /* properties */
- uv_transform_properties(ot, 1);
- uv_map_clip_correct_properties(ot);
+ /* properties */
+ uv_transform_properties(ot, 1);
+ uv_map_clip_correct_properties(ot);
}
/******************* Cube Project operator ****************/
-static void uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, const float center[3])
+static void uvedit_unwrap_cube_project(BMesh *bm,
+ float cube_size,
+ bool use_select,
+ const float center[3])
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- float loc[3];
- int cox, coy;
-
- int cd_loop_uv_offset;
-
- cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (center) {
- copy_v3_v3(loc, center);
- }
- else {
- zero_v3(loc);
- }
-
- /* choose x,y,z axis for projection depending on the largest normal
- * component, but clusters all together around the center of map. */
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
- if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
-
- axis_dominant_v3(&cox, &coy, efa->no);
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]);
- luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]);
- }
- }
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ float loc[3];
+ int cox, coy;
+
+ int cd_loop_uv_offset;
+
+ cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ if (center) {
+ copy_v3_v3(loc, center);
+ }
+ else {
+ zero_v3(loc);
+ }
+
+ /* choose x,y,z axis for projection depending on the largest normal
+ * component, but clusters all together around the center of map. */
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
+ if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ axis_dominant_v3(&cox, &coy, efa->no);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]);
+ luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]);
+ }
+ }
}
static int cube_project_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
- const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (em->bm->totfacesel == 0) {
- continue;
- }
-
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- continue;
- }
-
- float bounds[2][3];
- float (*bounds_buf)[3] = NULL;
-
- if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
- bounds_buf = bounds;
- }
-
- float center[3];
- uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
-
- /* calculate based on bounds */
- float cube_size = cube_size_init;
- if (bounds_buf) {
- float dims[3];
- sub_v3_v3v3(dims, bounds[1], bounds[0]);
- cube_size = max_fff(UNPACK3(dims));
- cube_size = cube_size ? 2.0f / cube_size : 1.0f;
- if (ob_index == 0) {
- /* This doesn't fit well with, multiple objects. */
- RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
- }
- }
-
- uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
-
- uv_map_clip_correct(scene, obedit, op);
-
- DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
+ const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
+
+ float bounds[2][3];
+ float(*bounds_buf)[3] = NULL;
+
+ if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
+ bounds_buf = bounds;
+ }
+
+ float center[3];
+ uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
+
+ /* calculate based on bounds */
+ float cube_size = cube_size_init;
+ if (bounds_buf) {
+ float dims[3];
+ sub_v3_v3v3(dims, bounds[1], bounds[0]);
+ cube_size = max_fff(UNPACK3(dims));
+ cube_size = cube_size ? 2.0f / cube_size : 1.0f;
+ if (ob_index == 0) {
+ /* This doesn't fit well with, multiple objects. */
+ RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
+ }
+ }
+
+ uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
+
+ uv_map_clip_correct(scene, obedit, op);
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void UV_OT_cube_project(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Cube Projection";
- ot->idname = "UV_OT_cube_project";
- ot->description = "Project the UV vertices of the mesh over the six faces of a cube";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = cube_project_exec;
- ot->poll = ED_operator_uvmap;
-
- /* properties */
- RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on", 0.001f, 100.0f);
- uv_map_clip_correct_properties(ot);
+ /* identifiers */
+ ot->name = "Cube Projection";
+ ot->idname = "UV_OT_cube_project";
+ ot->description = "Project the UV vertices of the mesh over the six faces of a cube";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = cube_project_exec;
+ ot->poll = ED_operator_uvmap;
+
+ /* properties */
+ RNA_def_float(ot->srna,
+ "cube_size",
+ 1.0f,
+ 0.0f,
+ FLT_MAX,
+ "Cube Size",
+ "Size of the cube to project on",
+ 0.001f,
+ 100.0f);
+ uv_map_clip_correct_properties(ot);
}
/************************* Simple UVs for texture painting *****************/
void ED_uvedit_add_simple_uvs(Main *bmain, Scene *scene, Object *ob)
{
- Mesh *me = ob->data;
- bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
-
- BMesh *bm = BM_mesh_create(
- &bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
-
- /* turn sync selection off,
- * since we are not in edit mode we need to ensure only the uv flags are tested */
- scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
-
- ED_mesh_uv_texture_ensure(me, NULL);
-
- BM_mesh_bm_from_me(
- bm, me, (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
- /* select all uv loops first - pack parameters needs this to make sure charts are registered */
- ED_uvedit_select_all(bm);
- uvedit_unwrap_cube_project(bm, 1.0, false, NULL);
- /* set the margin really quickly before the packing operation*/
- scene->toolsettings->uvcalc_margin = 0.001f;
- uvedit_pack_islands(scene, ob, bm);
- BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
- BM_mesh_free(bm);
-
- if (sync_selection)
- scene->toolsettings->uv_flag |= UV_SYNC_SELECTION;
+ Mesh *me = ob->data;
+ bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ /* turn sync selection off,
+ * since we are not in edit mode we need to ensure only the uv flags are tested */
+ scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
+
+ ED_mesh_uv_texture_ensure(me, NULL);
+
+ BM_mesh_bm_from_me(bm,
+ me,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ /* select all uv loops first - pack parameters needs this to make sure charts are registered */
+ ED_uvedit_select_all(bm);
+ uvedit_unwrap_cube_project(bm, 1.0, false, NULL);
+ /* set the margin really quickly before the packing operation*/
+ scene->toolsettings->uvcalc_margin = 0.001f;
+ uvedit_pack_islands(scene, ob, bm);
+ BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
+ BM_mesh_free(bm);
+
+ if (sync_selection)
+ scene->toolsettings->uv_flag |= UV_SYNC_SELECTION;
}