Fix UV Projection Center Calculation
authorCampbell Barton <ideasman42@gmail.com>
Fri, 17 Nov 2017 11:30:28 +0000 (22:30 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 17 Nov 2017 11:30:28 +0000 (22:30 +1100)
UV project mixed up global/local space,
3D cursor offset didn't take object scale into account.

Minor improvements:

- Match Cube Project 'center' behavior w/ sphere & cylinder.
- Add active-element center.
- Wrap UV's in Cube Project based on center instead of first vertex.

source/blender/editors/include/ED_uvedit.h
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c

index 535683823bf7260763cb51b51db799d77cbb04d6..354a9655a48051246a8767c65e05abc1c0cef42d 100644 (file)
@@ -101,7 +101,8 @@ void ED_uvedit_live_unwrap_end(short cancel);
 
 void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
 void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
-void ED_uvedit_unwrap_cube_project(struct Object *ob, struct BMesh *bm, float cube_size, bool use_select);
+void ED_uvedit_unwrap_cube_project(
+        struct BMesh *bm, float cube_size, bool use_select, const float center[3]);
 
 /* single call up unwrap using scene settings, used for edge tag unwrapping */
 void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
index d14b75149c9f55256fe9dff95496312b8f040b66..ae6dbbf440c63d8ce3b4ee090b7068012ed8ef3a 100644 (file)
@@ -5904,7 +5904,7 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
                }));
        /* select all uv loops first - pack parameters needs this to make sure charts are registered */
        ED_uvedit_select_all(bm);
-       ED_uvedit_unwrap_cube_project(ob, bm, 1.0, false);
+       ED_uvedit_unwrap_cube_project(bm, 1.0, false, NULL);
        /* set the margin really quickly before the packing operation*/
        scene->toolsettings->uvcalc_margin = 0.001f;
        ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
index b639a493b0235cc331e45a83739bb4c85f68cdab..ce7632436020b563b2704f43d97a5b0890fc54c8 100644 (file)
@@ -868,12 +868,10 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit)
 #define POLAR_ZX    0
 #define POLAR_ZY    1
 
-static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, 
-                                    Object *ob, BMEditMesh *em)
+static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, BMEditMesh *em)
 {
-       const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS;
-
        /* only operates on the edit object - this is all that's needed now */
+       const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS;
 
        switch (around) {
                case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
@@ -884,7 +882,7 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result,
                        float min[3], max[3];
 
                        INIT_MINMAX(min, max);
-                       
+
                        BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
                                if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
                                        BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -895,15 +893,41 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result,
                        mid_v3_v3v3(result, min, max);
                        break;
                }
+               case V3D_AROUND_CENTER_MEAN:
+               {
+                       BMFace *efa;
+                       BMLoop *l;
+                       BMIter iter, liter;
+                       int result_accum = 0;
+
+                       zero_v3(result);
+                       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+                               if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+                                       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+                                               add_v3_v3(result, l->v->co);
+                                               result_accum += 1;
+                                       }
+                               }
+                       }
+                       mul_v3_fl(result, 1.0f / (float)result_accum);
+                       break;
+               }
                case V3D_AROUND_CURSOR:  /* cursor center */
                {
-                       const float *curs = ED_view3d_cursor3d_get(scene, v3d);
-                       /* shift to objects world */
-                       sub_v3_v3v3(result, curs, ob->obmat[3]);
+                       invert_m4_m4(ob->imat, ob->obmat);
+                       mul_v3_m4v3(result, ob->imat, ED_view3d_cursor3d_get(scene, v3d));
                        break;
                }
+               case V3D_AROUND_ACTIVE:
+               {
+                       BMEditSelection ese;
+                       if (BM_select_history_active_get(em->bm, &ese)) {
+                               BM_editselection_center(&ese, result);
+                               break;
+                       }
+                       ATTR_FALLTHROUGH;
+               }
                case V3D_AROUND_LOCAL_ORIGINS:  /* object center */
-               case V3D_AROUND_CENTER_MEAN:    /* multiple objects centers, only one object here*/
                default:
                        zero_v3(result);
                        break;
@@ -958,13 +982,10 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec
        mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
 }
 
-static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])
+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 */
-       Scene *scene = CTX_data_scene(C);
        Object *obedit = CTX_data_edit_object(C);
-       BMEditMesh *em = BKE_editmesh_from_object(obedit);
-       View3D *v3d = CTX_wm_view3d(C);
        RegionView3D *rv3d = CTX_wm_region_view3d(C);
        /* common operator properties */
        int align = RNA_enum_get(op->ptr, "align");
@@ -972,8 +993,6 @@ static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float
        float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") : 1.0f;
        float upangledeg, sideangledeg;
 
-       uv_map_transform_center(scene, v3d, center, obedit, em);
-
        if (direction == VIEW_ON_EQUATOR) {
                upangledeg = 90.0f;
                sideangledeg = 0.0f;
@@ -1476,6 +1495,7 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
        Object *obedit = CTX_data_edit_object(C);
+       View3D *v3d = CTX_wm_view3d(C);
        BMEditMesh *em = BKE_editmesh_from_object(obedit);
        BMFace *efa;
        BMLoop *l;
@@ -1493,7 +1513,8 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
 
        cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 
-       uv_map_transform(C, op, center, rotmat);
+       uv_map_transform(C, op, rotmat);
+       uv_map_transform_center(scene, v3d, center, obedit, em);
 
        BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
                if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
@@ -1555,6 +1576,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
        Object *obedit = CTX_data_edit_object(C);
+       View3D *v3d = CTX_wm_view3d(C);
        BMEditMesh *em = BKE_editmesh_from_object(obedit);
        BMFace *efa;
        BMLoop *l;
@@ -1572,12 +1594,13 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
 
        cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 
-       uv_map_transform(C, op, center, rotmat);
+       uv_map_transform(C, op, rotmat);
+       uv_map_transform_center(scene, v3d, center, obedit, em);
 
        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);
 
@@ -1616,68 +1639,79 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
 
 /******************* Cube Project operator ****************/
 
-void ED_uvedit_unwrap_cube_project(Object *ob, BMesh *bm, float cube_size, bool use_select)
+void ED_uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, const float center[3])
 {
        BMFace *efa;
        BMLoop *l;
        BMIter iter, liter;
        /* MTexPoly *tf; */ /* UNUSED */
        MLoopUV *luv;
-       float *loc, dx, dy;
+       float loc[3];
        int cox, coy;
 
        int cd_loop_uv_offset;
 
        cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
 
-       loc = ob->obmat[3];
+       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) {
-               int first = 1;
-
                /* 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);
 
-               dx = dy = 0;
+               float uv_delta[2] = {0.0f};
+
                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]);
 
-                       luv->uv[0] = 0.5f + 0.5f * cube_size * (loc[cox] + l->v->co[cox]);
-                       luv->uv[1] = 0.5f + 0.5f * cube_size * (loc[coy] + l->v->co[coy]);
-
-                       if (first) {
-                               dx = floor(luv->uv[0]);
-                               dy = floor(luv->uv[1]);
-                               first = 0;
-                       }
+                       add_v2_v2(uv_delta, luv->uv);
+               }
 
+               mul_v2_fl(uv_delta, 1.0f / (float)efa->len);
+               uv_delta[0] = floor(uv_delta[0]);
+               uv_delta[1] = floor(uv_delta[1]);
 
-                       luv->uv[0] -= dx;
-                       luv->uv[1] -= dy;
+               if (uv_delta[0] != 0.0f || uv_delta[1] != 0.0f) {
+                       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] -= uv_delta[0];
+                               luv->uv[1] -= uv_delta[1];
+                       }
                }
        }
-
 }
 
 static int cube_project_exec(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
+       View3D *v3d = CTX_wm_view3d(C);
        Object *obedit = CTX_data_edit_object(C);
        BMEditMesh *em = BKE_editmesh_from_object(obedit);
        float cube_size = RNA_float_get(op->ptr, "cube_size");
+       float center[3];
 
        /* add uvs if they don't exist yet */
        if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
                return OPERATOR_CANCELLED;
        }
 
-       ED_uvedit_unwrap_cube_project(obedit, em->bm, cube_size, true);
+       uv_map_transform_center(scene, v3d, center, obedit, em);
+
+       ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
+
        uv_map_clip_correct(scene, obedit, em, op);
 
        DAG_id_tag_update(obedit->data, 0);