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