Blender  V2.59
BME_mesh.c
Go to the documentation of this file.
00001 /*
00002  * BME_mesh.c    jan 2007
00003  *
00004  *      BMesh mesh level functions.
00005  *
00006  * $Id: BME_mesh.c 35247 2011-02-27 20:40:57Z jesterking $
00007  *
00008  * ***** BEGIN GPL LICENSE BLOCK *****
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License
00012  * as published by the Free Software Foundation; either version 2
00013  * of the License, or (at your option) any later version.
00014  * about this.  
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00024  *
00025  * The Original Code is Copyright (C) 2007 Blender Foundation.
00026  * All rights reserved.
00027  *
00028  * The Original Code is: all of this file.
00029  *
00030  * Contributor(s): Geoffrey Bantle.
00031  *
00032  * ***** END GPL LICENSE BLOCK *****
00033  */
00034 
00041 #include "MEM_guardedalloc.h"
00042 #include "BKE_bmesh.h"
00043 #include "bmesh_private.h"
00044 
00045 /*      
00046  *      BME MAKE MESH
00047  *
00048  *  Allocates a new BME_Mesh structure.
00049  *  Returns -
00050  *  Pointer to a Bmesh
00051  *
00052 */
00053 
00054 BME_Mesh *BME_make_mesh(int allocsize[4])
00055 {
00056         /*allocate the structure*/
00057         BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
00058         /*allocate the memory pools for the mesh elements*/
00059         bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], 0);
00060         bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], 0);
00061         bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], 0);
00062         bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], 0);
00063         return bm;
00064 }
00065 /*      
00066  *      BME FREE MESH
00067  *
00068  *      Frees a BME_Mesh structure.
00069 */
00070 
00071 void BME_free_mesh(BME_Mesh *bm)
00072 {
00073         BME_Vert *v;
00074         BME_Edge *e;
00075         BME_Loop *l;
00076         BME_Poly *f;
00077 
00078         for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data);
00079         for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data);
00080         for(f=bm->polys.first; f; f=f->next){
00081                 CustomData_bmesh_free_block(&bm->pdata, &f->data);
00082                 l = f->loopbase;
00083                 do{
00084                         CustomData_bmesh_free_block(&bm->ldata, &l->data);
00085                         l = l->next;
00086                 }while(l!=f->loopbase);
00087         }
00088 
00089         /*Free custom data pools, This should probably go in CustomData_free?*/
00090         if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
00091         if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
00092         if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
00093         if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
00094 
00095          /*free custom data*/
00096         CustomData_free(&bm->vdata,0);
00097         CustomData_free(&bm->edata,0);
00098         CustomData_free(&bm->ldata,0);
00099         CustomData_free(&bm->pdata,0);
00100 
00101         /*destroy element pools*/
00102         BLI_mempool_destroy(bm->vpool);
00103         BLI_mempool_destroy(bm->epool);
00104         BLI_mempool_destroy(bm->ppool);
00105         BLI_mempool_destroy(bm->lpool);
00106         
00107         MEM_freeN(bm);  
00108 }
00109 
00110 /*      
00111  *      BME MODEL BEGIN AND END
00112  *
00113  *      These two functions represent the 'point of entry' for tools. Every BMesh tool
00114  *      must begin with a call to BME_model_end() and finish with a call to BME_model_end().
00115  *      No modification of mesh data is allowed except in between these two calls.
00116  *
00117  *  The purpose of these calls is allow for housekeeping tasks to be performed,
00118  *  such as allocating/freeing scratch arrays or performing debug validation of 
00119  *  the mesh structure.
00120  *
00121  *  Returns -
00122  *  Nothing
00123  *
00124 */
00125 
00126 int BME_model_begin(BME_Mesh *bm){
00127         /*Initialize some scratch pointer arrays used by eulers*/
00128         bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array");
00129         bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array");
00130         bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array");
00131         bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array");
00132 
00133         bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
00134 
00135         return 1;
00136 }
00137 
00138 void BME_model_end(BME_Mesh *bm){
00139         int meshok, totvert, totedge, totpoly;
00140 
00141         totvert = BLI_countlist(&(bm->verts));
00142         totedge = BLI_countlist(&(bm->edges));
00143         totpoly = BLI_countlist(&(bm->polys));
00144 
00145         if(bm->vtar) MEM_freeN(bm->vtar);
00146         if(bm->edar) MEM_freeN(bm->edar);
00147         if(bm->lpar) MEM_freeN(bm->lpar);
00148         if(bm->plar) MEM_freeN(bm->plar);
00149         
00150         bm->vtar = NULL;
00151         bm->edar = NULL;
00152         bm->lpar = NULL;
00153         bm->plar = NULL;
00154         bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
00155         
00156         
00157         if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly)
00158                 BME_error();
00159         
00160         meshok = BME_validate_mesh(bm, 1);
00161         if(!meshok){
00162                 BME_error();
00163         }
00164 }
00165 
00166 /*      
00167  *      BME VALIDATE MESH
00168  *
00169  *      There are several levels of validation for meshes. At the 
00170  *  Euler level, some basic validation is done to local topology.
00171  *  To catch more subtle problems however, BME_validate_mesh() is 
00172  *  called by BME_model_end() whenever a tool is done executing.
00173  *  The purpose of this function is to insure that during the course 
00174  *  of tool execution that nothing has been done to invalidate the 
00175  *  structure, and if it has, provide a way of reporting that so that
00176  *  we can restore the proper structure from a backup. Since a full mesh
00177  *  validation would be too expensive, this is presented as a compromise.
00178  *
00179  *      TODO 
00180  *      
00181  *      -Make this only part of debug builds
00182  */
00183 
00184 #define VHALT(halt) {BME_error(); if(halt) return 0;}
00185 
00186 int BME_validate_mesh(struct BME_Mesh *bm, int halt)
00187 {
00188         BME_Vert *v;
00189         BME_Edge *e;
00190         BME_Poly *f;
00191         BME_Loop *l;
00192         BME_CycleNode *diskbase;
00193         int i, ok;
00194         
00195         /*Simple edge verification*/
00196         for(e=bm->edges.first; e; e=e->next){
00197                 if(e->v1 == e->v2) VHALT(halt);
00198                 /*validate e->d1.data and e->d2.data*/
00199                 if(e->d1.data != e || e->d2.data != e) VHALT(halt);
00200                 /*validate e->loop->e*/
00201                 if(e->loop){
00202                         if(e->loop->e != e) VHALT(halt);
00203                 }
00204         }
00205         
00206         /*calculate disk cycle lengths*/
00207         for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0;
00208         for(e=bm->edges.first; e; e=e->next){ 
00209                 e->v1->tflag1++;
00210                 e->v2->tflag1++;
00211         }
00212         /*Validate vertices and disk cycle*/
00213         for(v=bm->verts.first; v; v=v->next){
00214                 /*validate v->edge pointer*/
00215                 if(v->tflag1){
00216                         if(v->edge){
00217                                 ok = BME_vert_in_edge(v->edge,v);
00218                                 if(!ok) VHALT(halt);
00219                                 /*validate length of disk cycle*/
00220                                 diskbase = BME_disk_getpointer(v->edge, v);
00221                                 ok = BME_cycle_validate(v->tflag1, diskbase);
00222                                 if(!ok) VHALT(halt);
00223                                 /*validate that each edge in disk cycle contains V*/
00224                                 for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
00225                                         ok = BME_vert_in_edge(e, v);
00226                                         if(!ok) VHALT(halt);
00227                                 }
00228                         }
00229                         else VHALT(halt);
00230                 }
00231         }
00232         /*validate edges*/
00233         for(e=bm->edges.first; e; e=e->next){
00234                 /*seperate these into BME_disk_hasedge (takes pointer to edge)*/
00235                 /*search v1 disk cycle for edge*/
00236                 ok = BME_disk_hasedge(e->v1,e);
00237                 if(!ok) VHALT(halt);
00238                 /*search v2 disk cycle for edge*/
00239                 ok = BME_disk_hasedge(e->v2,e);
00240                 if(!ok) VHALT(halt);
00241         }
00242         
00243         for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces
00244         /*Validate the loop cycle integrity.*/
00245         for(f=bm->polys.first; f; f=f->next){
00246                 ok = BME_cycle_length(f->loopbase);
00247                 if(ok > 1){
00248                         f->tflag1 = ok;
00249                 }
00250                 else VHALT(halt);
00251                 for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){
00252                         /*verify loop->v pointers*/
00253                         ok = BME_verts_in_edge(l->v, l->next->v, l->e);
00254                         if(!ok) VHALT(halt);
00255                         /*verify radial node data pointer*/
00256                         if(l->radial.data != l) VHALT(halt);
00257                         /*validate l->e->loop poitner*/
00258                         if(l->e->loop == NULL) VHALT(halt);
00259                         /*validate l->f pointer*/
00260                         if(l->f != f) VHALT(halt);
00261                         /*see if l->e->loop is actually in radial cycle*/
00262                         
00263                         l->e->tflag2++;
00264                  }
00265         }
00266         
00267         /*validate length of radial cycle*/
00268         for(e=bm->edges.first; e; e=e->next){
00269                 if(e->loop){
00270                         ok = BME_cycle_validate(e->tflag2,&(e->loop->radial));
00271                         if(!ok) VHALT(halt);
00272                 }
00273         }
00274         
00275         /*validate that EIDs are within range... if not indicates corrupted mem*/
00276 
00277         /*if we get this far, pretty safe to return 1*/
00278         return 1;
00279 }
00280 
00281 /*      Currently just a convient place for a breakpoint.
00282         Probably should take an error string
00283 */
00284 void BME_error(void){
00285         printf("BME modelling error!");
00286 }