Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / mesh / meshtools.c
index 8345812..786b27e 100644 (file)
@@ -286,7 +286,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
                return OPERATOR_CANCELLED;
        }
-       
+
        /* ob is the object we are adding geometry to */
        if (!ob || ob->type != OB_MESH) {
                BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
@@ -306,23 +306,23 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                        totloop += me->totloop;
                        totpoly += me->totpoly;
                        totmat += base->object->totcol;
-                       
+
                        if (base->object == ob)
                                ok = true;
-                       
+
                        /* check for shapekeys */
                        if (me->key)
                                haskey++;
                }
        }
        CTX_DATA_END;
-       
-       /* that way the active object is always selected */ 
+
+       /* that way the active object is always selected */
        if (ok == false) {
                BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
                return OPERATOR_CANCELLED;
        }
-       
+
        /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
        me = (Mesh *)ob->data;
        key = me->key;
@@ -331,7 +331,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
                return OPERATOR_CANCELLED;
        }
-       
+
        if (totvert > MESH_MAX_VERTS) {
                BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is %ld", totvert, MESH_MAX_VERTS);
                return OPERATOR_CANCELLED;
@@ -346,23 +346,23 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap");
        }
        totcol = ob->totcol;
-       
+
        /* obact materials in new main array, is nicer start! */
        for (a = 0; a < ob->totcol; a++) {
                matar[a] = give_current_material(ob, a + 1);
                id_us_plus((ID *)matar[a]);
                /* increase id->us : will be lowered later */
        }
-       
+
        /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
         *  with arrays that are large enough to hold shapekey data for all meshes
-        * -    if destination mesh didn't have shapekeys, but we encountered some in the meshes we're 
+        * -    if destination mesh didn't have shapekeys, but we encountered some in the meshes we're
         *      joining, set up a new keyblock and assign to the mesh
         */
        if (key) {
                /* make a duplicate copy that will only be used here... (must remember to free it!) */
                nkey = BKE_key_copy(bmain, key);
-               
+
                /* for all keys in old block, clear data-arrays */
                for (kb = key->block.first; kb; kb = kb->next) {
                        if (kb->data) MEM_freeN(kb->data);
@@ -375,14 +375,14 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                key = me->key = BKE_key_add((ID *)me);
                key->type = KEY_RELATIVE;
        }
-       
+
        /* first pass over objects - copying materials and vertexgroups across */
        CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
        {
                /* only act if a mesh, and not the one we're joining to */
                if ((ob != base->object) && (base->object->type == OB_MESH)) {
                        me = base->object->data;
-                       
+
                        /* Join this object's vertex groups to the base one's */
                        for (dg = base->object->defbase.first; dg; dg = dg->next) {
                                /* See if this group exists in the object (if it doesn't, add it to the end) */
@@ -394,8 +394,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                        }
                        if (ob->defbase.first && ob->actdef == 0)
                                ob->actdef = 1;
-                       
-                       
+
+
                        if (me->totvert) {
                                /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
                                if (totcol < MAXMAT) {
@@ -419,7 +419,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                                                }
                                        }
                                }
-                               
+
                                /* if this mesh has shapekeys, check if destination mesh already has matching entries too */
                                if (me->key && key) {
                                        /* for remapping KeyBlock.relative */
@@ -481,7 +481,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
        edgeofs = 0;
        loopofs = 0;
        polyofs = 0;
-       
+
        /* inverse transform for all selected meshes in this object */
        invert_m4_m4(imat, ob->obmat);
 
@@ -522,10 +522,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                }
        }
        CTX_DATA_END;
-       
+
        /* return to mesh we're merging to */
        me = ob->data;
-       
+
        CustomData_free(&me->vdata, me->totvert);
        CustomData_free(&me->edata, me->totedge);
        CustomData_free(&me->ldata, me->totloop);
@@ -546,7 +546,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
 
        /* update normals in case objects with non-uniform scale are joined */
        BKE_mesh_calc_normals(me);
-       
+
        /* old material array */
        for (a = 1; a <= ob->totcol; a++) {
                ma = ob->mat[a - 1];
@@ -573,13 +573,13 @@ int join_mesh_exec(bContext *C, wmOperator *op)
 
        /* other mesh users */
        test_all_objects_materials(bmain, (ID *)me);
-       
+
        /* free temp copy of destination shapekeys (if applicable) */
        if (nkey) {
                /* We can assume nobody is using that ID currently. */
                BKE_libblock_free_ex(bmain, nkey, false, false);
        }
-       
+
        /* ensure newly inserted keys are time sorted */
        if (key && (key->type != KEY_RELATIVE)) {
                BKE_key_sort(key);
@@ -599,7 +599,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
 
 /*********************** JOIN AS SHAPES ***************************/
 
-/* Append selected meshes vertex locations as shapes of the active mesh, 
+/* Append selected meshes vertex locations as shapes of the active mesh,
  * return 0 if no join is made (error) and 1 of the join is done */
 
 int join_mesh_shapes_exec(bContext *C, wmOperator *op)
@@ -613,14 +613,14 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
        Key *key = me->key;
        KeyBlock *kb;
        bool ok = false, nonequal_verts = false;
-       
+
        CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
        {
                if (base->object == ob) continue;
-               
+
                if (base->object->type == OB_MESH) {
                        selme = (Mesh *)base->object->data;
-                       
+
                        if (selme->totvert == me->totvert)
                                ok = true;
                        else
@@ -628,7 +628,7 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
                }
        }
        CTX_DATA_END;
-       
+
        if (!ok) {
                if (nonequal_verts)
                        BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
@@ -636,7 +636,7 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
                        BKE_report(op->reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join");
                return OPERATOR_CANCELLED;
        }
-       
+
        if (key == NULL) {
                key = me->key = BKE_key_add((ID *)me);
                key->type = KEY_RELATIVE;
@@ -645,32 +645,32 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
                kb = BKE_keyblock_add(key, NULL);
                BKE_keyblock_convert_from_mesh(me, kb);
        }
-       
+
        /* now ready to add new keys from selected meshes */
        CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
        {
                if (base->object == ob) continue;
-               
+
                if (base->object->type == OB_MESH) {
                        selme = (Mesh *)base->object->data;
-                       
+
                        if (selme->totvert == me->totvert) {
                                dm = mesh_get_derived_deform(depsgraph, scene, base->object, CD_MASK_BAREMESH);
-                               
+
                                if (!dm) continue;
-                                       
+
                                kb = BKE_keyblock_add(key, base->object->id.name + 2);
-                               
+
                                DM_to_meshkey(dm, me, kb);
-                               
+
                                dm->release(dm);
                        }
                }
        }
        CTX_DATA_END;
-       
+
        WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-       
+
        return OPERATOR_FINISHED;
 }
 
@@ -707,6 +707,30 @@ int ED_mesh_mirror_topo_table(
        return 0;
 }
 
+/* mode is 's' start, or 'e' end, or 'u' use */
+/* if end, ob can be NULL */
+/* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */
+int ED_mesh_mirror_topo_table__real_mesh(
+        Object *ob, Mesh *mesh, char mode)
+{
+       if (mode == 'u') {        /* use table */
+               if (ED_mesh_mirrtopo_recalc_check__real_mesh(ob->data, mesh, &mesh_topo_store)) {
+                       ED_mesh_mirror_topo_table__real_mesh(ob, mesh, 's');
+               }
+       }
+       else if (mode == 's') { /* start table */
+               ED_mesh_mirrtopo_init__real_mesh(ob->data, mesh, &mesh_topo_store, false);
+       }
+       else if (mode == 'e') { /* end table */
+               ED_mesh_mirrtopo_free(&mesh_topo_store);
+       }
+       else {
+               BLI_assert(0);
+       }
+
+       return 0;
+}
+
 /** \} */
 
 
@@ -715,12 +739,12 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index
        Mesh *me = ob->data;
        MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
        float vec[3];
-       
+
        mvert = &mvert[index];
        vec[0] = -mvert->co[0];
        vec[1] = mvert->co[1];
        vec[2] = mvert->co[2];
-       
+
        return ED_mesh_mirror_spatial_table(ob, NULL, dm, vec, 'u');
 }
 
@@ -742,11 +766,43 @@ int mesh_get_x_mirror_vert(Object *ob, DerivedMesh *dm, int index, const bool us
        }
 }
 
+static int mesh_get_x_mirror_vert_spatial__real_mesh(Object *ob, Mesh *mesh, int index)
+{
+       Mesh *me = ob->data;
+       MVert *mvert = mesh ? mesh->mvert : me->mvert;
+       float vec[3];
+
+       mvert = &mvert[index];
+       vec[0] = -mvert->co[0];
+       vec[1] = mvert->co[1];
+       vec[2] = mvert->co[2];
+
+       return ED_mesh_mirror_spatial_table__real_mesh(ob, NULL, mesh, vec, 'u');
+}
+
+static int mesh_get_x_mirror_vert_topo__real_mesh(Object *ob, Mesh *mesh, int index)
+{
+       if (ED_mesh_mirror_topo_table__real_mesh(ob, mesh, 'u') == -1)
+               return -1;
+
+       return mesh_topo_store.index_lookup[index];
+}
+
+int mesh_get_x_mirror_vert__real_mesh(Object *ob, Mesh *mesh, int index, const bool use_topology)
+{
+       if (use_topology) {
+               return mesh_get_x_mirror_vert_topo__real_mesh(ob, mesh, index);
+       }
+       else {
+               return mesh_get_x_mirror_vert_spatial__real_mesh(ob, mesh, index);
+       }
+}
+
 static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
 {
        float vec[3];
        int i;
-       
+
        /* ignore nan verts */
        if ((isfinite(co[0]) == false) ||
            (isfinite(co[1]) == false) ||
@@ -754,11 +810,11 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
        {
                return NULL;
        }
-       
+
        vec[0] = -co[0];
        vec[1] = co[1];
        vec[2] = co[2];
-       
+
        i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u');
        if (i != -1) {
                return BM_vert_at_index(em->bm, i);
@@ -775,14 +831,14 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *e
        if (index == -1) {
                BMIter iter;
                BMVert *v;
-               
+
                index = 0;
                BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
                        if (v == eve)
                                break;
                        index++;
                }
-               
+
                if (index == em->bm->totvert) {
                        return NULL;
                }
@@ -793,7 +849,7 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *e
        if (poinval != -1)
                return (BMVert *)(poinval);
        return NULL;
-}      
+}
 
 BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
 {
@@ -865,19 +921,19 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float
        {
                BMIter iter;
                BMFace *efa;
-               
+
                BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
                        uv_poly_center(efa, cent, cd_loop_uv_offset);
-                       
+
                        if ( (fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f) ) {
                                BMIter liter;
                                BMLoop *l;
-                               
+
                                BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
                                        MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
                                        if ( (fabsf(luv->uv[0] - vec[0]) < 0.001f) && (fabsf(luv->uv[1] - vec[1]) < 0.001f) ) {
                                                return luv->uv;
-                                                               
+
                                        }
                                }
                        }
@@ -926,7 +982,7 @@ static int mirror_facerotation(MFace *a, MFace *b)
                else if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3)
                        return 2;
        }
-       
+
        return -1;
 }
 
@@ -991,7 +1047,67 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm)
 
        BLI_ghash_free(fhash, NULL, NULL);
        MEM_freeN(mirrorverts);
-       
+
+       return mirrorfaces;
+}
+
+/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */
+int *mesh_get_x_mirror_faces__real_mesh(Object *ob, BMEditMesh *em, Mesh *mesh)
+{
+       Mesh *me = ob->data;
+       MVert *mv, *mvert;
+       MFace mirrormf, *mf, *hashmf, *mface;
+       GHash *fhash;
+       int *mirrorverts, *mirrorfaces;
+
+       BLI_assert(em == NULL);  /* Does not work otherwise, currently... */
+
+       const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+       const int totvert = mesh ? mesh->totvert : me->totvert;
+       const int totface = mesh ? mesh->totface : me->totface;
+       int a;
+
+       mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts");
+       mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces");
+
+       mvert = mesh ? mesh->mvert : me->mvert;
+       mface = mesh ? mesh->mface : me->mface;
+
+       ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, NULL, 's');
+
+       for (a = 0, mv = mvert; a < totvert; a++, mv++)
+               mirrorverts[a] = mesh_get_x_mirror_vert__real_mesh(ob, mesh, a, use_topology);
+
+       ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, NULL, 'e');
+
+       fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
+       for (a = 0, mf = mface; a < totface; a++, mf++)
+               BLI_ghash_insert(fhash, mf, mf);
+
+       for (a = 0, mf = mface; a < totface; a++, mf++) {
+               mirrormf.v1 = mirrorverts[mf->v3];
+               mirrormf.v2 = mirrorverts[mf->v2];
+               mirrormf.v3 = mirrorverts[mf->v1];
+               mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0;
+
+               /* make sure v4 is not 0 if a quad */
+               if (mf->v4 && mirrormf.v4 == 0) {
+                       SWAP(unsigned int, mirrormf.v1, mirrormf.v3);
+                       SWAP(unsigned int, mirrormf.v2, mirrormf.v4);
+               }
+
+               hashmf = BLI_ghash_lookup(fhash, &mirrormf);
+               if (hashmf) {
+                       mirrorfaces[a * 2] = hashmf - mface;
+                       mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
+               }
+               else
+                       mirrorfaces[a * 2] = -1;
+       }
+
+       BLI_ghash_free(fhash, NULL, NULL);
+       MEM_freeN(mirrorverts);
+
        return mirrorfaces;
 }
 
@@ -1038,21 +1154,22 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
 static void ed_mesh_pick_face_vert__mpoly_find(
         /* context */
         struct ARegion *ar, const float mval[2],
-        /* mesh data */
-        DerivedMesh *dm, MPoly *mp, MLoop *mloop,
+        /* mesh data (evaluated) */
+        const MPoly *mp,
+        const MVert *mvert, const MLoop *mloop,
         /* return values */
         float *r_len_best, int *r_v_idx_best)
 {
        const MLoop *ml;
        int j = mp->totloop;
        for (ml = &mloop[mp->loopstart]; j--; ml++) {
-               float co[3], sco[2], len;
+               float sco[2];
                const int v_idx = ml->v;
-               dm->getVertCo(dm, v_idx, co);
+               const float *co = mvert[v_idx].co;
                if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-                       len = len_manhattan_v2v2(mval, sco);
-                       if (len < *r_len_best) {
-                               *r_len_best = len;
+                       const float len_test = len_manhattan_v2v2(mval, sco);
+                       if (len_test < *r_len_best) {
+                               *r_len_best = len_test;
                                *r_v_idx_best = v_idx;
                        }
                }
@@ -1075,7 +1192,7 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
                struct ARegion *ar = CTX_wm_region(C);
 
                /* derived mesh to find deformed locations */
-               DerivedMesh *dm = mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
+               Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
 
                int v_idx_best = ORIGINDEX_NONE;
 
@@ -1083,36 +1200,38 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
                const float mval_f[2] = {UNPACK2(mval)};
                float len_best = FLT_MAX;
 
-               MPoly *dm_mpoly;
-               MLoop *dm_mloop;
-               unsigned int dm_mpoly_tot;
+               MPoly *me_eval_mpoly;
+               MLoop *me_eval_mloop;
+               MVert *me_eval_mvert;
+               unsigned int me_eval_mpoly_len;
                const int *index_mp_to_orig;
 
-               dm_mpoly = dm->getPolyArray(dm);
-               dm_mloop = dm->getLoopArray(dm);
+               me_eval_mpoly = me_eval->mpoly;
+               me_eval_mloop = me_eval->mloop;
+               me_eval_mvert = me_eval->mvert;
 
-               dm_mpoly_tot = dm->getNumPolys(dm);
+               me_eval_mpoly_len = me_eval->totpoly;
 
-               index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+               index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
 
                /* tag all verts using this face */
                if (index_mp_to_orig) {
                        unsigned int i;
 
-                       for (i = 0; i < dm_mpoly_tot; i++) {
+                       for (i = 0; i < me_eval_mpoly_len; i++) {
                                if (index_mp_to_orig[i] == poly_index) {
                                        ed_mesh_pick_face_vert__mpoly_find(
                                                ar, mval_f,
-                                               dm, &dm_mpoly[i], dm_mloop,
+                                               &me_eval_mpoly[i], me_eval_mvert, me_eval_mloop,
                                                &len_best, &v_idx_best);
                                }
                        }
                }
                else {
-                       if (poly_index < dm_mpoly_tot) {
+                       if (poly_index < me_eval_mpoly_len) {
                                ed_mesh_pick_face_vert__mpoly_find(
                                        ar, mval_f,
-                                       dm, &dm_mpoly[poly_index], dm_mloop,
+                                       &me_eval_mpoly[poly_index], me_eval_mvert, me_eval_mloop,
                                        &len_best, &v_idx_best);
                        }
                }
@@ -1120,15 +1239,12 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
                /* map 'dm -> me' index if possible */
                if (v_idx_best != ORIGINDEX_NONE) {
                        const int *index_mv_to_orig;
-
-                       index_mv_to_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
+                       index_mv_to_orig = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
                        if (index_mv_to_orig) {
                                v_idx_best = index_mv_to_orig[v_idx_best];
                        }
                }
 
-               dm->release(dm);
-
                if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) {
                        *index = v_idx_best;
                        return true;