Blender V2.61 - r43446
|
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 }