code cleanup: rename BKE_tessmesh -> BKE_editmesh, rename EditDerivedBMesh.tc ->...
[blender-staging.git] / source / blender / editors / mesh / meshtools.c
index 6694371d6ae957219dbaf69b4b103815afca222c..9e70fe550bc930d301a1c22c4479c988a5c9ede4 100644 (file)
 
 /** \file blender/editors/mesh/meshtools.c
  *  \ingroup edmesh
+ *
+ * meshtools.c: no editmode (violated already :), mirror & join),
+ * tools operating on meshes
  */
 
-
-/*
- * meshtools.c: no editmode (violated already :), tools operating on meshes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
-
 #include "MEM_guardedalloc.h"
 
 #include "DNA_mesh_types.h"
-#include "DNA_view3d_types.h"
 #include "DNA_key_types.h"
 #include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_rand.h" /* for randome face sorting */
-#include "BLI_threads.h"
 
 
 #include "BKE_context.h"
 #include "BKE_mesh.h"
 #include "BKE_material.h"
 #include "BKE_report.h"
-#include "BKE_tessmesh.h"
+#include "BKE_editmesh.h"
 #include "BKE_multires.h"
 
-#include "BLO_sys_types.h" // for intptr_t support
-
 #include "ED_mesh.h"
 #include "ED_object.h"
 #include "ED_view3d.h"
 #include "WM_api.h"
 #include "WM_types.h"
 
-/* own include */
-#include "mesh_intern.h"
-#include "uvedit_intern.h"
-
 /* * ********************** no editmode!!! *********** */
 
 /*********************** JOIN ***************************/
@@ -113,7 +96,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
        CustomData vdata, edata, fdata, ldata, pdata;
 
        if (scene->obedit) {
-               BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
+               BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
                return OPERATOR_CANCELLED;
        }
        
@@ -161,10 +144,13 @@ int join_mesh_exec(bContext *C, wmOperator *op)
        }
        
        if (totvert > MESH_MAX_VERTS) {
-               BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert);
-               return OPERATOR_CANCELLED;              
+               BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is %ld", totvert, MESH_MAX_VERTS);
+               return OPERATOR_CANCELLED;
        }
 
+       /* remove tessface to ensure we don't hold references to invalid faces */
+       BKE_mesh_tessface_clear(me);
+
        /* new material indices and material array */
        matar = MEM_callocN(sizeof(void *) * totmat, "join_mesh matar");
        if (totmat) matmap = MEM_callocN(sizeof(int) * totmat, "join_mesh matmap");
@@ -196,7 +182,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
        }
        else if (haskey) {
                /* add a new key-block and add to the mesh */
-               key = me->key = add_key((ID *)me);
+               key = me->key = BKE_key_add((ID *)me);
                key->type = KEY_RELATIVE;
        }
        
@@ -243,23 +229,28 @@ 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 (kb = me->key->block.first; kb; kb = kb->next) {
+                                       /* for remapping KeyBlock.relative */
+                                       int      *index_map = MEM_mallocN(sizeof(int)        * me->key->totkey, __func__);
+                                       KeyBlock **kb_map   = MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__);
+
+                                       for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) {
+                                               BLI_assert(i < me->key->totkey);
+
+                                               kbn = BKE_keyblock_find_name(key, kb->name);
                                                /* if key doesn't exist in destination mesh, add it */
-                                               if (key_get_named_keyblock(key, kb->name) == NULL) {
-                                                       kbn = add_keyblock(key, kb->name);
-                                                       
-                                                       /* copy most settings */
-                                                       kbn->pos        = kb->pos;
-                                                       kbn->curval     = kb->curval;
-                                                       kbn->type       = kb->type;
-                                                       kbn->relative   = kb->relative;
-                                                       BLI_strncpy(kbn->vgroup, kb->vgroup, sizeof(kbn->vgroup));
-                                                       kbn->slidermin  = kb->slidermin;
-                                                       kbn->slidermax  = kb->slidermax;
+                                               if (kbn) {
+                                                       index_map[i] = BLI_findindex(&key->block, kbn);
+                                               }
+                                               else {
+                                                       index_map[i] = key->totkey;
+
+                                                       kbn = BKE_keyblock_add(key, kb->name);
+
+                                                       BKE_keyblock_copy_settings(kbn, kb);
 
                                                        /* adjust settings to fit (allocate a new data-array) */
                                                        kbn->data = MEM_callocN(sizeof(float) * 3 * totvert, "joined_shapekey");
-                                                       kbn->totelem = totvert; 
+                                                       kbn->totelem = totvert;
                
                                                        /* XXX 2.5 Animato */
 #if 0
@@ -270,20 +261,33 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                                                        }
 #endif
                                                }
+
+                                               kb_map[i] = kbn;
                                        }
+
+                                       /* remap relative index values */
+                                       for (kb = me->key->block.first, i = 0; kb; kb = kb->next, i++) {
+                                               if (LIKELY(kb->relative < me->key->totkey)) {  /* sanity check, should always be true */
+                                                       kb_map[i]->relative = index_map[kb->relative];
+                                               }
+                                       }
+
+                                       MEM_freeN(index_map);
+                                       MEM_freeN(kb_map);
                                }
                        }
                }
        }
        CTX_DATA_END;
-       
+
+
        /* setup new data for destination mesh */
-       memset(&vdata, 0, sizeof(vdata));
-       memset(&edata, 0, sizeof(edata));
-       memset(&fdata, 0, sizeof(fdata));
-       memset(&ldata, 0, sizeof(ldata));
-       memset(&pdata, 0, sizeof(pdata));
-       
+       CustomData_reset(&vdata);
+       CustomData_reset(&edata);
+       CustomData_reset(&fdata);
+       CustomData_reset(&ldata);
+       CustomData_reset(&pdata);
+
        mvert = CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
        medge = CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
        mloop = CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
@@ -304,6 +308,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                        me = base->object->data;
                        
                        if (me->totvert) {
+
+                               /* merge customdata flag */
+                               ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
+
                                /* standard data */
                                CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
                                CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
@@ -351,7 +359,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                                                        fp1 = ((float *)kb->data) + (vertofs * 3);
                                                        
                                                        /* check if this mesh has such a shapekey */
-                                                       okb = key_get_named_keyblock(me->key, kb->name);
+                                                       okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
+
                                                        if (okb) {
                                                                /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
                                                                fp2 = ((float *)(okb->data));
@@ -381,7 +390,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                                                        fp1 = ((float *)kb->data) + (vertofs * 3);
                                                        
                                                        /* check if this was one of the original shapekeys */
-                                                       okb = key_get_named_keyblock(nkey, kb->name);
+                                                       okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
                                                        if (okb) {
                                                                /* copy this mesh's shapekey to the destination shapekey */
                                                                fp2 = ((float *)(okb->data));
@@ -420,10 +429,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
 
                                        multiresModifier_prepare_join(scene, base->object, ob);
 
-                                       if ((mmd = get_multires_modifier(scene, base->object, TRUE))) {
-                                               ED_object_iter_other(bmain, base->object, TRUE,
-                                                                                        ED_object_multires_update_totlevels_cb,
-                                                                                        &mmd->totlvl);
+                                       if ((mmd = get_multires_modifier(scene, base->object, true))) {
+                                               ED_object_iter_other(bmain, base->object, true,
+                                                                    ED_object_multires_update_totlevels_cb,
+                                                                    &mmd->totlvl);
                                        }
                                }
                                
@@ -494,7 +503,11 @@ int join_mesh_exec(bContext *C, wmOperator *op)
        me->ldata = ldata;
        me->pdata = pdata;
 
-       mesh_update_customdata_pointers(me, TRUE); /* BMESH_TODO, check if this arg can be failse, non urgent - campbell */
+       /* tessface data removed above, no need to update */
+       BKE_mesh_update_customdata_pointers(me, false);
+
+       /* update normals in case objects with non-uniform scale are joined */
+       ED_mesh_calc_normals(me);
        
        /* old material array */
        for (a = 1; a <= ob->totcol; a++) {
@@ -543,11 +556,17 @@ int join_mesh_exec(bContext *C, wmOperator *op)
                MEM_freeN(nkey);
        }
        
-       DAG_scene_sort(bmain, scene);   // removed objects, need to rebuild dag before editmode call
+       /* ensure newly inserted keys are time sorted */
+       if (key && (key->type != KEY_RELATIVE)) {
+               BKE_key_sort(key);
+       }
+
+
+       DAG_relations_tag_update(bmain);   // removed objects, need to rebuild dag
 
 #if 0
-       ED_object_enter_editmode(C, EM_WAITCURSOR);
-       ED_object_exit_editmode(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+       ED_object_editmode_enter(C, EM_WAITCURSOR);
+       ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
 #else
        /* toggle editmode using lower level functions so this can be called from python */
        EDBM_mesh_make(scene->toolsettings, scene, ob);
@@ -602,12 +621,12 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
        }
        
        if (key == NULL) {
-               key = me->key = add_key((ID *)me);
+               key = me->key = BKE_key_add((ID *)me);
                key->type = KEY_RELATIVE;
 
                /* first key added, so it was the basis. initialize it with the existing mesh */
-               kb = add_keyblock(key, NULL);
-               mesh_to_key(me, kb);
+               kb = BKE_keyblock_add(key, NULL);
+               BKE_key_convert_from_mesh(me, kb);
        }
        
        /* now ready to add new keys from selected meshes */
@@ -623,7 +642,7 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
                                
                                if (!dm) continue;
                                        
-                               kb = add_keyblock(key, base->object->id.name + 2);
+                               kb = BKE_keyblock_add(key, base->object->id.name + 2);
                                
                                DM_to_meshkey(dm, me, kb);
                                
@@ -704,9 +723,9 @@ static void mesh_octree_add_nodes(MocNode **basetable, const float co[3], const
        float fx, fy, fz;
        int vx, vy, vz;
        
-       if ((finite(co[0]) == FALSE) ||
-           (finite(co[1]) == FALSE) ||
-           (finite(co[2]) == FALSE))
+       if ((finite(co[0]) == false) ||
+           (finite(co[1]) == false) ||
+           (finite(co[2]) == false))
        {
                return;
        }
@@ -769,7 +788,9 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, const float c
                                        return (*bt)->index[a];
                        }
                }
-               else return -1;
+               else {
+                       return -1;
+               }
        }
        if ( (*bt)->next)
                return mesh_octree_find_index(&(*bt)->next, mvert, co);
@@ -818,7 +839,7 @@ intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, const float co[3], char m
                                minmax_v3v3_v3(min, max, eve->co);
                        }
                }
-               else {          
+               else {
                        MVert *mvert;
                        int a;
                        
@@ -853,7 +874,7 @@ intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, const float co[3], char m
                                mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve));
                        }
                }
-               else {          
+               else {
                        MVert *mvert;
                        int a;
                        
@@ -888,7 +909,7 @@ int mesh_mirrtopo_table(Object *ob, char mode)
                }
        }
        else if (mode == 's') { /* start table */
-               ED_mesh_mirrtopo_init(ob->data, ob->mode, &mesh_topo_store, FALSE);
+               ED_mesh_mirrtopo_init(ob->data, ob->mode, &mesh_topo_store, false);
        }
        else if (mode == 'e') { /* end table */
                ED_mesh_mirrtopo_free(&mesh_topo_store);
@@ -935,9 +956,9 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
        intptr_t poinval;
        
        /* ignore nan verts */
-       if ((finite(co[0]) == FALSE) ||
-           (finite(co[1]) == FALSE) ||
-           (finite(co[2]) == FALSE))
+       if ((finite(co[0]) == false) ||
+           (finite(co[1]) == false) ||
+           (finite(co[2]) == false))
        {
                return NULL;
        }
@@ -1051,7 +1072,7 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float
 static unsigned int mirror_facehash(const void *ptr)
 {
        const MFace *mf = ptr;
-       int v0, v1;
+       unsigned int v0, v1;
 
        if (mf->v4) {
                v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4);
@@ -1152,14 +1173,17 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
  * Face selection in object mode,
  * currently only weight-paint and vertex-paint use this.
  *
- * \return boolean TRUE == Found
+ * \return boolean true == Found
  */
-int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
+bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size)
 {
        ViewContext vc;
+       Mesh *me = ob->data;
+
+       BLI_assert(me && GS(me->id.name) == ID_ME);
 
        if (!me || me->totpoly == 0)
-               return 0;
+               return false;
 
        view3d_set_viewcontext(C, &vc);
 
@@ -1167,7 +1191,7 @@ int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *in
                /* sample rect to increase chances of selecting, so that when clicking
                 * on an edge in the backbuf, we can still select a face */
 
-               int dummy_dist;
+               float dummy_dist;
                *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist, 0, NULL, NULL);
        }
        else {
@@ -1176,21 +1200,24 @@ int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *in
        }
 
        if ((*index) <= 0 || (*index) > (unsigned int)me->totpoly)
-               return 0;
+               return false;
 
        (*index)--;
 
-       return 1;
+       return true;
 }
 /**
  * Use when the back buffer stores face index values. but we want a vert.
  * This gets the face then finds the closest vertex to mval.
  */
-int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], unsigned int *index, int size)
+bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size)
 {
        unsigned int poly_index;
+       Mesh *me = ob->data;
+
+       BLI_assert(me && GS(me->id.name) == ID_ME);
 
-       if (ED_mesh_pick_face(C, me, mval, &poly_index, size)) {
+       if (ED_mesh_pick_face(C, ob, mval, &poly_index, size)) {
                Scene *scene = CTX_data_scene(C);
                struct ARegion *ar = CTX_wm_region(C);
 
@@ -1199,6 +1226,8 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
                int v_idx_best = -1;
 
                if (dm->getVertCo) {
+                       RegionView3D *rv3d = ar->regiondata;
+
                        /* find the vert closest to 'mval' */
                        const float mval_f[2] = {(float)mval[0],
                                                 (float)mval[1]};
@@ -1206,17 +1235,19 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
                        int fidx;
                        float len_best = FLT_MAX;
 
+                       ED_view3d_init_mats_rv3d(ob, rv3d);
+
                        fidx = mp->totloop - 1;
                        do {
                                float co[3], sco[2], len;
                                const int v_idx = me->mloop[mp->loopstart + fidx].v;
                                dm->getVertCo(dm, v_idx, co);
-                               mul_m4_v3(ob->obmat, co);
-                               project_float_noclip(ar, co, sco);
-                               len = len_squared_v2v2(mval_f, sco);
-                               if (len < len_best) {
-                                       len_best = len;
-                                       v_idx_best = v_idx;
+                               if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                                       len = len_manhattan_v2v2(mval_f, sco);
+                                       if (len < len_best) {
+                                               len_best = len;
+                                               v_idx_best = v_idx;
+                                       }
                                }
                        } while (fidx--);
                }
@@ -1225,44 +1256,110 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
 
                if (v_idx_best != -1) {
                        *index = v_idx_best;
-                       return 1;
+                       return true;
                }
        }
 
-       return 0;
+       return false;
 }
 
 /**
  * Vertex selection in object mode,
  * currently only weight paint uses this.
  *
- * \return boolean TRUE == Found
+ * \return boolean true == Found
  */
-int ED_mesh_pick_vert(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
+typedef struct VertPickData {
+       const MVert *mvert;
+       const float *mval_f;  /* [2] */
+       ARegion *ar;
+
+       /* runtime */
+       float len_best;
+       int v_idx_best;
+} VertPickData;
+
+static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3],
+                                       const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+       VertPickData *data = userData;
+       if ((data->mvert[index].flag & ME_HIDE) == 0) {
+               float sco[2];
+
+               if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) {
+                       const float len = len_manhattan_v2v2(data->mval_f, sco);
+                       if (len < data->len_best) {
+                               data->len_best = len;
+                               data->v_idx_best = index;
+                       }
+               }
+       }
+}
+bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size, bool use_zbuf)
 {
        ViewContext vc;
+       Mesh *me = ob->data;
+
+       BLI_assert(me && GS(me->id.name) == ID_ME);
 
        if (!me || me->totvert == 0)
-               return 0;
+               return false;
 
        view3d_set_viewcontext(C, &vc);
 
-       if (size > 0) {
-               /* sample rect to increase chances of selecting, so that when clicking
-                * on an face in the backbuf, we can still select a vert */
+       if (use_zbuf) {
+               if (size > 0) {
+                       /* sample rect to increase chances of selecting, so that when clicking
+                        * on an face in the backbuf, we can still select a vert */
+
+                       float dummy_dist;
+                       *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+               }
+               else {
+                       /* sample only on the exact position */
+                       *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+               }
+
+               if ((*index) <= 0 || (*index) > (unsigned int)me->totvert)
+                       return false;
 
-               int dummy_dist;
-               *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+               (*index)--;
        }
        else {
-               /* sample only on the exact position */
-               *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
-       }
+               /* derived mesh to find deformed locations */
+               DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH);
+               ARegion *ar = vc.ar;
+               RegionView3D *rv3d = ar->regiondata;
 
-       if ((*index) <= 0 || (*index) > (unsigned int)me->totvert)
-               return 0;
+               /* find the vert closest to 'mval' */
+               const float mval_f[2] = {(float)mval[0],
+                                        (float)mval[1]};
 
-       (*index)--;
+               VertPickData data = {0};
+
+               ED_view3d_init_mats_rv3d(ob, rv3d);
+
+               if (dm == NULL) {
+                       return false;
+               }
+
+               /* setup data */
+               data.mvert = me->mvert;
+               data.ar = ar;
+               data.mval_f = mval_f;
+               data.len_best = FLT_MAX;
+               data.v_idx_best = -1;
+
+               dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data);
+
+               dm->release(dm);
+
+               if (data.v_idx_best == -1) {
+                       return false;
+               }
+
+               *index = data.v_idx_best;
+       }
 
-       return 1;
+       return true;
 }