2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2008-02-23 22:11:16 +00:00
|
|
|
* BME_mesh.c jan 2007
|
|
|
|
|
*
|
|
|
|
|
* BMesh mesh level functions.
|
|
|
|
|
*
|
2009-03-31 22:34:34 +00:00
|
|
|
* $Id$
|
2008-02-23 22:11:16 +00:00
|
|
|
*
|
2008-04-16 22:40:48 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
2008-02-23 22:11:16 +00:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2008-04-16 22:40:48 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
2008-02-23 22:11:16 +00:00
|
|
|
* about this.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2008-02-23 22:11:16 +00:00
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2007 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): Geoffrey Bantle.
|
|
|
|
|
*
|
2008-04-16 22:40:48 +00:00
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
2008-02-23 22:11:16 +00:00
|
|
|
*/
|
|
|
|
|
|
2011-02-27 20:40:57 +00:00
|
|
|
/** \file blender/blenkernel/intern/BME_mesh.c
|
|
|
|
|
* \ingroup bke
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2008-02-23 22:11:16 +00:00
|
|
|
|
2008-07-04 17:59:16 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2008-02-23 22:11:16 +00:00
|
|
|
#include "BKE_bmesh.h"
|
|
|
|
|
#include "bmesh_private.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* BME MAKE MESH
|
|
|
|
|
*
|
2008-06-02 20:52:40 +00:00
|
|
|
* Allocates a new BME_Mesh structure.
|
|
|
|
|
* Returns -
|
|
|
|
|
* Pointer to a Bmesh
|
|
|
|
|
*
|
2008-02-23 22:11:16 +00:00
|
|
|
*/
|
|
|
|
|
|
2008-07-04 17:59:16 +00:00
|
|
|
BME_Mesh *BME_make_mesh(int allocsize[4])
|
2008-06-02 20:52:40 +00:00
|
|
|
{
|
2008-06-01 17:15:03 +00:00
|
|
|
/*allocate the structure*/
|
2008-02-23 22:11:16 +00:00
|
|
|
BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
|
2008-06-01 17:15:03 +00:00
|
|
|
/*allocate the memory pools for the mesh elements*/
|
Added a new notifyer, NC_SPACE_CHANGED, to signal an editor that
replaces another so it can do updates (e.g. dopesheet editor can
sync channel selection).
Also coded a simple optimization for allocating small objects,
based on mempools. It's #ifdef'd out, you can enabled it by
defining OPTIMIZE_SMALL_BLOCKS (e.g. adding -DDOPTIMIZE_SMALL_BLOCKS to
your compiler flags).
We suffer from a great deal of performance loss from the system allocator
(vgroups, ghash, edgehash, the singly-linked list implementation in blenlib,
editmesh, and likely a great many areas I'm forgetting), and this is the
common solution for handling the many-small-objects problem. It's not
really production-ready yet (it's long-term memory consequencers need to
be profiled first, and the implementation tweaked as necassary), but for
people on systems with slow system allocators it's worth trying.
Note that since this creates a guardedalloc<->blenlib link, the build systems
need to be updated accordingly (I've already done this for scons, though I'm
not sure if the player builds).
2010-01-21 03:08:57 +00:00
|
|
|
bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], 0);
|
|
|
|
|
bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], 0);
|
|
|
|
|
bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], 0);
|
|
|
|
|
bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], 0);
|
2008-06-01 18:02:29 +00:00
|
|
|
return bm;
|
|
|
|
|
}
|
2008-02-23 22:11:16 +00:00
|
|
|
/*
|
|
|
|
|
* BME FREE MESH
|
|
|
|
|
*
|
|
|
|
|
* Frees a BME_Mesh structure.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void BME_free_mesh(BME_Mesh *bm)
|
|
|
|
|
{
|
2008-06-02 20:52:40 +00:00
|
|
|
BME_Vert *v;
|
|
|
|
|
BME_Edge *e;
|
|
|
|
|
BME_Loop *l;
|
|
|
|
|
BME_Poly *f;
|
|
|
|
|
|
2008-07-04 17:59:16 +00:00
|
|
|
for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data);
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data);
|
2008-06-02 20:52:40 +00:00
|
|
|
for(f=bm->polys.first; f; f=f->next){
|
2008-07-04 17:59:16 +00:00
|
|
|
CustomData_bmesh_free_block(&bm->pdata, &f->data);
|
2008-06-02 20:52:40 +00:00
|
|
|
l = f->loopbase;
|
|
|
|
|
do{
|
2008-07-04 17:59:16 +00:00
|
|
|
CustomData_bmesh_free_block(&bm->ldata, &l->data);
|
2008-06-02 20:52:40 +00:00
|
|
|
l = l->next;
|
|
|
|
|
}while(l!=f->loopbase);
|
|
|
|
|
}
|
2008-07-04 17:59:16 +00:00
|
|
|
|
|
|
|
|
/*Free custom data pools, This should probably go in CustomData_free?*/
|
|
|
|
|
if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
|
|
|
|
|
if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
|
|
|
|
|
if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
|
|
|
|
|
if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
|
|
|
|
|
|
2010-03-22 09:30:00 +00:00
|
|
|
/*free custom data*/
|
2008-07-04 17:59:16 +00:00
|
|
|
CustomData_free(&bm->vdata,0);
|
|
|
|
|
CustomData_free(&bm->edata,0);
|
|
|
|
|
CustomData_free(&bm->ldata,0);
|
|
|
|
|
CustomData_free(&bm->pdata,0);
|
|
|
|
|
|
2008-06-01 17:15:03 +00:00
|
|
|
/*destroy element pools*/
|
2008-07-04 17:59:16 +00:00
|
|
|
BLI_mempool_destroy(bm->vpool);
|
|
|
|
|
BLI_mempool_destroy(bm->epool);
|
|
|
|
|
BLI_mempool_destroy(bm->ppool);
|
|
|
|
|
BLI_mempool_destroy(bm->lpool);
|
|
|
|
|
|
2008-02-23 22:11:16 +00:00
|
|
|
MEM_freeN(bm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* BME MODEL BEGIN AND END
|
|
|
|
|
*
|
|
|
|
|
* These two functions represent the 'point of entry' for tools. Every BMesh tool
|
|
|
|
|
* must begin with a call to BME_model_end() and finish with a call to BME_model_end().
|
|
|
|
|
* No modification of mesh data is allowed except in between these two calls.
|
|
|
|
|
*
|
2008-06-02 20:52:40 +00:00
|
|
|
* The purpose of these calls is allow for housekeeping tasks to be performed,
|
|
|
|
|
* such as allocating/freeing scratch arrays or performing debug validation of
|
|
|
|
|
* the mesh structure.
|
2008-02-23 22:11:16 +00:00
|
|
|
*
|
2008-06-02 20:52:40 +00:00
|
|
|
* Returns -
|
|
|
|
|
* Nothing
|
2008-02-23 22:11:16 +00:00
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int BME_model_begin(BME_Mesh *bm){
|
2008-02-29 20:26:35 +00:00
|
|
|
/*Initialize some scratch pointer arrays used by eulers*/
|
|
|
|
|
bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array");
|
2008-02-25 04:53:37 +00:00
|
|
|
bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array");
|
2008-02-29 20:26:35 +00:00
|
|
|
bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array");
|
|
|
|
|
bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array");
|
|
|
|
|
|
|
|
|
|
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
|
|
|
|
|
|
2008-02-23 22:11:16 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BME_model_end(BME_Mesh *bm){
|
2008-06-02 01:02:08 +00:00
|
|
|
int meshok, totvert, totedge, totpoly;
|
2008-02-23 22:11:16 +00:00
|
|
|
|
|
|
|
|
totvert = BLI_countlist(&(bm->verts));
|
|
|
|
|
totedge = BLI_countlist(&(bm->edges));
|
|
|
|
|
totpoly = BLI_countlist(&(bm->polys));
|
2008-06-01 17:15:03 +00:00
|
|
|
|
2008-02-29 20:26:35 +00:00
|
|
|
if(bm->vtar) MEM_freeN(bm->vtar);
|
|
|
|
|
if(bm->edar) MEM_freeN(bm->edar);
|
|
|
|
|
if(bm->lpar) MEM_freeN(bm->lpar);
|
|
|
|
|
if(bm->plar) MEM_freeN(bm->plar);
|
|
|
|
|
|
2008-03-07 03:24:23 +00:00
|
|
|
bm->vtar = NULL;
|
|
|
|
|
bm->edar = NULL;
|
|
|
|
|
bm->lpar = NULL;
|
|
|
|
|
bm->plar = NULL;
|
2008-06-01 17:15:03 +00:00
|
|
|
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
|
2008-02-29 20:26:35 +00:00
|
|
|
|
|
|
|
|
|
2008-06-01 17:15:03 +00:00
|
|
|
if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly)
|
2008-02-23 22:11:16 +00:00
|
|
|
BME_error();
|
|
|
|
|
|
|
|
|
|
meshok = BME_validate_mesh(bm, 1);
|
|
|
|
|
if(!meshok){
|
2008-02-25 04:53:37 +00:00
|
|
|
BME_error();
|
2008-02-23 22:11:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* BME VALIDATE MESH
|
|
|
|
|
*
|
|
|
|
|
* There are several levels of validation for meshes. At the
|
|
|
|
|
* Euler level, some basic validation is done to local topology.
|
|
|
|
|
* To catch more subtle problems however, BME_validate_mesh() is
|
|
|
|
|
* called by BME_model_end() whenever a tool is done executing.
|
|
|
|
|
* The purpose of this function is to insure that during the course
|
|
|
|
|
* of tool execution that nothing has been done to invalidate the
|
|
|
|
|
* structure, and if it has, provide a way of reporting that so that
|
|
|
|
|
* we can restore the proper structure from a backup. Since a full mesh
|
|
|
|
|
* validation would be too expensive, this is presented as a compromise.
|
|
|
|
|
*
|
|
|
|
|
* TODO
|
|
|
|
|
*
|
2008-06-02 20:52:40 +00:00
|
|
|
* -Make this only part of debug builds
|
2008-02-23 22:11:16 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define VHALT(halt) {BME_error(); if(halt) return 0;}
|
|
|
|
|
|
|
|
|
|
int BME_validate_mesh(struct BME_Mesh *bm, int halt)
|
|
|
|
|
{
|
|
|
|
|
BME_Vert *v;
|
|
|
|
|
BME_Edge *e;
|
|
|
|
|
BME_Poly *f;
|
|
|
|
|
BME_Loop *l;
|
|
|
|
|
BME_CycleNode *diskbase;
|
|
|
|
|
int i, ok;
|
|
|
|
|
|
|
|
|
|
/*Simple edge verification*/
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next){
|
|
|
|
|
if(e->v1 == e->v2) VHALT(halt);
|
|
|
|
|
/*validate e->d1.data and e->d2.data*/
|
|
|
|
|
if(e->d1.data != e || e->d2.data != e) VHALT(halt);
|
|
|
|
|
/*validate e->loop->e*/
|
|
|
|
|
if(e->loop){
|
|
|
|
|
if(e->loop->e != e) VHALT(halt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*calculate disk cycle lengths*/
|
|
|
|
|
for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0;
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next){
|
|
|
|
|
e->v1->tflag1++;
|
|
|
|
|
e->v2->tflag1++;
|
|
|
|
|
}
|
|
|
|
|
/*Validate vertices and disk cycle*/
|
|
|
|
|
for(v=bm->verts.first; v; v=v->next){
|
|
|
|
|
/*validate v->edge pointer*/
|
|
|
|
|
if(v->tflag1){
|
|
|
|
|
if(v->edge){
|
|
|
|
|
ok = BME_vert_in_edge(v->edge,v);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
/*validate length of disk cycle*/
|
|
|
|
|
diskbase = BME_disk_getpointer(v->edge, v);
|
|
|
|
|
ok = BME_cycle_validate(v->tflag1, diskbase);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
/*validate that each edge in disk cycle contains V*/
|
|
|
|
|
for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
|
|
|
|
|
ok = BME_vert_in_edge(e, v);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else VHALT(halt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*validate edges*/
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next){
|
|
|
|
|
/*seperate these into BME_disk_hasedge (takes pointer to edge)*/
|
|
|
|
|
/*search v1 disk cycle for edge*/
|
|
|
|
|
ok = BME_disk_hasedge(e->v1,e);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
/*search v2 disk cycle for edge*/
|
|
|
|
|
ok = BME_disk_hasedge(e->v2,e);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces
|
|
|
|
|
/*Validate the loop cycle integrity.*/
|
|
|
|
|
for(f=bm->polys.first; f; f=f->next){
|
|
|
|
|
ok = BME_cycle_length(f->loopbase);
|
|
|
|
|
if(ok > 1){
|
|
|
|
|
f->tflag1 = ok;
|
|
|
|
|
}
|
|
|
|
|
else VHALT(halt);
|
|
|
|
|
for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){
|
|
|
|
|
/*verify loop->v pointers*/
|
|
|
|
|
ok = BME_verts_in_edge(l->v, l->next->v, l->e);
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
/*verify radial node data pointer*/
|
|
|
|
|
if(l->radial.data != l) VHALT(halt);
|
|
|
|
|
/*validate l->e->loop poitner*/
|
|
|
|
|
if(l->e->loop == NULL) VHALT(halt);
|
|
|
|
|
/*validate l->f pointer*/
|
|
|
|
|
if(l->f != f) VHALT(halt);
|
|
|
|
|
/*see if l->e->loop is actually in radial cycle*/
|
|
|
|
|
|
|
|
|
|
l->e->tflag2++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*validate length of radial cycle*/
|
|
|
|
|
for(e=bm->edges.first; e; e=e->next){
|
|
|
|
|
if(e->loop){
|
|
|
|
|
ok = BME_cycle_validate(e->tflag2,&(e->loop->radial));
|
|
|
|
|
if(!ok) VHALT(halt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-29 20:26:35 +00:00
|
|
|
/*validate that EIDs are within range... if not indicates corrupted mem*/
|
|
|
|
|
|
2008-02-23 22:11:16 +00:00
|
|
|
/*if we get this far, pretty safe to return 1*/
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Currently just a convient place for a breakpoint.
|
|
|
|
|
Probably should take an error string
|
|
|
|
|
*/
|
|
|
|
|
void BME_error(void){
|
|
|
|
|
printf("BME modelling error!");
|
|
|
|
|
}
|