Blender V2.61 - r43446

meshtools.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2004 by Blender Foundation
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /*
00034     meshtools.c: no editmode (violated already :), tools operating on meshes
00035 */
00036 
00037 #include <stddef.h>
00038 #include <stdlib.h>
00039 #include <math.h>
00040 #include <float.h>
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "DNA_key_types.h"
00045 #include "DNA_material_types.h"
00046 #include "DNA_meshdata_types.h"
00047 #include "DNA_object_types.h"
00048 #include "DNA_scene_types.h"
00049 
00050 #include "BLI_math.h"
00051 #include "BLI_blenlib.h"
00052 #include "BLI_utildefines.h"
00053 #include "BLI_editVert.h"
00054 #include "BLI_ghash.h"
00055 #include "BLI_rand.h" /* for randome face sorting */
00056 #include "BLI_threads.h"
00057 
00058 
00059 #include "BKE_context.h"
00060 #include "BKE_depsgraph.h"
00061 #include "BKE_deform.h"
00062 #include "BKE_DerivedMesh.h"
00063 #include "BKE_key.h"
00064 #include "BKE_library.h"
00065 #include "BKE_main.h"
00066 #include "BKE_mesh.h"
00067 #include "BKE_material.h"
00068 #include "BKE_report.h"
00069 #include "BKE_multires.h"
00070 
00071 #include "BLO_sys_types.h" // for intptr_t support
00072 
00073 #include "ED_mesh.h"
00074 #include "ED_object.h"
00075 #include "ED_view3d.h"
00076 
00077 #include "WM_api.h"
00078 #include "WM_types.h"
00079 
00080 /* own include */
00081 #include "mesh_intern.h"
00082 
00083 
00084 /* * ********************** no editmode!!! *********** */
00085 
00086 /*********************** JOIN ***************************/
00087 
00088 /* join selected meshes into the active mesh, context sensitive
00089 return 0 if no join is made (error) and 1 of the join is done */
00090 
00091 int join_mesh_exec(bContext *C, wmOperator *op)
00092 {
00093     Main *bmain= CTX_data_main(C);
00094     Scene *scene= CTX_data_scene(C);
00095     Object *ob= CTX_data_active_object(C);
00096     Material **matar, *ma;
00097     Mesh *me;
00098     MVert *mvert, *mv;
00099     MEdge *medge = NULL;
00100     MFace *mface = NULL;
00101     Key *key, *nkey=NULL;
00102     KeyBlock *kb, *okb, *kbn;
00103     float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
00104     int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
00105     int vertofs, *matmap=NULL;
00106     int i, j, index, haskey=0, edgeofs, faceofs;
00107     bDeformGroup *dg, *odg;
00108     MDeformVert *dvert;
00109     CustomData vdata, edata, fdata;
00110 
00111     if(scene->obedit) {
00112         BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
00113         return OPERATOR_CANCELLED;
00114     }
00115     
00116     /* ob is the object we are adding geometry to */
00117     if(!ob || ob->type!=OB_MESH) {
00118         BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
00119         return OPERATOR_CANCELLED;
00120     }
00121     
00122     /* count & check */
00123     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00124         if(base->object->type==OB_MESH) {
00125             me= base->object->data;
00126             
00127             totvert+= me->totvert;
00128             totedge+= me->totedge;
00129             totface+= me->totface;
00130             totmat+= base->object->totcol;
00131             
00132             if(base->object == ob)
00133                 ok= 1;
00134             
00135             /* check for shapekeys */
00136             if(me->key)
00137                 haskey++;
00138         }
00139     }
00140     CTX_DATA_END;
00141     
00142     /* that way the active object is always selected */ 
00143     if(ok==0) {
00144         BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
00145         return OPERATOR_CANCELLED;
00146     }
00147     
00148     /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
00149     me= (Mesh *)ob->data;
00150     key= me->key;
00151 
00152     if(totvert==0 || totvert==me->totvert) {
00153         BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
00154         return OPERATOR_CANCELLED;
00155     }
00156     
00157     if(totvert > MESH_MAX_VERTS) {
00158         BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert);
00159         return OPERATOR_CANCELLED;      
00160     }
00161 
00162     /* new material indices and material array */
00163     matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar");
00164     if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap");
00165     totcol= ob->totcol;
00166     
00167     /* obact materials in new main array, is nicer start! */
00168     for(a=0; a<ob->totcol; a++) {
00169         matar[a]= give_current_material(ob, a+1);
00170         id_us_plus((ID *)matar[a]);
00171         /* increase id->us : will be lowered later */
00172     }
00173     
00174     /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
00175      *  with arrays that are large enough to hold shapekey data for all meshes
00176      * -    if destination mesh didn't have shapekeys, but we encountered some in the meshes we're 
00177      *  joining, set up a new keyblock and assign to the mesh
00178      */
00179     if(key) {
00180         /* make a duplicate copy that will only be used here... (must remember to free it!) */
00181         nkey= copy_key(key);
00182         
00183         /* for all keys in old block, clear data-arrays */
00184         for(kb= key->block.first; kb; kb= kb->next) {
00185             if(kb->data) MEM_freeN(kb->data);
00186             kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
00187             kb->totelem= totvert;
00188             kb->weights= NULL;
00189         }
00190     }
00191     else if(haskey) {
00192         /* add a new key-block and add to the mesh */
00193         key= me->key= add_key((ID *)me);
00194         key->type = KEY_RELATIVE;
00195     }
00196     
00197     /* first pass over objects - copying materials and vertexgroups across */
00198     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00199         /* only act if a mesh, and not the one we're joining to */
00200         if((ob!=base->object) && (base->object->type==OB_MESH)) {
00201             me= base->object->data;
00202             
00203             /* Join this object's vertex groups to the base one's */
00204             for(dg=base->object->defbase.first; dg; dg=dg->next) {
00205                 /* See if this group exists in the object (if it doesn't, add it to the end) */
00206                 if(!defgroup_find_name(ob, dg->name)) {
00207                     odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
00208                     memcpy(odg, dg, sizeof(bDeformGroup));
00209                     BLI_addtail(&ob->defbase, odg);
00210                 }
00211             }
00212             if(ob->defbase.first && ob->actdef==0)
00213                 ob->actdef=1;
00214             
00215             
00216             if(me->totvert) {
00217                 /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
00218                 if(totcol < MAXMAT) {
00219                     for(a=1; a<=base->object->totcol; a++) {
00220                         ma= give_current_material(base->object, a);
00221 
00222                         for(b=0; b<totcol; b++) {
00223                             if(ma == matar[b]) break;
00224                         }
00225                         if(b==totcol) {
00226                             matar[b]= ma;
00227                             if(ma) {
00228                                 id_us_plus(&ma->id);
00229                             }
00230                             totcol++;
00231                         }
00232                         if(totcol >= MAXMAT)
00233                             break;
00234                     }
00235                 }
00236                 
00237                 /* if this mesh has shapekeys, check if destination mesh already has matching entries too */
00238                 if(me->key && key) {
00239                     for(kb= me->key->block.first; kb; kb= kb->next) {
00240                         /* if key doesn't exist in destination mesh, add it */
00241                         if(key_get_named_keyblock(key, kb->name) == NULL) {
00242                             /* copy this existing one over to the new shapekey block */
00243                             kbn= MEM_dupallocN(kb);
00244                             kbn->prev= kbn->next= NULL;
00245                             
00246                             /* adjust adrcode and other settings to fit (allocate a new data-array) */
00247                             kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey");
00248                             kbn->totelem= totvert;
00249                             kbn->weights= NULL;
00250                             
00251                             okb= key->block.last;
00252                             curpos= (okb) ? okb->pos : -0.1f;
00253                             if(key->type == KEY_RELATIVE)
00254                                 kbn->pos= curpos + 0.1f;
00255                             else
00256                                 kbn->pos= curpos;
00257                             
00258                             BLI_addtail(&key->block, kbn);
00259                             kbn->adrcode= key->totkey;
00260                             key->totkey++;
00261                             if(key->totkey==1) key->refkey= kbn;
00262                             
00263                             // XXX 2.5 Animato
00264 #if 0
00265                             /* also, copy corresponding ipo-curve to ipo-block if applicable */
00266                             if(me->key->ipo && key->ipo) {
00267                                 // FIXME... this is a luxury item!
00268                                 puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now...");
00269                             }
00270 #endif
00271                         }
00272                     }
00273                 }
00274             }
00275         }
00276     }
00277     CTX_DATA_END;
00278     
00279     /* setup new data for destination mesh */
00280     memset(&vdata, 0, sizeof(vdata));
00281     memset(&edata, 0, sizeof(edata));
00282     memset(&fdata, 0, sizeof(fdata));
00283     
00284     mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
00285     medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
00286     mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
00287 
00288     vertofs= 0;
00289     edgeofs= 0;
00290     faceofs= 0;
00291     
00292     /* inverse transform for all selected meshes in this object */
00293     invert_m4_m4(imat, ob->obmat);
00294     
00295     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00296         /* only join if this is a mesh */
00297         if(base->object->type==OB_MESH) {
00298             me= base->object->data;
00299             
00300             if(me->totvert) {
00301                 /* standard data */
00302                 CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
00303                 CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
00304                 
00305                 /* vertex groups */
00306                 dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
00307                 
00308                 /* NB: vertex groups here are new version */
00309                 if(dvert) {
00310                     for(i=0; i<me->totvert; i++) {
00311                         for(j=0; j<dvert[i].totweight; j++) {
00312                             /*  Find the old vertex group */
00313                             odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
00314                             if(odg) {
00315                                 /*  Search for a match in the new object, and set new index */
00316                                 for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) {
00317                                     if(!strcmp(dg->name, odg->name)) {
00318                                         dvert[i].dw[j].def_nr = index;
00319                                         break;
00320                                     }
00321                                 }
00322                             }
00323                         }
00324                     }
00325                 }
00326                 
00327                 /* if this is the object we're merging into, no need to do anything */
00328                 if(base->object != ob) {
00329                     /* watch this: switch matmul order really goes wrong */
00330                     mult_m4_m4m4(cmat, imat, base->object->obmat);
00331                     
00332                     /* transform vertex coordinates into new space */
00333                     for(a=0, mv=mvert; a < me->totvert; a++, mv++) {
00334                         mul_m4_v3(cmat, mv->co);
00335                     }
00336                     
00337                     /* for each shapekey in destination mesh:
00338                      *  - if there's a matching one, copy it across (will need to transform vertices into new space...)
00339                      *  - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
00340                      */
00341                     if(key) {
00342                         /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
00343                         for(kb= key->block.first; kb; kb= kb->next) {
00344                             /* get pointer to where to write data for this mesh in shapekey's data array */
00345                             fp1= ((float *)kb->data) + (vertofs*3); 
00346                             
00347                             /* check if this mesh has such a shapekey */
00348                             okb= key_get_named_keyblock(me->key, kb->name);
00349                             if(okb) {
00350                                 /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
00351                                 fp2= ((float *)(okb->data));
00352                                 for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
00353                                     VECCOPY(fp1, fp2);
00354                                     mul_m4_v3(cmat, fp1);
00355                                 }
00356                             }
00357                             else {
00358                                 /* copy this mesh's vertex coordinates to the destination shapekey */
00359                                 mv= mvert;
00360                                 for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
00361                                     VECCOPY(fp1, mv->co);
00362                                 }
00363                             }
00364                         }
00365                     }
00366                 }
00367                 else {
00368                     /* for each shapekey in destination mesh:
00369                      *  - if it was an 'original', copy the appropriate data from nkey
00370                      *  - otherwise, copy across plain coordinates (no need to transform coordinates)
00371                      */
00372                     if(key) {
00373                         for(kb= key->block.first; kb; kb= kb->next) {
00374                             /* get pointer to where to write data for this mesh in shapekey's data array */
00375                             fp1= ((float *)kb->data) + (vertofs*3); 
00376                             
00377                             /* check if this was one of the original shapekeys */
00378                             okb= key_get_named_keyblock(nkey, kb->name);
00379                             if(okb) {
00380                                 /* copy this mesh's shapekey to the destination shapekey */
00381                                 fp2= ((float *)(okb->data));
00382                                 for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
00383                                     VECCOPY(fp1, fp2);
00384                                 }
00385                             }
00386                             else {
00387                                 /* copy base-coordinates to the destination shapekey */
00388                                 mv= mvert;
00389                                 for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
00390                                     VECCOPY(fp1, mv->co);
00391                                 }
00392                             }
00393                         }
00394                     }
00395                 }
00396                 
00397                 /* advance mvert pointer to end of base mesh's data */
00398                 mvert+= me->totvert;
00399             }
00400             
00401             if(me->totface) {
00402                 /* make mapping for materials */
00403                 for(a=1; a<=base->object->totcol; a++) {
00404                     ma= give_current_material(base->object, a);
00405 
00406                     for(b=0; b<totcol; b++) {
00407                         if(ma == matar[b]) {
00408                             matmap[a-1]= b;
00409                             break;
00410                         }
00411                     }
00412                 }
00413                 
00414                 if(base->object!=ob)
00415                     multiresModifier_prepare_join(scene, base->object, ob);
00416 
00417                 CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
00418                 CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
00419                 
00420                 for(a=0; a<me->totface; a++, mface++) {
00421                     mface->v1+= vertofs;
00422                     mface->v2+= vertofs;
00423                     mface->v3+= vertofs;
00424                     if(mface->v4) mface->v4+= vertofs;
00425                     
00426                     if (matmap)
00427                         mface->mat_nr= matmap[(int)mface->mat_nr];
00428                     else 
00429                         mface->mat_nr= 0;
00430                 }
00431                 
00432                 faceofs += me->totface;
00433             }
00434             
00435             if(me->totedge) {
00436                 CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
00437                 CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
00438                 
00439                 for(a=0; a<me->totedge; a++, medge++) {
00440                     medge->v1+= vertofs;
00441                     medge->v2+= vertofs;
00442                 }
00443                 
00444                 edgeofs += me->totedge;
00445             }
00446             
00447             /* vertofs is used to help newly added verts be reattached to their edge/face 
00448              * (cannot be set earlier, or else reattaching goes wrong)
00449              */
00450             vertofs += me->totvert;
00451             
00452             /* free base, now that data is merged */
00453             if(base->object != ob)
00454                 ED_base_object_free_and_unlink(bmain, scene, base);
00455         }
00456     }
00457     CTX_DATA_END;
00458     
00459     /* return to mesh we're merging to */
00460     me= ob->data;
00461     
00462     CustomData_free(&me->vdata, me->totvert);
00463     CustomData_free(&me->edata, me->totedge);
00464     CustomData_free(&me->fdata, me->totface);
00465 
00466     me->totvert= totvert;
00467     me->totedge= totedge;
00468     me->totface= totface;
00469     
00470     me->vdata= vdata;
00471     me->edata= edata;
00472     me->fdata= fdata;
00473 
00474     mesh_update_customdata_pointers(me);
00475     
00476     /* old material array */
00477     for(a=1; a<=ob->totcol; a++) {
00478         ma= ob->mat[a-1];
00479         if(ma) ma->id.us--;
00480     }
00481     for(a=1; a<=me->totcol; a++) {
00482         ma= me->mat[a-1];
00483         if(ma) ma->id.us--;
00484     }
00485     if(ob->mat) MEM_freeN(ob->mat);
00486     if(ob->matbits) MEM_freeN(ob->matbits);
00487     if(me->mat) MEM_freeN(me->mat);
00488     ob->mat= me->mat= NULL;
00489     ob->matbits= NULL;
00490     
00491     if(totcol) {
00492         me->mat= matar;
00493         ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
00494         ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits");
00495     }
00496     else
00497         MEM_freeN(matar);
00498     
00499     ob->totcol= me->totcol= totcol;
00500 
00501     if (matmap) MEM_freeN(matmap);
00502     
00503     /* other mesh users */
00504     test_object_materials((ID *)me);
00505     
00506     /* free temp copy of destination shapekeys (if applicable) */
00507     if(nkey) {
00508         // XXX 2.5 Animato
00509 #if 0
00510         /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
00511         if(nkey->ipo) {
00512             free_ipo(nkey->ipo);
00513             BLI_remlink(&bmain->ipo, nkey->ipo);
00514             MEM_freeN(nkey->ipo);
00515         }
00516 #endif
00517         
00518         free_key(nkey);
00519         BLI_remlink(&bmain->key, nkey);
00520         MEM_freeN(nkey);
00521     }
00522     
00523     DAG_scene_sort(bmain, scene);   // removed objects, need to rebuild dag before editmode call
00524 
00525 #if 0
00526     ED_object_enter_editmode(C, EM_WAITCURSOR);
00527     ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
00528 #else
00529     /* toggle editmode using lower level functions so this can be called from python */
00530     make_editMesh(scene, ob);
00531     load_editMesh(scene, ob);
00532     free_editMesh(me->edit_mesh);
00533     MEM_freeN(me->edit_mesh);
00534     me->edit_mesh= NULL;
00535     DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
00536 #endif
00537     WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00538 
00539     return OPERATOR_FINISHED;
00540 }
00541 
00542 /*********************** JOIN AS SHAPES ***************************/
00543 
00544 /* Append selected meshes vertex locations as shapes of the active mesh, 
00545   return 0 if no join is made (error) and 1 of the join is done */
00546 
00547 int join_mesh_shapes_exec(bContext *C, wmOperator *op)
00548 {
00549     Scene *scene= CTX_data_scene(C);
00550     Object *ob= CTX_data_active_object(C);
00551     Mesh *me= (Mesh *)ob->data;
00552     Mesh *selme=NULL;
00553     DerivedMesh *dm=NULL;
00554     Key *key=me->key;
00555     KeyBlock *kb;
00556     int ok=0, nonequal_verts=0;
00557     
00558     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00559         if (base->object == ob) continue;
00560         
00561         if (base->object->type==OB_MESH) {
00562             selme = (Mesh *)base->object->data;
00563             
00564             if (selme->totvert==me->totvert)
00565                 ok++;
00566             else
00567                 nonequal_verts=1;
00568         }
00569     }
00570     CTX_DATA_END;
00571     
00572     if (!ok) {
00573         if (nonequal_verts)
00574             BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
00575         else
00576             BKE_report(op->reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join");
00577         return OPERATOR_CANCELLED;
00578     }
00579     
00580     if(key == NULL) {
00581         key= me->key= add_key((ID *)me);
00582         key->type= KEY_RELATIVE;
00583 
00584         /* first key added, so it was the basis. initialise it with the existing mesh */
00585         kb= add_keyblock(key, NULL);
00586         mesh_to_key(me, kb);
00587     }
00588     
00589     /* now ready to add new keys from selected meshes */
00590     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
00591         if (base->object == ob) continue;
00592         
00593         if(base->object->type==OB_MESH) {
00594             selme = (Mesh *)base->object->data;
00595             
00596             if (selme->totvert==me->totvert) {
00597                 dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH);
00598                 
00599                 if (!dm) continue;
00600                     
00601                 kb= add_keyblock(key, base->object->id.name+2);
00602                 
00603                 DM_to_meshkey(dm, me, kb);
00604                 
00605                 dm->release(dm);
00606             }
00607         }
00608     }
00609     CTX_DATA_END;
00610     
00611     WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00612     
00613     return OPERATOR_FINISHED;
00614 }
00615 
00616 /* ********************* MESH VERTEX OCTREE LOOKUP ************* */
00617 
00618 /* important note; this is unfinished, needs better API for editmode, and custom threshold */
00619 
00620 #define MOC_RES         8
00621 #define MOC_NODE_RES    8
00622 #define MOC_THRESH      0.00002f
00623 
00624 typedef struct MocNode {
00625     struct MocNode *next;
00626     intptr_t index[MOC_NODE_RES];
00627 } MocNode;
00628 
00629 static int mesh_octree_get_base_offs(float *co, float *offs, float *div)
00630 {
00631     int vx, vy, vz;
00632     
00633     vx= floor( (co[0]-offs[0])/div[0] );
00634     vy= floor( (co[1]-offs[1])/div[1] );
00635     vz= floor( (co[2]-offs[2])/div[2] );
00636     
00637     CLAMP(vx, 0, MOC_RES-1);
00638     CLAMP(vy, 0, MOC_RES-1);
00639     CLAMP(vz, 0, MOC_RES-1);
00640 
00641     return (vx*MOC_RES*MOC_RES) + vy*MOC_RES + vz;
00642 }
00643 
00644 static void mesh_octree_add_node(MocNode **bt, intptr_t index)
00645 {
00646     if(*bt==NULL) {
00647         *bt= MEM_callocN(sizeof(MocNode), "MocNode");
00648         (*bt)->index[0]= index;
00649     }
00650     else {
00651         int a;
00652         for(a=0; a<MOC_NODE_RES; a++) {
00653             if((*bt)->index[a]==index)
00654                 return;
00655             else if((*bt)->index[a]==0) {
00656                 (*bt)->index[a]= index;
00657                 return;
00658             }
00659         }
00660         mesh_octree_add_node(&(*bt)->next, index);
00661     }
00662 }
00663 
00664 static void mesh_octree_free_node(MocNode **bt)
00665 {
00666     if( (*bt)->next ) {
00667         mesh_octree_free_node(&(*bt)->next);
00668     }
00669     MEM_freeN(*bt);
00670 }
00671 
00672 
00673 /* temporal define, just to make nicer code below */
00674 #define MOC_INDEX(vx, vy, vz)  (((vx)*MOC_RES*MOC_RES) + (vy)*MOC_RES + (vz))
00675 
00676 static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, float *div, intptr_t index)
00677 {
00678     float fx, fy, fz;
00679     int vx, vy, vz;
00680     
00681     if ( !finite(co[0]) ||
00682          !finite(co[1]) ||
00683          !finite(co[2]))
00684     {
00685         return;
00686     }
00687     
00688     fx= (co[0]-offs[0])/div[0];
00689     fy= (co[1]-offs[1])/div[1];
00690     fz= (co[2]-offs[2])/div[2];
00691     CLAMP(fx, 0.0f, MOC_RES-MOC_THRESH);
00692     CLAMP(fy, 0.0f, MOC_RES-MOC_THRESH);
00693     CLAMP(fz, 0.0f, MOC_RES-MOC_THRESH);
00694     
00695     vx= (int)floorf(fx);
00696     vy= (int)floorf(fy);
00697     vz= (int)floorf(fz);
00698 
00699     mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz), index);
00700 
00701     if (vx > 0)
00702         if (fx-((float)vx)-MOC_THRESH < 0.0f)
00703             mesh_octree_add_node(basetable + MOC_INDEX(vx - 1, vy, vz), index);
00704     if (vx < MOC_RES - 2)
00705         if (fx-((float)vx)+MOC_THRESH > 1.0f)
00706             mesh_octree_add_node(basetable + MOC_INDEX(vx + 1, vy, vz), index);
00707 
00708     if (vy > 0)
00709         if (fy-((float)vy)-MOC_THRESH < 0.0f)
00710             mesh_octree_add_node(basetable + MOC_INDEX(vx, vy - 1, vz), index);
00711     if (vy < MOC_RES - 2)
00712         if (fy-((float)vy)+MOC_THRESH > 1.0f)
00713             mesh_octree_add_node(basetable + MOC_INDEX(vx, vy + 1, vz), index);
00714 
00715     if (vz > 0)
00716         if (fz-((float)vz)-MOC_THRESH < 0.0f)
00717             mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz - 1), index);
00718     if (vz <MOC_RES - 2)
00719         if (fz-((float)vz)+MOC_THRESH > 1.0f)
00720             mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz + 1), index);
00721 
00722 }
00723 
00724 static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
00725 {
00726     float *vec;
00727     int a;
00728     
00729     if(*bt==NULL)
00730         return -1;
00731     
00732     for(a=0; a<MOC_NODE_RES; a++) {
00733         if((*bt)->index[a]) {
00734             /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */
00735             if(mvert) {
00736                 vec= (mvert+(*bt)->index[a]-1)->co;
00737                 if(compare_v3v3(vec, co, MOC_THRESH))
00738                     return (*bt)->index[a]-1;
00739             }
00740             else {
00741                 EditVert *eve= (EditVert *)((*bt)->index[a]);
00742                 if(compare_v3v3(eve->co, co, MOC_THRESH))
00743                     return (*bt)->index[a];
00744             }
00745         }
00746         else return -1;
00747     }
00748     if( (*bt)->next)
00749         return mesh_octree_find_index(&(*bt)->next, mvert, co);
00750     
00751     return -1;
00752 }
00753 
00754 static struct {
00755     MocNode **table;
00756     float offs[3], div[3];
00757 } MeshOctree = {NULL, {0, 0, 0}, {0, 0, 0}};
00758 
00759 /* mode is 's' start, or 'e' end, or 'u' use */
00760 /* if end, ob can be NULL */
00761 intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
00762 {
00763     MocNode **bt;
00764     
00765     if(mode=='u') {     /* use table */
00766         if(MeshOctree.table==NULL)
00767             mesh_octree_table(ob, em, NULL, 's');
00768 
00769         if(MeshOctree.table) {
00770             Mesh *me= ob->data;
00771             bt= MeshOctree.table + mesh_octree_get_base_offs(co, MeshOctree.offs, MeshOctree.div);
00772             if(em)
00773                 return mesh_octree_find_index(bt, NULL, co);
00774             else
00775                 return mesh_octree_find_index(bt, me->mvert, co);
00776         }
00777         return -1;
00778     }
00779     else if(mode=='s') {    /* start table */
00780         Mesh *me= ob->data;
00781         float min[3], max[3];
00782 
00783         /* we compute own bounding box and don't reuse ob->bb because
00784          * we are using the undeformed coordinates*/
00785         INIT_MINMAX(min, max);
00786 
00787         if(em && me->edit_mesh==em) {
00788             EditVert *eve;
00789             
00790             for(eve= em->verts.first; eve; eve= eve->next)
00791                 DO_MINMAX(eve->co, min, max)
00792         }
00793         else {      
00794             MVert *mvert;
00795             int a;
00796             
00797             for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++)
00798                 DO_MINMAX(mvert->co, min, max);
00799         }
00800         
00801         /* for quick unit coordinate calculus */
00802         VECCOPY(MeshOctree.offs, min);
00803         MeshOctree.offs[0]-= MOC_THRESH;        /* we offset it 1 threshold unit extra */
00804         MeshOctree.offs[1]-= MOC_THRESH;
00805         MeshOctree.offs[2]-= MOC_THRESH;
00806         
00807         sub_v3_v3v3(MeshOctree.div, max, min);
00808         MeshOctree.div[0]+= 2*MOC_THRESH;   /* and divide with 2 threshold unit more extra (try 8x8 unit grid on paint) */
00809         MeshOctree.div[1]+= 2*MOC_THRESH;
00810         MeshOctree.div[2]+= 2*MOC_THRESH;
00811         
00812         mul_v3_fl(MeshOctree.div, 1.0f/MOC_RES);
00813         if(MeshOctree.div[0]==0.0f) MeshOctree.div[0]= 1.0f;
00814         if(MeshOctree.div[1]==0.0f) MeshOctree.div[1]= 1.0f;
00815         if(MeshOctree.div[2]==0.0f) MeshOctree.div[2]= 1.0f;
00816             
00817         if(MeshOctree.table) /* happens when entering this call without ending it */
00818             mesh_octree_table(ob, em, co, 'e');
00819         
00820         MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table");
00821         
00822         if(em && me->edit_mesh==em) {
00823             EditVert *eve;
00824 
00825             for(eve= em->verts.first; eve; eve= eve->next) {
00826                 mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve));
00827             }
00828         }
00829         else {      
00830             MVert *mvert;
00831             int a;
00832             
00833             for(a=0, mvert= me->mvert; a<me->totvert; a++, mvert++)
00834                 mesh_octree_add_nodes(MeshOctree.table, mvert->co, MeshOctree.offs, MeshOctree.div, a+1);
00835         }
00836     }
00837     else if(mode=='e') { /* end table */
00838         if(MeshOctree.table) {
00839             int a;
00840             
00841             for(a=0, bt=MeshOctree.table; a<MOC_RES*MOC_RES*MOC_RES; a++, bt++) {
00842                 if(*bt) mesh_octree_free_node(bt);
00843             }
00844             MEM_freeN(MeshOctree.table);
00845             MeshOctree.table= NULL;
00846         }
00847     }
00848     return 0;
00849 }
00850 
00851 MirrTopoStore_t mesh_topo_store= {NULL, -1. -1, -1};
00852 
00853 /* mode is 's' start, or 'e' end, or 'u' use */
00854 /* if end, ob can be NULL */
00855 /* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */
00856 int mesh_mirrtopo_table(Object *ob, char mode)
00857 {
00858     if(mode=='u') {     /* use table */
00859         if (ED_mesh_mirrtopo_recalc_check(ob->data, ob->mode, &mesh_topo_store)) {
00860             mesh_mirrtopo_table(ob, 's');
00861         }
00862     }
00863     else if(mode=='s') { /* start table */
00864         ED_mesh_mirrtopo_init(ob->data, ob->mode, &mesh_topo_store, FALSE);
00865     }
00866     else if(mode=='e') { /* end table */
00867         ED_mesh_mirrtopo_free(&mesh_topo_store);
00868     }
00869     return 0;
00870 }
00871 
00872 static int mesh_get_x_mirror_vert_spacial(Object *ob, int index)
00873 {
00874     Mesh *me= ob->data;
00875     MVert *mvert;
00876     float vec[3];
00877     
00878     mvert= me->mvert+index;
00879     vec[0]= -mvert->co[0];
00880     vec[1]= mvert->co[1];
00881     vec[2]= mvert->co[2];
00882     
00883     return mesh_octree_table(ob, NULL, vec, 'u');
00884 }
00885 
00886 static int mesh_get_x_mirror_vert_topo(Object *ob, int index)
00887 {
00888     if (mesh_mirrtopo_table(ob, 'u')==-1)
00889         return -1;
00890 
00891     return mesh_topo_store.index_lookup[index];
00892 }
00893 
00894 int mesh_get_x_mirror_vert(Object *ob, int index)
00895 {
00896     if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) {
00897         return mesh_get_x_mirror_vert_topo(ob, index);
00898     } else {
00899         return mesh_get_x_mirror_vert_spacial(ob, index);
00900     }
00901 }
00902 
00903 static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, float *co)
00904 {
00905     float vec[3];
00906     intptr_t poinval;
00907     
00908     /* ignore nan verts */
00909     if (!finite(co[0]) ||
00910         !finite(co[1]) ||
00911         !finite(co[2])
00912        )
00913         return NULL;
00914     
00915     vec[0]= -co[0];
00916     vec[1]= co[1];
00917     vec[2]= co[2];
00918     
00919     poinval= mesh_octree_table(ob, em, vec, 'u');
00920     if(poinval != -1)
00921         return (EditVert *)(poinval);
00922     return NULL;
00923 }
00924 
00925 static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em, EditVert *eve, int index)
00926 {
00927     intptr_t poinval;
00928     if (mesh_mirrtopo_table(ob, 'u')==-1)
00929         return NULL;
00930 
00931     if (index == -1) {
00932         index = BLI_findindex(&em->verts, eve);
00933 
00934         if (index == -1) {
00935             return NULL;
00936         }
00937     }
00938 
00939     poinval= mesh_topo_store.index_lookup[index];
00940 
00941     if(poinval != -1)
00942         return (EditVert *)(poinval);
00943     return NULL;
00944 }   
00945 
00946 EditVert *editmesh_get_x_mirror_vert(Object *ob, struct EditMesh *em, EditVert *eve, float *co, int index)
00947 {
00948     if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) {
00949         return editmesh_get_x_mirror_vert_topo(ob, em, eve, index);
00950     } else {
00951         return editmesh_get_x_mirror_vert_spacial(ob, em, co);
00952     }
00953 }
00954 
00955 
00956 #if 0
00957 float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_cent)
00958 {
00959     float vec[2];
00960     float cent_vec[2];
00961     float cent[2];
00962 
00963     /* ignore nan verts */
00964     if (isnan(uv[0]) || !finite(uv[0]) ||
00965         isnan(uv[1]) || !finite(uv[1])
00966        )
00967         return NULL;
00968 
00969     if (axis) {
00970         vec[0]= uv[0];
00971         vec[1]= -((uv[1])-mirrCent[1]) + mirrCent[1];
00972 
00973         cent_vec[0] = face_cent[0];
00974         cent_vec[1]= -((face_cent[1])-mirrCent[1]) + mirrCent[1];
00975     } else {
00976         vec[0]= -((uv[0])-mirrCent[0]) + mirrCent[0];
00977         vec[1]= uv[1];
00978 
00979         cent_vec[0]= -((face_cent[0])-mirrCent[0]) + mirrCent[0];
00980         cent_vec[1] = face_cent[1];
00981     }
00982 
00983     /* TODO - Optimize */
00984     {
00985         EditFace *efa;
00986         int i, len;
00987         for(efa=em->faces.first; efa; efa=efa->next) {
00988             MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00989             uv_center(tf->uv, cent, (void *)efa->v4);
00990 
00991             if ( (fabs(cent[0] - cent_vec[0]) < 0.001) && (fabs(cent[1] - cent_vec[1]) < 0.001) ) {
00992                 len = efa->v4 ? 4 : 3;
00993                 for (i=0; i<len; i++) {
00994                     if ( (fabs(tf->uv[i][0] - vec[0]) < 0.001) && (fabs(tf->uv[i][1] - vec[1]) < 0.001) ) {
00995                         return tf->uv[i];
00996                     }
00997                 }
00998             }
00999         }
01000     }
01001 
01002     return NULL;
01003 }
01004 #endif
01005 
01006 static unsigned int mirror_facehash(const void *ptr)
01007 {
01008     const MFace *mf= ptr;
01009     int v0, v1;
01010 
01011     if(mf->v4) {
01012         v0= MIN4(mf->v1, mf->v2, mf->v3, mf->v4);
01013         v1= MAX4(mf->v1, mf->v2, mf->v3, mf->v4);
01014     }
01015     else {
01016         v0= MIN3(mf->v1, mf->v2, mf->v3);
01017         v1= MAX3(mf->v1, mf->v2, mf->v3);
01018     }
01019 
01020     return ((v0*39)^(v1*31));
01021 }
01022 
01023 static int mirror_facerotation(MFace *a, MFace *b)
01024 {
01025     if(b->v4) {
01026         if(a->v1==b->v1 && a->v2==b->v2 && a->v3==b->v3 && a->v4==b->v4)
01027             return 0;
01028         else if(a->v4==b->v1 && a->v1==b->v2 && a->v2==b->v3 && a->v3==b->v4)
01029             return 1;
01030         else if(a->v3==b->v1 && a->v4==b->v2 && a->v1==b->v3 && a->v2==b->v4)
01031             return 2;
01032         else if(a->v2==b->v1 && a->v3==b->v2 && a->v4==b->v3 && a->v1==b->v4)
01033             return 3;
01034     }
01035     else {
01036         if(a->v1==b->v1 && a->v2==b->v2 && a->v3==b->v3)
01037             return 0;
01038         else if(a->v3==b->v1 && a->v1==b->v2 && a->v2==b->v3)
01039             return 1;
01040         else if(a->v2==b->v1 && a->v3==b->v2 && a->v1==b->v3)
01041             return 2;
01042     }
01043     
01044     return -1;
01045 }
01046 
01047 static int mirror_facecmp(const void *a, const void *b)
01048 {
01049     return (mirror_facerotation((MFace*)a, (MFace*)b) == -1);
01050 }
01051 
01052 int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em)
01053 {
01054     Mesh *me= ob->data;
01055     MVert *mv, *mvert= me->mvert;
01056     MFace mirrormf, *mf, *hashmf, *mface= me->mface;
01057     GHash *fhash;
01058     int *mirrorverts, *mirrorfaces;
01059     int a;
01060 
01061     mirrorverts= MEM_callocN(sizeof(int)*me->totvert, "MirrorVerts");
01062     mirrorfaces= MEM_callocN(sizeof(int)*2*me->totface, "MirrorFaces");
01063 
01064     mesh_octree_table(ob, em, NULL, 's');
01065 
01066     for(a=0, mv=mvert; a<me->totvert; a++, mv++)
01067         mirrorverts[a]= mesh_get_x_mirror_vert(ob, a);
01068 
01069     mesh_octree_table(ob, em, NULL, 'e');
01070 
01071     fhash= BLI_ghash_new(mirror_facehash, mirror_facecmp, "mirror_facehash gh");
01072     for(a=0, mf=mface; a<me->totface; a++, mf++)
01073         BLI_ghash_insert(fhash, mf, mf);
01074 
01075     for(a=0, mf=mface; a<me->totface; a++, mf++) {
01076         mirrormf.v1= mirrorverts[mf->v3];
01077         mirrormf.v2= mirrorverts[mf->v2];
01078         mirrormf.v3= mirrorverts[mf->v1];
01079         mirrormf.v4= (mf->v4)? mirrorverts[mf->v4]: 0;
01080 
01081         /* make sure v4 is not 0 if a quad */
01082         if(mf->v4 && mirrormf.v4==0) {
01083             SWAP(unsigned int, mirrormf.v1, mirrormf.v3);
01084             SWAP(unsigned int, mirrormf.v2, mirrormf.v4);
01085         }
01086 
01087         hashmf= BLI_ghash_lookup(fhash, &mirrormf);
01088         if(hashmf) {
01089             mirrorfaces[a*2]= hashmf - mface;
01090             mirrorfaces[a*2+1]= mirror_facerotation(&mirrormf, hashmf);
01091         }
01092         else
01093             mirrorfaces[a*2]= -1;
01094     }
01095 
01096     BLI_ghash_free(fhash, NULL, NULL);
01097     MEM_freeN(mirrorverts);
01098     
01099     return mirrorfaces;
01100 }