Blender  V2.59
MOD_boolean_util.c
Go to the documentation of this file.
00001 /*
00002  * $Id: MOD_boolean_util.c 35178 2011-02-25 13:57:17Z jesterking $
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) 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  * CSG operations. 
00029  */
00030 
00036 #include "DNA_material_types.h"
00037 #include "DNA_mesh_types.h"
00038 #include "DNA_meshdata_types.h"
00039 #include "DNA_object_types.h"
00040 #include "DNA_scene_types.h"
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "BLI_math.h"
00045 #include "BLI_utildefines.h"
00046 #include "BLI_ghash.h"
00047 
00048 #include "BKE_cdderivedmesh.h"
00049 #include "BKE_depsgraph.h"
00050 #include "BKE_material.h"
00051 #include "BKE_mesh.h"
00052 #include "BKE_object.h"
00053 
00054 #include "CSG_BooleanOps.h"
00055 
00056 #include "MOD_boolean_util.h"
00057 
00063 typedef struct {
00064         DerivedMesh *dm;
00065         Object *ob;
00066         int pos;
00067 } VertexIt;
00068 
00074 static void VertexIt_Destruct(CSG_VertexIteratorDescriptor * iterator)
00075 {
00076         if (iterator->it) {
00077                 // deallocate memory for iterator
00078                 MEM_freeN(iterator->it);
00079                 iterator->it = 0;
00080         }
00081         iterator->Done = NULL;
00082         iterator->Fill = NULL;
00083         iterator->Reset = NULL;
00084         iterator->Step = NULL;
00085         iterator->num_elements = 0;
00086 
00087 }               
00088 
00089 static int VertexIt_Done(CSG_IteratorPtr it)
00090 {
00091         VertexIt * iterator = (VertexIt *)it;
00092         return(iterator->pos >= iterator->dm->getNumVerts(iterator->dm));
00093 }
00094 
00095 static void VertexIt_Fill(CSG_IteratorPtr it, CSG_IVertex *vert)
00096 {
00097         VertexIt * iterator = (VertexIt *)it;
00098         MVert *verts = iterator->dm->getVertArray(iterator->dm);
00099 
00100         float global_pos[3];
00101 
00102         /* boolean happens in global space, transform both with obmat */
00103         mul_v3_m4v3(
00104                 global_pos,
00105                 iterator->ob->obmat, 
00106                 verts[iterator->pos].co
00107         );
00108 
00109         vert->position[0] = global_pos[0];
00110         vert->position[1] = global_pos[1];
00111         vert->position[2] = global_pos[2];
00112 }
00113 
00114 static void VertexIt_Step(CSG_IteratorPtr it)
00115 {
00116         VertexIt * iterator = (VertexIt *)it;
00117         iterator->pos ++;
00118 } 
00119  
00120 static void VertexIt_Reset(CSG_IteratorPtr it)
00121 {
00122         VertexIt * iterator = (VertexIt *)it;
00123         iterator->pos = 0;
00124 }
00125 
00126 static void VertexIt_Construct(CSG_VertexIteratorDescriptor *output, DerivedMesh *dm, Object *ob)
00127 {
00128 
00129         VertexIt *it;
00130         if (output == 0) return;
00131 
00132         // allocate some memory for blender iterator
00133         it = (VertexIt *)(MEM_mallocN(sizeof(VertexIt),"Boolean_VIt"));
00134         if (it == 0) {
00135                 return;
00136         }
00137         // assign blender specific variables
00138         it->dm = dm;
00139         it->ob = ob; // needed for obmat transformations 
00140         
00141         it->pos = 0;
00142 
00143          // assign iterator function pointers.
00144         output->Step = VertexIt_Step;
00145         output->Fill = VertexIt_Fill;
00146         output->Done = VertexIt_Done;
00147         output->Reset = VertexIt_Reset;
00148         output->num_elements = it->dm->getNumVerts(it->dm);
00149         output->it = it;
00150 }
00151 
00156 typedef struct {
00157         DerivedMesh *dm;
00158         int pos;
00159         int offset;
00160         int flip;
00161 } FaceIt;
00162 
00163 static void FaceIt_Destruct(CSG_FaceIteratorDescriptor * iterator)
00164 {
00165         MEM_freeN(iterator->it);
00166         iterator->Done = NULL;
00167         iterator->Fill = NULL;
00168         iterator->Reset = NULL;
00169         iterator->Step = NULL;
00170         iterator->num_elements = 0;
00171 }
00172 
00173 static int FaceIt_Done(CSG_IteratorPtr it)
00174 {
00175         // assume CSG_IteratorPtr is of the correct type.
00176         FaceIt * iterator = (FaceIt *)it;
00177         return(iterator->pos >= iterator->dm->getNumFaces(iterator->dm));
00178 }
00179 
00180 static void FaceIt_Fill(CSG_IteratorPtr it, CSG_IFace *face)
00181 {
00182         // assume CSG_IteratorPtr is of the correct type.
00183         FaceIt *face_it = (FaceIt *)it;
00184         MFace *mfaces = face_it->dm->getFaceArray(face_it->dm);
00185         MFace *mface = &mfaces[face_it->pos];
00186 
00187         /* reverse face vertices if necessary */
00188         face->vertex_index[1] = mface->v2;
00189         if( face_it->flip == 0 ) {
00190         face->vertex_index[0] = mface->v1;
00191         face->vertex_index[2] = mface->v3;
00192         } else {
00193                 face->vertex_index[2] = mface->v1;
00194                 face->vertex_index[0] = mface->v3;
00195         }
00196         if (mface->v4) {
00197                 face->vertex_index[3] = mface->v4;
00198                 face->vertex_number = 4;
00199         } else {
00200                 face->vertex_number = 3;
00201         }
00202 
00203         face->orig_face = face_it->offset + face_it->pos;
00204 }
00205 
00206 static void FaceIt_Step(CSG_IteratorPtr it)
00207 {
00208         FaceIt * face_it = (FaceIt *)it;                
00209         face_it->pos ++;
00210 }
00211 
00212 static void FaceIt_Reset(CSG_IteratorPtr it)
00213 {
00214         FaceIt * face_it = (FaceIt *)it;                
00215         face_it->pos = 0;
00216 }       
00217 
00218 static void FaceIt_Construct(
00219         CSG_FaceIteratorDescriptor *output, DerivedMesh *dm, int offset, Object *ob)
00220 {
00221         FaceIt *it;
00222         if (output == 0) return;
00223 
00224         // allocate some memory for blender iterator
00225         it = (FaceIt *)(MEM_mallocN(sizeof(FaceIt),"Boolean_FIt"));
00226         if (it == 0) {
00227                 return ;
00228         }
00229         // assign blender specific variables
00230         it->dm = dm;
00231         it->offset = offset;
00232         it->pos = 0;
00233 
00234         /* determine if we will need to reverse order of face vertices */
00235         if (ob->size[0] < 0.0f) {
00236                 if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) {
00237                         it->flip = 1;
00238                 } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) {
00239                         it->flip = 1;
00240                 } else {
00241                         it->flip = 0;
00242                 }
00243         } else {
00244                 if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) {
00245                         it->flip = 0;
00246                 } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) {
00247                         it->flip = 0;
00248                 } else {
00249                         it->flip = 1;
00250                 }
00251         }
00252 
00253         // assign iterator function pointers.
00254         output->Step = FaceIt_Step;
00255         output->Fill = FaceIt_Fill;
00256         output->Done = FaceIt_Done;
00257         output->Reset = FaceIt_Reset;
00258         output->num_elements = it->dm->getNumFaces(it->dm);
00259         output->it = it;
00260 }
00261 
00262 static Object *AddNewBlenderMesh(Scene *scene, Base *base)
00263 {
00264         // This little function adds a new mesh object to the blender object list
00265         // It uses ob to duplicate data as this seems to be easier than creating
00266         // a new one. This new oject contains no faces nor vertices.
00267         Mesh *old_me;
00268         Base *basen;
00269         Object *ob_new;
00270 
00271         // now create a new blender object.
00272         // duplicating all the settings from the previous object
00273         // to the new one.
00274         ob_new= copy_object(base->object);
00275 
00276         // Ok we don't want to use the actual data from the
00277         // last object, the above function incremented the 
00278         // number of users, so decrement it here.
00279         old_me= ob_new->data;
00280         old_me->id.us--;
00281 
00282         // Now create a new base to add into the linked list of 
00283         // vase objects.
00284         
00285         basen= MEM_mallocN(sizeof(Base), "duplibase");
00286         *basen= *base;
00287         BLI_addhead(&scene->base, basen);       /* addhead: anders oneindige lus */
00288         basen->object= ob_new;
00289         basen->flag &= ~SELECT;
00290                                 
00291         // Initialize the mesh data associated with this object.                                                
00292         ob_new->data= add_mesh("Mesh");
00293 
00294         // Finally assign the object type.
00295         ob_new->type= OB_MESH;
00296 
00297         return ob_new;
00298 }
00299 
00300 static void InterpCSGFace(
00301         DerivedMesh *dm, DerivedMesh *orig_dm, int index, int orig_index, int nr,
00302         float mapmat[][4])
00303 {
00304         float obco[3], *co[4], *orig_co[4], w[4][4];
00305         MFace *mface, *orig_mface;
00306         int j;
00307 
00308         mface = CDDM_get_face(dm, index);
00309         orig_mface = orig_dm->getFaceArray(orig_dm) + orig_index;
00310 
00311         // get the vertex coordinates from the original mesh
00312         orig_co[0] = (orig_dm->getVertArray(orig_dm) + orig_mface->v1)->co;
00313         orig_co[1] = (orig_dm->getVertArray(orig_dm) + orig_mface->v2)->co;
00314         orig_co[2] = (orig_dm->getVertArray(orig_dm) + orig_mface->v3)->co;
00315         orig_co[3] = (orig_mface->v4)? (orig_dm->getVertArray(orig_dm) + orig_mface->v4)->co: NULL;
00316 
00317         // get the vertex coordinates from the new derivedmesh
00318         co[0] = CDDM_get_vert(dm, mface->v1)->co;
00319         co[1] = CDDM_get_vert(dm, mface->v2)->co;
00320         co[2] = CDDM_get_vert(dm, mface->v3)->co;
00321         co[3] = (nr == 4)? CDDM_get_vert(dm, mface->v4)->co: NULL;
00322 
00323         for (j = 0; j < nr; j++) {
00324                 // get coordinate into the space of the original mesh
00325                 if (mapmat)
00326                         mul_v3_m4v3(obco, mapmat, co[j]);
00327                 else
00328                         copy_v3_v3(obco, co[j]);
00329 
00330                 interp_weights_face_v3( w[j],orig_co[0], orig_co[1], orig_co[2], orig_co[3], obco);
00331         }
00332 
00333         CustomData_interp(&orig_dm->faceData, &dm->faceData, &orig_index, NULL, (float*)w, 1, index);
00334 }
00335 
00336 /* Iterate over the CSG Output Descriptors and create a new DerivedMesh
00337    from them */
00338 static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
00339         CSG_FaceIteratorDescriptor *face_it,
00340         CSG_VertexIteratorDescriptor *vertex_it,
00341         float parinv[][4],
00342         float mapmat[][4],
00343         Material **mat,
00344         int *totmat,
00345         DerivedMesh *dm1,
00346         Object *ob1,
00347         DerivedMesh *dm2,
00348         Object *ob2)
00349 {
00350         DerivedMesh *result, *orig_dm;
00351         GHash *material_hash = NULL;
00352         Mesh *me1= (Mesh*)ob1->data;
00353         Mesh *me2= (Mesh*)ob2->data;
00354         int i;
00355 
00356         // create a new DerivedMesh
00357         result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements);
00358         CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
00359                                           CD_DEFAULT, face_it->num_elements); 
00360         CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
00361                                           CD_DEFAULT, face_it->num_elements); 
00362 
00363         // step through the vertex iterators:
00364         for (i = 0; !vertex_it->Done(vertex_it->it); i++) {
00365                 CSG_IVertex csgvert;
00366                 MVert *mvert = CDDM_get_vert(result, i);
00367 
00368                 // retrieve a csg vertex from the boolean module
00369                 vertex_it->Fill(vertex_it->it, &csgvert);
00370                 vertex_it->Step(vertex_it->it);
00371 
00372                 // we have to map the vertex coordinates back in the coordinate frame
00373                 // of the resulting object, since it was computed in world space
00374                 mul_v3_m4v3(mvert->co, parinv, csgvert.position);
00375         }
00376 
00377         // a hash table to remap materials to indices
00378         if (mat) {
00379                 material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "CSG_mat gh");
00380                 *totmat = 0;
00381         }
00382 
00383         // step through the face iterators
00384         for(i = 0; !face_it->Done(face_it->it); i++) {
00385                 Mesh *orig_me;
00386                 Object *orig_ob;
00387                 Material *orig_mat;
00388                 CSG_IFace csgface;
00389                 MFace *mface;
00390                 int orig_index, mat_nr;
00391 
00392                 // retrieve a csg face from the boolean module
00393                 face_it->Fill(face_it->it, &csgface);
00394                 face_it->Step(face_it->it);
00395 
00396                 // find the original mesh and data
00397                 orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2;
00398                 orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2;
00399                 orig_me = (orig_ob == ob1)? me1: me2;
00400                 orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1);
00401 
00402                 // copy all face layers, including mface
00403                 CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1);
00404 
00405                 // set mface
00406                 mface = CDDM_get_face(result, i);
00407                 mface->v1 = csgface.vertex_index[0];
00408                 mface->v2 = csgface.vertex_index[1];
00409                 mface->v3 = csgface.vertex_index[2];
00410                 mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0;
00411 
00412                 // set material, based on lookup in hash table
00413                 orig_mat= give_current_material(orig_ob, mface->mat_nr+1);
00414 
00415                 if (mat && orig_mat) {
00416                         if (!BLI_ghash_haskey(material_hash, orig_mat)) {
00417                                 mat[*totmat] = orig_mat;
00418                                 mat_nr = mface->mat_nr = (*totmat)++;
00419                                 BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr));
00420                         }
00421                         else
00422                                 mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat));
00423                 }
00424                 else
00425                         mface->mat_nr = 0;
00426 
00427                 InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number,
00428                                           (orig_me == me2)? mapmat: NULL);
00429 
00430                 test_index_face(mface, &result->faceData, i, csgface.vertex_number);
00431         }
00432 
00433         if (material_hash)
00434                 BLI_ghash_free(material_hash, NULL, NULL);
00435 
00436         CDDM_calc_edges(result);
00437         CDDM_calc_normals(result);
00438 
00439         return result;
00440 }
00441         
00442 static void BuildMeshDescriptors(
00443         struct DerivedMesh *dm,
00444         struct Object *ob,
00445         int face_offset,
00446         struct CSG_FaceIteratorDescriptor * face_it,
00447         struct CSG_VertexIteratorDescriptor * vertex_it)
00448 {
00449         VertexIt_Construct(vertex_it,dm, ob);
00450         FaceIt_Construct(face_it,dm,face_offset,ob);
00451 }
00452         
00453 static void FreeMeshDescriptors(
00454         struct CSG_FaceIteratorDescriptor *face_it,
00455         struct CSG_VertexIteratorDescriptor *vertex_it)
00456 {
00457         VertexIt_Destruct(vertex_it);
00458         FaceIt_Destruct(face_it);
00459 }
00460 
00461 static DerivedMesh *NewBooleanDerivedMesh_intern(
00462         DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select,
00463         int int_op_type, Material **mat, int *totmat)
00464 {
00465 
00466         float inv_mat[4][4];
00467         float map_mat[4][4];
00468 
00469         DerivedMesh *result = NULL;
00470 
00471         if (dm == NULL || dm_select == NULL) return 0;
00472         if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) return 0;
00473 
00474         // we map the final object back into ob's local coordinate space. For this
00475         // we need to compute the inverse transform from global to ob (inv_mat),
00476         // and the transform from ob to ob_select for use in interpolation (map_mat)
00477         invert_m4_m4(inv_mat, ob->obmat);
00478         mul_m4_m4m4(map_mat, ob_select->obmat, inv_mat);
00479         invert_m4_m4(inv_mat, ob_select->obmat);
00480 
00481         {
00482                 // interface with the boolean module:
00483                 //
00484                 // the idea is, we pass the boolean module verts and faces using the
00485                 // provided descriptors. once the boolean operation is performed, we
00486                 // get back output descriptors, from which we then build a DerivedMesh
00487 
00488                 CSG_VertexIteratorDescriptor vd_1, vd_2;
00489                 CSG_FaceIteratorDescriptor fd_1, fd_2;
00490                 CSG_OperationType op_type;
00491                 CSG_BooleanOperation *bool_op;
00492 
00493                 // work out the operation they chose and pick the appropriate 
00494                 // enum from the csg module.
00495                 switch (int_op_type) {
00496                         case 1 : op_type = e_csg_intersection; break;
00497                         case 2 : op_type = e_csg_union; break;
00498                         case 3 : op_type = e_csg_difference; break;
00499                         case 4 : op_type = e_csg_classify; break;
00500                         default : op_type = e_csg_intersection;
00501                 }
00502                 
00503                 BuildMeshDescriptors(dm_select, ob_select, 0, &fd_1, &vd_1);
00504                 BuildMeshDescriptors(dm, ob, dm_select->getNumFaces(dm_select) , &fd_2, &vd_2);
00505 
00506                 bool_op = CSG_NewBooleanFunction();
00507 
00508                 // perform the operation
00509                 if (CSG_PerformBooleanOperation(bool_op, op_type, fd_1, vd_1, fd_2, vd_2)) {
00510                         CSG_VertexIteratorDescriptor vd_o;
00511                         CSG_FaceIteratorDescriptor fd_o;
00512 
00513                         CSG_OutputFaceDescriptor(bool_op, &fd_o);
00514                         CSG_OutputVertexDescriptor(bool_op, &vd_o);
00515 
00516                         // iterate through results of operation and insert
00517                         // into new object
00518                         result = ConvertCSGDescriptorsToDerivedMesh(
00519                                 &fd_o, &vd_o, inv_mat, map_mat, mat, totmat, dm_select, ob_select, dm, ob);
00520 
00521                         // free up the memory
00522                         CSG_FreeVertexDescriptor(&vd_o);
00523                         CSG_FreeFaceDescriptor(&fd_o);
00524                 }
00525                 else
00526                         printf("Unknown internal error in boolean");
00527 
00528                 CSG_FreeBooleanOperation(bool_op);
00529 
00530                 FreeMeshDescriptors(&fd_1, &vd_1);
00531                 FreeMeshDescriptors(&fd_2, &vd_2);
00532         }
00533 
00534         return result;
00535 }
00536 
00537 int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type)
00538 {
00539         Mesh *me_new;
00540         int a, maxmat, totmat= 0;
00541         Object *ob_new, *ob, *ob_select;
00542         Material **mat;
00543         DerivedMesh *result;
00544         DerivedMesh *dm_select;
00545         DerivedMesh *dm;
00546 
00547         ob= base->object;
00548         ob_select= base_select->object;
00549 
00550         dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
00551         dm_select = mesh_create_derived_view(scene, ob_select, 0); // no modifiers in editmode ??
00552 
00553         maxmat= ob->totcol + ob_select->totcol;
00554         mat= (Material**)MEM_mallocN(sizeof(Material*)*maxmat, "NewBooleanMeshMat");
00555         
00556         /* put some checks in for nice user feedback */
00557         if (dm == NULL || dm_select == NULL) return 0;
00558         if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select))
00559         {
00560                 MEM_freeN(mat);
00561                 return -1;
00562         }
00563         
00564         result= NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, mat, &totmat);
00565 
00566         if (result == NULL) {
00567                 MEM_freeN(mat);
00568                 return 0;
00569         }
00570 
00571         /* create a new blender mesh object - using 'base' as  a template */
00572         ob_new= AddNewBlenderMesh(scene, base_select);
00573         me_new= ob_new->data;
00574 
00575         DM_to_mesh(result, me_new);
00576         result->release(result);
00577 
00578         dm->release(dm);
00579         dm_select->release(dm_select);
00580 
00581         /* add materials to object */
00582         for (a = 0; a < totmat; a++)
00583                 assign_material(ob_new, mat[a], a+1);
00584 
00585         MEM_freeN(mat);
00586 
00587         /* update dag */
00588         DAG_id_tag_update(&ob_new->id, OB_RECALC_DATA);
00589 
00590         return 1;
00591 }
00592 
00593 DerivedMesh *NewBooleanDerivedMesh(DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select,
00594                                                                    int int_op_type)
00595 {
00596         return NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, NULL, NULL);
00597 }