Fix for [#19847] Joined meshes fail to render
[blender.git] / source / blender / editors / mesh / meshtools.c
index d835fdb8eed9f36f5845359710d1dd64118ff8ca..18125207eca4b21018ed04a326be3218ec96b58b 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <float.h>
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_image_types.h"
-#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
 #include "DNA_object_types.h"
-#include "DNA_material_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 #include "DNA_view3d_types.h"
-#include "DNA_world_types.h"
 #include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
 
 
 #include "BKE_blender.h"
+#include "BKE_context.h"
 #include "BKE_depsgraph.h"
 #include "BKE_customdata.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
+#include "BKE_key.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_mesh.h"
 #include "ED_object.h"
 #include "ED_view3d.h"
 
+#include "WM_api.h"
+#include "WM_types.h"
+
 /* own include */
 #include "mesh_intern.h"
 
-
-/* from rendercode.c */
-#define VECMUL(dest, f)                  dest[0]*= f; dest[1]*= f; dest[2]*= f
-
 /* XXX */
-static void BIF_undo_push() {}
-static void waitcursor() {}
+static void waitcursor(int val) {}
 static void error() {}
 static int pupmenu() {return 0;}
 /* XXX */
@@ -103,140 +105,189 @@ static int pupmenu() {return 0;}
 
 /* * ********************** no editmode!!! *********** */
 
+/*********************** JOIN ***************************/
+
 /* join selected meshes into the active mesh, context sensitive
 return 0 if no join is made (error) and 1 of the join is done */
-int join_mesh(Scene *scene, View3D *v3d, wmOperator *op)
+
+int join_mesh_exec(bContext *C, wmOperator *op)
 {
-       Base *base, *nextb;
-       Object *ob;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
        Material **matar, *ma;
        Mesh *me;
-       MVert *mvert, *mvertmain;
+       MVert *mvert, *mv, *mvertmain;
        MEdge *medge = NULL, *medgemain;
        MFace *mface = NULL, *mfacemain;
-       float imat[4][4], cmat[4][4];
-       int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
-       int     i, j, index, haskey=0, hasmulti=0, edgeofs, faceofs;
+       Key *key, *nkey=NULL;
+       KeyBlock *kb, *okb, *kbn;
+       float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
+       int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
+       int vertofs, *matmap=NULL;
+       int     i, j, index, haskey=0, edgeofs, faceofs;
        bDeformGroup *dg, *odg;
        MDeformVert *dvert;
        CustomData vdata, edata, fdata;
 
-       if(scene->obedit) return 0;
+       if(scene->obedit)
+               return OPERATOR_CANCELLED;
        
-       ob= OBACT;
-       if(!ob || ob->type!=OB_MESH) return 0;
+       /* ob is the object we are adding geometry to */
+       if(!ob || ob->type!=OB_MESH)
+               return OPERATOR_CANCELLED;
        
-       if (object_data_is_libdata(ob)) {
-// XXX         error_libdata();
-               return 0;
-       }
-
        /* count & check */
-       base= FIRSTBASE;
-       while(base) {
-               if(TESTBASELIB_BGMODE(base)) { /* BGMODE since python can access */
-                       if(base->object->type==OB_MESH) {
-                               me= base->object->data;
-                               totvert+= me->totvert;
-                               totface+= me->totface;
-
-                               if(base->object == ob) ok= 1;
-
-                               if(me->key) {
-                                       haskey= 1;
-                                       break;
-                               }
-                               if(me->mr) {
-                                       hasmulti= 1;
-                                       break;
-                               }
-                       }
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               if(base->object->type==OB_MESH) {
+                       me= base->object->data;
+                       
+                       totvert+= me->totvert;
+                       totedge+= me->totedge;
+                       totface+= me->totface;
+                       totmat+= base->object->totcol;
+                       
+                       if(base->object == ob)
+                               ok= 1;
+                       
+                       /* check for shapekeys */
+                       if(me->key)
+                               haskey++;
                }
-               base= base->next;
        }
+       CTX_DATA_END;
        
-       if(haskey) {
-               BKE_report(op->reports, RPT_ERROR, "Can't join meshes with vertex keys");
-               return 0;
-       }
-       if(hasmulti) {
-               BKE_report(op->reports, RPT_ERROR, "Can't join meshes with Multires");
-               return 0;
-       }
        /* that way the active object is always selected */ 
-       if(ok==0) return 0;
+       if(ok==0)
+               return OPERATOR_CANCELLED;
        
-       if(totvert==0 || totvert>MESH_MAX_VERTS) return 0;
-
-       /* if needed add edges to other meshes */
-       for(base= FIRSTBASE; base; base= base->next) {
-               if(TESTBASELIB_BGMODE(base)) {
-                       if(base->object->type==OB_MESH) {
-                               me= base->object->data;
-                               totedge += me->totedge;
-                       }
-               }
-       }
+       /* 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;
+       if(totvert==0 || totvert>MESH_MAX_VERTS || totvert==me->totvert) 
+               return OPERATOR_CANCELLED;
        
        /* new material indices and material array */
-       matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
+       matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar");
+       if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap");
        totcol= ob->totcol;
        
        /* obact materials in new main array, is nicer start! */
-       for(a=1; a<=ob->totcol; a++) {
-               matar[a-1]= give_current_material(ob, a);
-               id_us_plus((ID *)matar[a-1]);
+       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 */
        }
        
-       base= FIRSTBASE;
-       while(base) {
-               if(TESTBASELIB_BGMODE(base)) {
-                       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 */
-                                       for (odg=ob->defbase.first; odg; odg=odg->next){
-                                               if (!strcmp(odg->name, dg->name)){
-                                                       break;
-                                               }
-                                       }
-                                       if (!odg){
-                                               odg = MEM_callocN (sizeof(bDeformGroup), "join deformGroup");
-                                               memcpy (odg, dg, sizeof(bDeformGroup));
-                                               BLI_addtail(&ob->defbase, odg);
+       /* - 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 
+        *      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= copy_key(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);
+                       kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
+                       kb->totelem= totvert;
+                       kb->weights= NULL;
+               }
+       }
+       else if(haskey) {
+               /* add a new key-block and add to the mesh */
+               key= me->key= add_key((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) */
+                               for(odg=ob->defbase.first; odg; odg=odg->next) {
+                                       if(!strcmp(odg->name, dg->name)) {
+                                               break;
                                        }
-
                                }
-                               if (ob->defbase.first && ob->actdef==0)
-                                       ob->actdef=1;
-
-                               if(me->totvert) {
+                               if(!odg) {
+                                       odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
+                                       memcpy(odg, dg, sizeof(bDeformGroup));
+                                       BLI_addtail(&ob->defbase, odg);
+                               }
+                       }
+                       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-1) {
                                        for(a=1; a<=base->object->totcol; a++) {
                                                ma= give_current_material(base->object, a);
-                                               if(ma) {
-                                                       for(b=0; b<totcol; b++) {
-                                                               if(ma == matar[b]) break;
-                                                       }
-                                                       if(b==totcol) {
-                                                               matar[b]= ma;
+
+                                               for(b=0; b<totcol; b++) {
+                                                       if(ma == matar[b]) break;
+                                               }
+                                               if(b==totcol) {
+                                                       matar[b]= ma;
+                                                       if(ma)
                                                                ma->id.us++;
-                                                               totcol++;
+                                                       totcol++;
+                                               }
+                                               if(totcol>=MAXMAT-1) 
+                                                       break;
+                                       }
+                               }
+                               
+                               /* 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) {
+                                               /* if key doesn't exist in destination mesh, add it */
+                                               if(key_get_named_keyblock(key, kb->name) == NULL) {
+                                                       /* copy this existing one over to the new shapekey block */
+                                                       kbn= MEM_dupallocN(kb);
+                                                       kbn->prev= kbn->next= NULL;
+                                                       
+                                                       /* adjust adrcode and other settings to fit (allocate a new data-array) */
+                                                       kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey");
+                                                       kbn->totelem= totvert;
+                                                       kbn->weights= NULL;
+                                                       
+                                                       okb= key->block.last;
+                                                       curpos= (okb) ? okb->pos : -0.1f;
+                                                       if(key->type == KEY_RELATIVE)
+                                                               kbn->pos= curpos + 0.1f;
+                                                       else
+                                                               kbn->pos= curpos;
+                                                       
+                                                       BLI_addtail(&key->block, kbn);
+                                                       kbn->adrcode= key->totkey;
+                                                       key->totkey++;
+                                                       if(key->totkey==1) key->refkey= kbn;
+                                                       
+                                                       // XXX 2.5 Animato
+#if 0
+                                                       /* also, copy corresponding ipo-curve to ipo-block if applicable */
+                                                       if(me->key->ipo && key->ipo) {
+                                                               // FIXME... this is a luxury item!
+                                                               puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now...");
                                                        }
-                                                       if(totcol>=MAXMAT-1) break;
+#endif
                                                }
                                        }
                                }
                        }
-                       if(totcol>=MAXMAT-1) break;
                }
-               base= base->next;
        }
-
-       me= ob->data;
-
+       CTX_DATA_END;
+       
+       /* setup new data for destination mesh */
        memset(&vdata, 0, sizeof(vdata));
        memset(&edata, 0, sizeof(edata));
        memset(&fdata, 0, sizeof(fdata));
@@ -244,114 +295,180 @@ int join_mesh(Scene *scene, View3D *v3d, wmOperator *op)
        mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
        medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
        mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
-
+       
        mvertmain= mvert;
        medgemain= medge;
        mfacemain= mface;
-
-       /* inverse transorm all selected meshes in this object */
-       Mat4Invert(imat, ob->obmat);
-
+       
        vertofs= 0;
        edgeofs= 0;
        faceofs= 0;
-       base= FIRSTBASE;
-       while(base) {
-               nextb= base->next;
-               if (TESTBASELIB_BGMODE(base)) {
-                       if(base->object->type==OB_MESH) {
+       
+       /* inverse transform for all selected meshes in this object */
+       Mat4Invert(imat, ob->obmat);
+       
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               /* only join if this is a mesh */
+               if(base->object->type==OB_MESH) {
+                       me= base->object->data;
+                       
+                       if(me->totvert) {
+                               /* standard data */
+                               CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+                               CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
                                
-                               me= base->object->data;
+                               /* vertex groups */
+                               dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
                                
-                               if(me->totvert) {
-                                       CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
-                                       CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
-                                       
-                                       dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
-
-                                       /* NEW VERSION */
-                                       if (dvert){
-                                               for (i=0; i<me->totvert; i++){
-                                                       for (j=0; j<dvert[i].totweight; j++){
-                                                               //      Find the old vertex group
-                                                               odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
-                                                               if(odg) {
-                                                                       //      Search for a match in the new object
-                                                                       for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
-                                                                               if (!strcmp(dg->name, odg->name)){
-                                                                                       dvert[i].dw[j].def_nr = index;
-                                                                                       break;
-                                                                               }
+                               /* NB: vertex groups here are new version */
+                               if(dvert) {
+                                       for(i=0; i<me->totvert; i++) {
+                                               for(j=0; j<dvert[i].totweight; j++) {
+                                                       /*      Find the old vertex group */
+                                                       odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
+                                                       if(odg) {
+                                                               /*      Search for a match in the new object, and set new index */
+                                                               for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) {
+                                                                       if(!strcmp(dg->name, odg->name)) {
+                                                                               dvert[i].dw[j].def_nr = index;
+                                                                               break;
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
-
-                                       if(base->object != ob) {
-                                               /* watch this: switch matmul order really goes wrong */
-                                               Mat4MulMat4(cmat, base->object->obmat, imat);
-                                               
-                                               a= me->totvert;
-                                               while(a--) {
-                                                       Mat4MulVecfl(cmat, mvert->co);
-                                                       mvert++;
-                                               }
-                                       }
-                                       else mvert+= me->totvert;
                                }
-                               if(me->totface) {
                                
-                                       /* make mapping for materials */
-                                       memset(map, 0, 4*MAXMAT);
-                                       for(a=1; a<=base->object->totcol; a++) {
-                                               ma= give_current_material(base->object, a);
-                                               if(ma) {
-                                                       for(b=0; b<totcol; b++) {
-                                                               if(ma == matar[b]) {
-                                                                       map[a-1]= b;
-                                                                       break;
+                               /* if this is the object we're merging into, no need to do anything */
+                               if(base->object != ob) {
+                                       /* watch this: switch matmul order really goes wrong */
+                                       Mat4MulMat4(cmat, base->object->obmat, imat);
+                                       
+                                       /* transform vertex coordinates into new space */
+                                       for(a=0, mv=mvert; a < me->totvert; a++, mv++) {
+                                               Mat4MulVecfl(cmat, mv->co);
+                                       }
+                                       
+                                       /* for each shapekey in destination mesh:
+                                        *      - if there's a matching one, copy it across (will need to transform vertices into new space...)
+                                        *      - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
+                                        */
+                                       if(key) {
+                                               /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
+                                               for(kb= key->block.first; kb; kb= kb->next) {
+                                                       /* get pointer to where to write data for this mesh in shapekey's data array */
+                                                       fp1= ((float *)kb->data) + (vertofs*3); 
+                                                       
+                                                       /* check if this mesh has such a shapekey */
+                                                       okb= key_get_named_keyblock(me->key, kb->name);
+                                                       if(okb) {
+                                                               /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
+                                                               fp2= ((float *)(okb->data));
+                                                               for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
+                                                                       VECCOPY(fp1, fp2);
+                                                                       Mat4MulVecfl(cmat, fp1);
+                                                               }
+                                                       }
+                                                       else {
+                                                               /* copy this mesh's vertex coordinates to the destination shapekey */
+                                                               mv= mvert;
+                                                               for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
+                                                                       VECCOPY(fp1, mv->co);
                                                                }
                                                        }
                                                }
                                        }
-
-                                       CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
-                                       CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
-
-                                       for(a=0; a<me->totface; a++, mface++) {
-                                               mface->v1+= vertofs;
-                                               mface->v2+= vertofs;
-                                               mface->v3+= vertofs;
-                                               if(mface->v4) mface->v4+= vertofs;
-                                               
-                                               mface->mat_nr= map[(int)mface->mat_nr];
+                               }
+                               else {
+                                       /* for each shapekey in destination mesh:
+                                        *      - if it was an 'original', copy the appropriate data from nkey
+                                        *      - otherwise, copy across plain coordinates (no need to transform coordinates)
+                                        */
+                                       if(key) {
+                                               for(kb= key->block.first; kb; kb= kb->next) {
+                                                       /* get pointer to where to write data for this mesh in shapekey's data array */
+                                                       fp1= ((float *)kb->data) + (vertofs*3); 
+                                                       
+                                                       /* check if this was one of the original shapekeys */
+                                                       okb= key_get_named_keyblock(nkey, kb->name);
+                                                       if(okb) {
+                                                               /* copy this mesh's shapekey to the destination shapekey */
+                                                               fp2= ((float *)(okb->data));
+                                                               for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
+                                                                       VECCOPY(fp1, fp2);
+                                                               }
+                                                       }
+                                                       else {
+                                                               /* copy base-coordinates to the destination shapekey */
+                                                               mv= mvert;
+                                                               for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
+                                                                       VECCOPY(fp1, mv->co);
+                                                               }
+                                                       }
+                                               }
                                        }
-
-                                       faceofs += me->totface;
                                }
                                
-                               if(me->totedge) {
-                                       CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
-                                       CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
-
-                                       for(a=0; a<me->totedge; a++, medge++) {
-                                               medge->v1+= vertofs;
-                                               medge->v2+= vertofs;
+                               /* advance mvert pointer to end of base mesh's data */
+                               mvert+= me->totvert;
+                       }
+                       
+                       if(me->totface) {
+                               /* make mapping for materials */
+                               for(a=1; a<=base->object->totcol; a++) {
+                                       ma= give_current_material(base->object, a);
+
+                                       for(b=0; b<totcol; b++) {
+                                               if(ma == matar[b]) {
+                                                       matmap[a-1]= b;
+                                                       break;
+                                               }
                                        }
-
-                                       edgeofs += me->totedge;
                                }
                                
-                               vertofs += me->totvert;
+                               CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
+                               CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
+                               
+                               for(a=0; a<me->totface; a++, mface++) {
+                                       mface->v1+= vertofs;
+                                       mface->v2+= vertofs;
+                                       mface->v3+= vertofs;
+                                       if(mface->v4) mface->v4+= vertofs;
+                                       
+                                       if (matmap)
+                                               mface->mat_nr= matmap[(int)mface->mat_nr];
+                                       else 
+                                               mface->mat_nr= 0;
+                               }
+                               
+                               faceofs += me->totface;
+                       }
+                       
+                       if(me->totedge) {
+                               CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+                               CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
+                               
+                               for(a=0; a<me->totedge; a++, medge++) {
+                                       medge->v1+= vertofs;
+                                       medge->v2+= vertofs;
+                               }
                                
-                               if(base->object!=ob)
-                                       ED_base_object_free_and_unlink(scene, base);
+                               edgeofs += me->totedge;
                        }
+                       
+                       /* vertofs is used to help newly added verts be reattached to their edge/face 
+                        * (cannot be set earlier, or else reattaching goes wrong)
+                        */
+                       vertofs += me->totvert;
+                       
+                       /* free base, now that data is merged */
+                       if(base->object != ob)
+                               ED_base_object_free_and_unlink(scene, base);
                }
-               base= nextb;
        }
+       CTX_DATA_END;
        
+       /* return to mesh we're merging to */
        me= ob->data;
        
        CustomData_free(&me->vdata, me->totvert);
@@ -378,30 +495,53 @@ int join_mesh(Scene *scene, View3D *v3d, wmOperator *op)
                if(ma) ma->id.us--;
        }
        if(ob->mat) MEM_freeN(ob->mat);
+       if(ob->matbits) MEM_freeN(ob->matbits);
        if(me->mat) MEM_freeN(me->mat);
-       ob->mat= me->mat= 0;
+       ob->mat= me->mat= NULL;
+       ob->matbits= NULL;
        
        if(totcol) {
                me->mat= matar;
                ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
+               ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits");
        }
-       else MEM_freeN(matar);
+       else
+               MEM_freeN(matar);
        
        ob->totcol= me->totcol= totcol;
        ob->colbits= 0;
+
+       if (matmap) MEM_freeN(matmap);
        
        /* other mesh users */
        test_object_materials((ID *)me);
        
-       DAG_scene_sort(scene);  // removed objects, need to rebuild dag before editmode call
+       /* free temp copy of destination shapekeys (if applicable) */
+       if(nkey) {
+               // XXX 2.5 Animato
+#if 0
+               /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
+               if(nkey->ipo) {
+                       free_ipo(nkey->ipo);
+                       BLI_remlink(&G.main->ipo, nkey->ipo);
+                       MEM_freeN(nkey->ipo);
+               }
+#endif
+               
+               free_key(nkey);
+               BLI_remlink(&G.main->key, nkey);
+               MEM_freeN(nkey);
+       }
        
-// XXX enter_editmode(EM_WAITCURSOR);
-//     exit_editmode(EM_FREEDATA|EM_WAITCURSOR);       // freedata, but no undo
+       DAG_scene_sort(scene);  // removed objects, need to rebuild dag before editmode call
        
-       BIF_undo_push("Join Mesh");
-       return 1;
-}
+       ED_object_enter_editmode(C, EM_WAITCURSOR);
+       ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
+
+       WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
 
+       return OPERATOR_FINISHED;
+}
 
 /* ********************** SORT FACES ******************* */
 
@@ -495,7 +635,7 @@ void sort_faces(Scene *scene, View3D *v3d)
                if (event == 1)
                        Mat4MulMat4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */
                else if (event == 2) { /* sort from cursor */
-                       if( v3d && v3d->localview ) {
+                       if( v3d && v3d->localvd ) {
                                VECCOPY(cur, v3d->cursor);
                        } else {
                                VECCOPY(cur, scene->cursor);
@@ -515,14 +655,14 @@ void sort_faces(Scene *scene, View3D *v3d)
                                else                                            face_sort_floats[i] = reverse;
                        } else {
                                /* find the faces center */
-                               VECADD(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
+                               VecAddf(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
                                if (mf->v4) {
-                                       VECADD(vec, vec, (me->mvert+mf->v3)->co);
-                                       VECADD(vec, vec, (me->mvert+mf->v4)->co);
-                                       VECMUL(vec, 0.25f);
+                                       VecAddf(vec, vec, (me->mvert+mf->v3)->co);
+                                       VecAddf(vec, vec, (me->mvert+mf->v4)->co);
+                                       VecMulf(vec, 0.25f);
                                } else {
-                                       VECADD(vec, vec, (me->mvert+mf->v3)->co);
-                                       VECMUL(vec, 1.0f/3.0f);
+                                       VecAddf(vec, vec, (me->mvert+mf->v3)->co);
+                                       VecMulf(vec, 1.0f/3.0f);
                                } /* done */
                                
                                if (event == 1) { /* sort on view axis */
@@ -545,7 +685,7 @@ void sort_faces(Scene *scene, View3D *v3d)
 
        MEM_freeN(index);
 
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+       DAG_id_flush_update(ob->data, OB_RECALC_DATA);
 }
 
 
@@ -615,9 +755,9 @@ static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, f
        float fx, fy, fz;
        int vx, vy, vz;
        
-       if (isnan(co[0]) || !finite(co[0]) ||
-               isnan(co[1]) || !finite(co[1]) ||
-               isnan(co[2]) || !finite(co[2])
+       if (!finite(co[0]) ||
+               !finite(co[1]) ||
+               !finite(co[2])
        ) {
                return;
        }
@@ -658,7 +798,7 @@ static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, f
        
 }
 
-static intptr_t mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mvert, float *co)
+static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
 {
        float *vec;
        int a;
@@ -669,12 +809,7 @@ static intptr_t mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mv
        for(a=0; a<MOC_NODE_RES; a++) {
                if((*bt)->index[a]) {
                        /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */
-                       if(orco) {
-                               vec= orco[(*bt)->index[a]-1];
-                               if(FloatCompare(vec, co, MOC_THRESH))
-                                       return (*bt)->index[a]-1;
-                       }
-                       else if(mvert) {
+                       if(mvert) {
                                vec= (mvert+(*bt)->index[a]-1)->co;
                                if(FloatCompare(vec, co, MOC_THRESH))
                                        return (*bt)->index[a]-1;
@@ -688,7 +823,7 @@ static intptr_t mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mv
                else return -1;
        }
        if( (*bt)->next)
-               return mesh_octree_find_index(&(*bt)->next, orco, mvert, co);
+               return mesh_octree_find_index(&(*bt)->next, mvert, co);
        
        return -1;
 }
@@ -696,9 +831,7 @@ static intptr_t mesh_octree_find_index(MocNode **bt, float (*orco)[3], MVert *mv
 static struct {
        MocNode **table;
        float offs[3], div[3];
-       float (*orco)[3];
-       float orcoloc[3];
-} MeshOctree = {NULL, {0, 0, 0}, {0, 0, 0}, NULL};
+} MeshOctree = {NULL, {0, 0, 0}, {0, 0, 0}};
 
 /* mode is 's' start, or 'e' end, or 'u' use */
 /* if end, ob can be NULL */
@@ -714,9 +847,9 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
                        Mesh *me= ob->data;
                        bt= MeshOctree.table + mesh_octree_get_base_offs(co, MeshOctree.offs, MeshOctree.div);
                        if(em)
-                               return mesh_octree_find_index(bt, NULL, NULL, co);
+                               return mesh_octree_find_index(bt, NULL, co);
                        else
-                               return mesh_octree_find_index(bt, MeshOctree.orco, me->mvert, co);
+                               return mesh_octree_find_index(bt, me->mvert, co);
                }
                return -1;
        }
@@ -736,16 +869,10 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
                }
                else {          
                        MVert *mvert;
-                       float *vco;
-                       int a, totvert;
-                       
-                       MeshOctree.orco= mesh_getRefKeyCos(me, &totvert);
-                       mesh_get_texspace(me, MeshOctree.orcoloc, NULL, NULL);
+                       int a;
                        
-                       for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++) {
-                               vco= (MeshOctree.orco)? MeshOctree.orco[a]: mvert->co;
-                               DO_MINMAX(vco, min, max);
-                       }
+                       for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++)
+                               DO_MINMAX(mvert->co, min, max);
                }
                
                /* for quick unit coordinate calculus */
@@ -778,13 +905,10 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
                }
                else {          
                        MVert *mvert;
-                       float *vco;
                        int a;
                        
-                       for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++) {
-                               vco= (MeshOctree.orco)? MeshOctree.orco[a]: mvert->co;
-                               mesh_octree_add_nodes(MeshOctree.table, vco, MeshOctree.offs, MeshOctree.div, a+1);
-                       }
+                       for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++)
+                               mesh_octree_add_nodes(MeshOctree.table, mvert->co, MeshOctree.offs, MeshOctree.div, a+1);
                }
        }
        else if(mode=='e') { /* end table */
@@ -797,10 +921,6 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
                        MEM_freeN(MeshOctree.table);
                        MeshOctree.table= NULL;
                }
-               if(MeshOctree.orco) {
-                       MEM_freeN(MeshOctree.orco);
-                       MeshOctree.orco= NULL;
-               }
        }
        return 0;
 }
@@ -811,19 +931,10 @@ int mesh_get_x_mirror_vert(Object *ob, int index)
        MVert *mvert;
        float vec[3];
        
-       if(MeshOctree.orco) {
-               float *loc= MeshOctree.orcoloc;
-
-               vec[0]= -(MeshOctree.orco[index][0] + loc[0]) - loc[0];
-               vec[1]= MeshOctree.orco[index][1];
-               vec[2]= MeshOctree.orco[index][2];
-       }
-       else {
-               mvert= me->mvert+index;
-               vec[0]= -mvert->co[0];
-               vec[1]= mvert->co[1];
-               vec[2]= mvert->co[2];
-       }
+       mvert= me->mvert+index;
+       vec[0]= -mvert->co[0];
+       vec[1]= mvert->co[1];
+       vec[2]= mvert->co[2];
        
        return mesh_octree_table(ob, NULL, vec, 'u');
 }
@@ -834,9 +945,9 @@ EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co)
        intptr_t poinval;
        
        /* ignore nan verts */
-       if (isnan(co[0]) || !finite(co[0]) ||
-               isnan(co[1]) || !finite(co[1]) ||
-               isnan(co[2]) || !finite(co[2])
+       if (!finite(co[0]) ||
+               !finite(co[1]) ||
+               !finite(co[2])
           )
                return NULL;