Merging r39717 through r39983 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / mesh / editmesh.c
index c3f1637d3aff5779b40ddbeb7009a9bfed20e6ef..e371c346f362c7ddddb8efb9f193d667e736d502 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/mesh/editmesh.c
+ *  \ingroup edmesh
+ */
+
+
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "MEM_guardedalloc.h"
 
-#include "PIL_time.h"
-
-#include "DNA_customdata_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
 #include "DNA_object_types.h"
-#include "DNA_object_force.h"
-#include "DNA_screen_types.h"
 #include "DNA_key_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_userdef_types.h"
 
 #include "BLI_blenlib.h"
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_editVert.h"
 #include "BLI_dynstr.h"
 #include "BLI_rand.h"
+#include "BLI_utildefines.h"
 
-#include "BKE_cloth.h"
+#include "BKE_DerivedMesh.h"
 #include "BKE_context.h"
-#include "BKE_customdata.h"
 #include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
 #include "BKE_global.h"
 #include "BKE_key.h"
-#include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_material.h"
 #include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
 #include "BKE_paint.h"
-#include "BKE_pointcache.h"
-#include "BKE_softbody.h"
-#include "BKE_texture.h"
-#include "BKE_utildefines.h"
-
-#include "LBM_fluidsim.h"
-
+#include "BKE_report.h"
+#include "BKE_multires.h"
 
 #include "ED_mesh.h"
 #include "ED_object.h"
-#include "ED_retopo.h"
 #include "ED_screen.h"
 #include "ED_util.h"
 #include "ED_view3d.h"
@@ -100,8 +85,8 @@ editmesh.c:
 */
 
 /* XXX */
-static void BIF_undo_push() {}
-static void error() {}
+static void BIF_undo_push(const char *UNUSED(arg)) {}
+static void error(const char *UNUSED(arg)) {}
 
 
 /* ***************** HASH ********************* */
@@ -113,7 +98,7 @@ static void error() {}
 
 /* ************ ADD / REMOVE / FIND ****************** */
 
-static void *calloc_em(EditMesh *em, size_t size, size_t nr)
+static void *calloc_em(EditMesh *UNUSED(em), size_t size, size_t nr)
 {
        return calloc(size, nr);
 }
@@ -279,7 +264,7 @@ EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *exampl
                        eed->h |= (example->h & EM_FGON);
                }
        }
-
+       
        return eed;
 }
 
@@ -400,6 +385,7 @@ EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, Ed
                efa->mat_nr= example->mat_nr;
                efa->flag= example->flag;
                CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
+               CustomData_em_validate_data(&em->fdata, efa->data, efa->v4 ? 4 : 3);
        }
        else {
                efa->mat_nr= em->mat_nr;
@@ -411,12 +397,12 @@ EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, Ed
        em->totface++;
        
        if(efa->v4) {
-               CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
-               CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+               normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+               cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
        }
        else {
-               CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
-               CalcCent3f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
+               normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
+               cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
        }
 
        return efa;
@@ -469,19 +455,19 @@ int editface_containsEdge(EditFace *efa, EditEdge *eed)
 /* ************************ stuct EditMesh manipulation ***************************** */
 
 /* fake callocs for fastmalloc below */
-static void *calloc_fastvert(EditMesh *em, size_t size, size_t nr)
+static void *calloc_fastvert(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
 {
        EditVert *eve= em->curvert++;
        eve->fast= 1;
        return eve;
 }
-static void *calloc_fastedge(EditMesh *em, size_t size, size_t nr)
+static void *calloc_fastedge(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
 {
        EditEdge *eed= em->curedge++;
        eed->fast= 1;
        return eed;
 }
-static void *calloc_fastface(EditMesh *em, size_t size, size_t nr)
+static void *calloc_fastface(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
 {
        EditFace *efa= em->curface++;
        efa->fast= 1;
@@ -576,7 +562,8 @@ void free_editMesh(EditMesh *em)
        em->allfaces= em->curface= NULL;
        
        mesh_octree_table(NULL, NULL, NULL, 'e');
-       
+       mesh_mirrtopo_table(NULL, 'e');
+
        em->totvert= em->totedge= em->totface= 0;
 
 // XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
@@ -612,18 +599,18 @@ static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
        if(efa1==efa2) return;
        
        inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
-       if(inp<0.999 && inp >-0.999) eed->f2= 1;
+       if(inp<0.999f && inp >-0.999f) eed->f2= 1;
                
-       if(efa1->v4) CalcCent4f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
-       else CalcCent3f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
-       if(efa2->v4) CalcCent4f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
-       else CalcCent3f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
+       if(efa1->v4) cent_quad_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
+       else cent_tri_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
+       if(efa2->v4) cent_quad_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
+       else cent_tri_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
        
-       VecSubf(cent1, cent2, cent1);
-       Normalize(cent1);
+       sub_v3_v3v3(cent1, cent2, cent1);
+       normalize_v3(cent1);
        inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2]; 
 
-       if(inp < -0.001 ) eed->f1= 1;
+       if(inp < -0.001f) eed->f1= 1;
 }
 
 #if 0
@@ -753,11 +740,12 @@ void make_editMesh(Scene *scene, Object *ob)
        KeyBlock *actkey;
        EditMesh *em;
        EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
-       EditFace *efa;
+       EditFace *efa, *efa_last_sel= NULL;
        EditEdge *eed;
        EditSelection *ese;
-       float *co;
+       float *co, (*keyco)[3]= NULL;
        int tot, a, eekadoodle= 0;
+       const short is_paint_sel= paint_facesel_test(ob);
 
        if(me->edit_mesh==NULL)
                me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh");
@@ -777,17 +765,20 @@ void make_editMesh(Scene *scene, Object *ob)
                return;
        }
        
+       if(ob->actcol > 0)
+               em->mat_nr= ob->actcol-1;
+
        /* initialize fastmalloc for editmesh */
        init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
 
        actkey = ob_get_keyblock(ob);
        if(actkey) {
-               tot= actkey->totelem;
                /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
                undo_editmode_clear();
+               keyco= actkey->data;
+               em->shapenr= ob->shapenr;
        }
 
-       
        /* make editverts */
        CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
        mvert= me->mvert;
@@ -797,17 +788,19 @@ void make_editMesh(Scene *scene, Object *ob)
                
                co= mvert->co;
 
+               /* edit the shape key coordinate if available */
+               if(keyco && a < actkey->totelem)
+                       co= keyco[a];
+
                eve= addvertlist(em, co, NULL);
                evlist[a]= eve;
                
-               // face select sets selection in next loop
-               if(!paint_facesel_test(ob))
+               /* face select sets selection in next loop */
+               if(!is_paint_sel)
                        eve->f |= (mvert->flag & 1);
                
-               if (mvert->flag & ME_HIDE) eve->h= 1;           
-               eve->no[0]= mvert->no[0]/32767.0;
-               eve->no[1]= mvert->no[1]/32767.0;
-               eve->no[2]= mvert->no[2]/32767.0;
+               if (mvert->flag & ME_HIDE) eve->h= 1;
+               normal_short_to_float_v3(eve->no, mvert->no);
 
                eve->bweight= ((float)mvert->bweight)/255.0f;
 
@@ -876,15 +869,21 @@ void make_editMesh(Scene *scene, Object *ob)
                                        if(mface->flag & ME_FACE_SEL) {
                                                efa->f |= SELECT;
                                                
-                                               if(paint_facesel_test(ob)) {
+                                               if(is_paint_sel) {
                                                        EM_select_face(efa, 1); /* flush down */
                                                }
+
+                                               efa_last_sel= efa;
                                        }
                                }
                        }
                }
        }
        
+       if(EM_get_actFace(em, 0)==NULL && efa_last_sel) {
+               EM_set_actFace(em, efa_last_sel);
+       }
+
        if(eekadoodle)
                error("This Mesh has old style edgecodes, please put it in the bugtracker!");
        
@@ -923,9 +922,9 @@ void make_editMesh(Scene *scene, Object *ob)
 }
 
 /* makes Mesh out of editmesh */
-void load_editMesh(Scene *scene, Object *ob)
+void load_editMesh(Scene *scene, Object *obedit)
 {
-       Mesh *me= ob->data;
+       Mesh *me= obedit->data;
        MVert *mvert, *oldverts;
        MEdge *medge;
        MFace *mface;
@@ -935,7 +934,7 @@ void load_editMesh(Scene *scene, Object *ob)
        EditFace *efa, *efa_act;
        EditEdge *eed;
        EditSelection *ese;
-       float *fp, *newkey, *oldkey, nor[3];
+       float *fp, *newkey, *oldkey;
        int i, a, ototvert;
        
        /* this one also tests of edges are not in faces: */
@@ -993,12 +992,8 @@ void load_editMesh(Scene *scene, Object *ob)
        while(eve) {
                VECCOPY(mvert->co, eve->co);
 
-               mvert->mat_nr= 32767;  /* what was this for, halos? */
-               
                /* vertex normal */
-               VECCOPY(nor, eve->no);
-               VecMulf(nor, 32767.0);
-               VECCOPY(mvert->no, nor);
+               normal_float_to_short_v3(mvert->no, eve->no);
 
                /* note: it used to remove me->dvert when it was not in use, cancelled
                   that... annoying when you have a fresh vgroup */
@@ -1010,7 +1005,7 @@ void load_editMesh(Scene *scene, Object *ob)
                mvert->flag |= (eve->f & SELECT);
                if (eve->h) mvert->flag |= ME_HIDE;
                
-               mvert->bweight= (char)(255.0*eve->bweight);
+               mvert->bweight= (char)(255.0f*eve->bweight);
 
                eve= eve->next;
                mvert++;
@@ -1031,8 +1026,8 @@ void load_editMesh(Scene *scene, Object *ob)
                if(eed->h & EM_FGON) medge->flag |= ME_FGON;    // different defines yes
                if(eed->h & 1) medge->flag |= ME_HIDE;
                
-               medge->crease= (char)(255.0*eed->crease);
-               medge->bweight= (char)(255.0*eed->bweight);
+               medge->crease= (char)(255.0f*eed->crease);
+               medge->bweight= (char)(255.0f*eed->bweight);
                CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);         
 
                eed->tmp.l = a++;
@@ -1067,20 +1062,6 @@ void load_editMesh(Scene *scene, Object *ob)
                        if(efa->f & 1) mface->flag |= ME_FACE_SEL;
                        else mface->flag &= ~ME_FACE_SEL;
                }
-               
-               /* mat_nr in vertex */
-               if(me->totcol>1) {
-                       mvert= me->mvert+mface->v1;
-                       if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
-                       mvert= me->mvert+mface->v2;
-                       if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
-                       mvert= me->mvert+mface->v3;
-                       if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
-                       if(mface->v4) {
-                               mvert= me->mvert+mface->v4;
-                               if(mvert->mat_nr == (char)32767) mvert->mat_nr= mface->mat_nr;
-                       }
-               }
                        
                /* watch: efa->e1->f2==0 means loose edge */ 
                        
@@ -1115,10 +1096,10 @@ void load_editMesh(Scene *scene, Object *ob)
                Object *ob;
                ModifierData *md;
                EditVert **vertMap = NULL;
-               int i,j;
+               int j;
 
                for (ob=G.main->object.first; ob; ob=ob->id.next) {
-                       if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) {
+                       if (ob->parent==obedit && ELEM(ob->partype, PARVERT1,PARVERT3)) {
                                
                                /* duplicate code from below, make it function later...? */
                                if (!vertMap) {
@@ -1179,13 +1160,46 @@ void load_editMesh(Scene *scene, Object *ob)
 
        /* are there keys? */
        if(me->key) {
-               KeyBlock *currkey, *actkey = ob_get_keyblock(ob);
+               KeyBlock *currkey;
+               KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1);
+
+               float (*ofs)[3] = NULL;
+
+               /* editing the base key should update others */
+               if(me->key->type==KEY_RELATIVE && oldverts) {
+                       int act_is_basis = 0;
+                       /* find if this key is a basis for any others */
+                       for(currkey = me->key->block.first; currkey; currkey= currkey->next) {
+                               if(em->shapenr-1 == currkey->relative) {
+                                       act_is_basis = 1;
+                                       break;
+                               }
+                       }
+
+                       if(act_is_basis) { /* active key is a base */
+                               float (*fp)[3]= actkey->data;
+                               i=0;
+                               ofs= MEM_callocN(sizeof(float) * 3 * em->totvert,  "currkey->data");
+                               eve= em->verts.first;
+                               mvert = me->mvert;
+                               while(eve) {
+                                       if(eve->keyindex>=0)
+                                               VECSUB(ofs[i], mvert->co, fp[eve->keyindex]);
+
+                                       eve= eve->next;
+                                       i++;
+                                       mvert++;
+                               }
+                       }
+               }
+
 
                /* Lets reorder the key data so that things line up roughly
                 * with the way things were before editmode */
                currkey = me->key->block.first;
                while(currkey) {
-                       
+                       int apply_offset = (ofs && (currkey != actkey) && (em->shapenr-1 == currkey->relative));
+
                        fp= newkey= MEM_callocN(me->key->elemsize*em->totvert,  "currkey->data");
                        oldkey = currkey->data;
 
@@ -1196,7 +1210,7 @@ void load_editMesh(Scene *scene, Object *ob)
                        while(eve) {
                                if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
                                        if(currkey == actkey) {
-                                               if (actkey == me->key->refkey) {
+                                               if(actkey == me->key->refkey) {
                                                        VECCOPY(fp, mvert->co);
                                                }
                                                else {
@@ -1215,6 +1229,12 @@ void load_editMesh(Scene *scene, Object *ob)
                                else {
                                        VECCOPY(fp, mvert->co);
                                }
+
+                               /* propagate edited basis offsets to other shapes */
+                               if(apply_offset) {
+                                       VECADD(fp, fp, ofs[i]);
+                               }
+
                                fp+= 3;
                                ++i;
                                ++mvert;
@@ -1226,6 +1246,8 @@ void load_editMesh(Scene *scene, Object *ob)
                        
                        currkey= currkey->next;
                }
+
+               if(ofs) MEM_freeN(ofs);
        }
 
        if(oldverts) MEM_freeN(oldverts);
@@ -1275,12 +1297,15 @@ void load_editMesh(Scene *scene, Object *ob)
        }
 
        mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+       /* topology could be changed, ensure mdisps are ok */
+       multires_topology_changed(scene, obedit);
 }
 
 void remake_editMesh(Scene *scene, Object *ob)
 {
        make_editMesh(scene, ob);
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        BIF_undo_push("Undo all changes");
 }
 
@@ -1294,7 +1319,7 @@ static EnumPropertyItem prop_separate_types[] = {
 };
 
 /* return 1: success */
-static int mesh_separate_selected(Scene *scene, Base *editbase)
+static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
 {
        EditMesh *em, *emnew;
        EditVert *eve, *v1;
@@ -1310,7 +1335,7 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
        me= obedit->data;
        em= BKE_mesh_get_editmesh(me);
        if(me->key) {
-               error("Can't separate with vertex keys");
+               BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys.");
                BKE_mesh_end_editmesh(me, em);
                return 0;
        }
@@ -1336,14 +1361,18 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
         */
        
        /* 1 */
-       basenew= ED_object_add_duplicate(scene, editbase, 0);   /* 0 = fully linked */
+       basenew= ED_object_add_duplicate(bmain, scene, editbase, 0);    /* 0 = fully linked */
        ED_base_object_select(basenew, BA_DESELECT);
        
        /* 2 */
-       basenew->object->data= menew= add_mesh(me->id.name);    /* empty */
+       basenew->object->data= menew= add_mesh(me->id.name+2);  /* empty */
+       assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
        me->id.us--;
        make_editMesh(scene, basenew->object);
        emnew= menew->edit_mesh;
+       CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
+       CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
+       CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
        
        /* 3 */
        /* SPLIT: first make duplicate */
@@ -1386,12 +1415,21 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
        /* 5 */
        load_editMesh(scene, basenew->object);
        free_editMesh(emnew);
-       
+       MEM_freeN(menew->edit_mesh);
+       menew->edit_mesh= NULL;
+
+       /* copy settings */
+       menew->texflag= me->texflag;
+       menew->drawflag= me->drawflag;
+       menew->flag= me->flag;
+       menew->editflag= me->editflag;
+       menew->smoothresh= me->smoothresh;
+
        /* hashedges are invalid now, make new! */
        editMesh_set_hash(em);
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
-       DAG_object_flush_update(scene, basenew->object, OB_RECALC_DATA);        
+       DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); 
+       DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA);        
 
        BKE_mesh_end_editmesh(me, em);
 
@@ -1399,7 +1437,7 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
 }
 
 /* return 1: success */
-static int mesh_separate_material(Scene *scene, Base *editbase)
+static int mesh_separate_material(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
 {
        Mesh *me= editbase->object->data;
        EditMesh *em= BKE_mesh_get_editmesh(me);
@@ -1411,9 +1449,8 @@ static int mesh_separate_material(Scene *scene, Base *editbase)
                /* select the material */
                EM_select_by_material(em, curr_mat);
                /* and now separate */
-               if(0==mesh_separate_selected(scene, editbase)) {
-                       BKE_mesh_end_editmesh(me, em);
-                       return 0;
+               if(em->totfacesel > 0) {
+                       mesh_separate_selected(op, bmain, scene, editbase);
                }
        }
 
@@ -1422,7 +1459,7 @@ static int mesh_separate_material(Scene *scene, Base *editbase)
 }
 
 /* return 1: success */
-static int mesh_separate_loose(Scene *scene, Base *editbase)
+static int mesh_separate_loose(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
 {
        Mesh *me;
        EditMesh *em;
@@ -1438,16 +1475,35 @@ static int mesh_separate_loose(Scene *scene, Base *editbase)
        }
        
        EM_clear_flag_all(em, SELECT);
-       
-       while(doit && em->verts.first) {
+
+       while(doit) {
                /* Select a random vert to start with */
-               EditVert *eve= em->verts.first;
+               EditVert *eve;
+               int tot;
+
+               /* check if all verts that are visible have been done */
+               for(eve=em->verts.first; eve; eve= eve->next)
+                       if(!eve->h) break;
+               if(eve==NULL) break; /* only hidden verts left, quit early */
+
+               /* first non hidden vert */
                eve->f |= SELECT;
                
                selectconnected_mesh_all(em);
                
+               /* don't separate the very last part */
+               for(eve=em->verts.first; eve; eve= eve->next)
+                       if((eve->f & SELECT)==0) break;
+               if(eve==NULL) break;
+
+               tot= BLI_countlist(&em->verts);
+
                /* and now separate */
-               doit= mesh_separate_selected(scene, editbase);
+               doit= mesh_separate_selected(op, bmain, scene, editbase);
+
+               /* with hidden verts this can happen */
+               if(tot == BLI_countlist(&em->verts))
+                       break;
        }
 
        BKE_mesh_end_editmesh(me, em);
@@ -1457,19 +1513,25 @@ static int mesh_separate_loose(Scene *scene, Base *editbase)
 
 static int mesh_separate_exec(bContext *C, wmOperator *op)
 {
+       Main *bmain= CTX_data_main(C);
        Scene *scene= CTX_data_scene(C);
        Base *base= CTX_data_active_base(C);
        int retval= 0, type= RNA_enum_get(op->ptr, "type");
        
        if(type == 0)
-               retval= mesh_separate_selected(scene, base);
+               retval= mesh_separate_selected(op, bmain, scene, base);
        else if(type == 1)
-               retval= mesh_separate_material (scene, base);
+               retval= mesh_separate_material(op, bmain, scene, base);
        else if(type == 2)
-               retval= mesh_separate_loose(scene, base);
+               retval= mesh_separate_loose(op, bmain, scene, base);
           
        if(retval) {
-               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, base->object);
+               WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
+
+               // XXX: new object was created, but selection wasn't actually changed
+               //      need this for outliner update without adding new ND. nazgul.
+               WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
+
                return OPERATOR_FINISHED;
        }
        return OPERATOR_CANCELLED;
@@ -1479,7 +1541,7 @@ void MESH_OT_separate(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Separate";
-       ot->description= "Separate selected geometry into a new mesh.";
+       ot->description= "Separate selected geometry into a new mesh";
        ot->idname= "MESH_OT_separate";
        
        /* api callbacks */
@@ -1490,7 +1552,7 @@ void MESH_OT_separate(wmOperatorType *ot)
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
 }
 
 
@@ -1538,8 +1600,7 @@ typedef struct UndoMesh {
        EditFaceC *faces;
        EditSelectionC *selected;
        int totvert, totedge, totface, totsel;
-       short selectmode;
-       RetopoPaintData *retopo_paint_data;
+       int selectmode, shapenr;
        char retopo_mode;
        CustomData vdata, edata, fdata;
 } UndoMesh;
@@ -1578,6 +1639,7 @@ static void *editMesh_to_undoMesh(void *emv)
        um= MEM_callocN(sizeof(UndoMesh), "undomesh");
        
        um->selectmode = em->selectmode;
+       um->shapenr = em->shapenr;
        
        for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
        for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
@@ -1604,7 +1666,7 @@ static void *editMesh_to_undoMesh(void *emv)
                evec->h= eve->h;
                evec->keyindex= eve->keyindex;
                eve->tmp.l = a; /*store index*/
-               evec->bweight= (short)(eve->bweight*255.0);
+               evec->bweight= (short)(eve->bweight*255.0f);
 
                CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
        }
@@ -1618,8 +1680,8 @@ static void *editMesh_to_undoMesh(void *emv)
                eedc->h= eed->h;
                eedc->seam= eed->seam;
                eedc->sharp= eed->sharp;
-               eedc->crease= (short)(eed->crease*255.0);
-               eedc->bweight= (short)(eed->bweight*255.0);
+               eedc->crease= (short)(eed->crease*255.0f);
+               eedc->bweight= (short)(eed->bweight*255.0f);
                eedc->fgoni= eed->fgoni;
                eed->tmp.l = a; /*store index*/
                CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
@@ -1680,6 +1742,7 @@ static void undoMesh_to_editMesh(void *umv, void *emv)
        memset(em, 0, sizeof(EditMesh));
                
        em->selectmode = um->selectmode;
+       em->shapenr = um->shapenr;
        
        init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
 
@@ -1757,6 +1820,11 @@ static void undoMesh_to_editMesh(void *umv, void *emv)
                EM_free_index_arrays();
        }
 
+       /* restore total selections */
+       EM_nvertices_selected(em);
+       EM_nedges_selected(em);
+       EM_nfaces_selected(em);
+
 // XXX retopo_free_paint();
 //     em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
 //     scene->toolsettings->retopo_mode= um->retopo_mode;
@@ -1779,7 +1847,7 @@ static void *getEditMesh(bContext *C)
 }
 
 /* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, char *name)
+void undo_push_mesh(bContext *C, const char *name)
 {
        undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
 }