/** * bmesh_construct.c August 2008 * * BM construction functions. * * ***** BEGIN GPL LICENSE BLOCK ***** * * 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 * of the License, or (at your option) any later version. * 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, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2007 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): Geoffrey Bantle. * * ***** END GPL LICENSE BLOCK ***** */ #include "MEM_guardedalloc.h" #include "BKE_customdata.h" #include "BKE_utildefines.h" #include "BLI_array.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "bmesh.h" #include "bmesh_private.h" #include "math.h" #include "stdio.h" #include "string.h" #define SELECT 1 #define BM_EDGEVERT (1<<14) /*prototypes*/ static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop); #if 0 /* * BM_CONSTRUCT.C * * This file contains functions for making and destroying * individual elements like verts, edges and faces. * */ /* * BMESH MAKE VERT * * Creates a new vertex and returns a pointer * to it. If a pointer to an example vertex is * passed in, it's custom data and properties * will be copied to the new vertex. * */ BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example) { BMVert *v = NULL; v = bmesh_mv(bm, co); if(example) CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data); return v; } /* * BMESH MAKE EDGE * * Creates a new edge betweeen two vertices and returns a * pointer to it. If 'nodouble' equals 1, then a check is * is done to make sure that an edge between those two vertices * does not already exist. If it does, that edge is returned instead * of creating a new one. * * If a new edge is created, and a pointer to an example edge is * provided, it's custom data and properties will be copied to the * new edge. * */ BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble) { BMEdge *e = NULL; if(nodouble) /*test if edge already exists.*/ e = BM_Edge_Exist(v1, v2); if(!e){ e = bmesh_me(bm, v1, v2); if(example) CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data); } return e; } #endif /* * BMESH MAKE QUADTRIANGLE * * Creates a new quad or triangle from * a list of 3 or 4 vertices. If nodouble * equals 1, then a check is done to see * if a face with these vertices already * exists and returns it instead. If a pointer * to an example face is provided, it's custom * data and properties will be copied to the new * face. * * Note that the winding of the face is determined * by the order of the vertices in the vertex array * */ BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, BMFace *example, int nodouble) { BMEdge *edar[4]; BMVert *vtar[4]; edar[0] = BM_Edge_Exist(v1, v2); edar[1] = BM_Edge_Exist(v2, v3); edar[2] = BM_Edge_Exist(v3, v4? v4 : v1); if (v4) edar[3] = BM_Edge_Exist(v4, v1); else edar[3] = NULL; if (!edar[0]) edar[0] = BM_Make_Edge(bm, v1, v2, NULL, 0); if (!edar[1]) edar[1] = BM_Make_Edge(bm, v2, v3, NULL, 0); if (!edar[2]) edar[2] = BM_Make_Edge(bm, v3, v4?v4:v1, NULL, 0); if (!edar[0] && v4) edar[0] = BM_Make_Edge(bm, v4, v1, NULL, 0); vtar[0] = v1; vtar[1] = v2; vtar[2] = v3; vtar[3] = v4; return BM_Make_Quadtriangle(bm, vtar, edar, v4?4:3, example, nodouble); } /*remove the edge array bits from this. Its not really needed?*/ BMFace *BM_Make_Quadtriangle(BMesh *bm, BMVert **verts, BMEdge **edges, int len, BMFace *example, int nodouble) { BMEdge *edar[4]; BMFace *f = NULL; int overlap = 0; edar[0] = edar[1] = edar[2] = edar[3] = NULL; if(edges){ edar[0] = edges[0]; edar[1] = edges[1]; edar[2] = edges[2]; if(len == 4) edar[3] = edges[3]; }else{ edar[0] = BM_Edge_Exist(verts[0],verts[1]); edar[1] = BM_Edge_Exist(verts[1],verts[2]); if(len == 4){ edar[2] = BM_Edge_Exist(verts[2],verts[3]); edar[3] = BM_Edge_Exist(verts[3],verts[0]); }else{ edar[2] = BM_Edge_Exist(verts[2],verts[0]); } } if(nodouble){ /*check if face exists or overlaps*/ if(len == 4){ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f); }else{ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f); } } /*make new face*/ if((!f) && (!overlap)){ if(!edar[0]) edar[0] = BM_Make_Edge(bm, verts[0], verts[1], NULL, 0); if(!edar[1]) edar[1] = BM_Make_Edge(bm, verts[1], verts[2], NULL, 0); if(len == 4){ if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[3], NULL, 0); if(!edar[3]) edar[3] = BM_Make_Edge(bm, verts[3], verts[0], NULL, 0); } else { if(!edar[2]) edar[2] = BM_Make_Edge(bm, verts[2], verts[0], NULL, 0); } f = BM_Make_Face(bm, verts, edar, len); if(example) CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data); } return f; } /*copies face data from shared adjacent faces*/ void BM_Face_CopyShared(BMesh *bm, BMFace *f) { BMIter iter; BMLoop *l, *l2; if (!f) return; l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); for (; l; l=BMIter_Step(&iter)) { l2 = l->radial_next; if (l2 && l2 != l) { if (l2->v == l->v) { bm_copy_loop_attributes(bm, bm, l2, l); } else { l2 = (BMLoop*) l2->next; bm_copy_loop_attributes(bm, bm, l2, l); } } } } /* * BMESH MAKE NGON * * Attempts to make a new Ngon from a list of edges. * If nodouble equals one, a check for overlaps or existing * * The edges are not required to be ordered, simply to to form * a single closed loop as a whole */ #define VERT_BUF_SIZE 100 BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble) { BMEdge **edges2 = NULL; BLI_array_staticdeclare(edges2, VERT_BUF_SIZE); BMVert **verts = NULL, *v; BLI_array_staticdeclare(verts, VERT_BUF_SIZE); BMFace *f = NULL; BMEdge *e; int overlap = 0, i, j, v1found, reverse; /*this code is hideous, yeek. I'll have to think about ways of cleaning it up. basically, it now combines the old BM_Make_Ngon *and* the old bmesh_mf functions, so its kindof smashed together - joeedh*/ if (!len || !v1 || !v2 || !edges || !bm) return NULL; /*put edges in correct order*/ for (i=0; iv1); v = edges[0]->v2; e = edges[0]; do { BMEdge *e2 = e; BLI_array_append(verts, v); BLI_array_append(edges2, e); do { e2 = bmesh_disk_nextedge(e2, v); if (e2 != e && bmesh_api_getflag(e2, _FLAG_MF)) { v = BM_OtherEdgeVert(e2, v); break; } } while (e2 != e); if (e2 == e) goto err; /*the edges do not form a closed loop*/ e = e2; } while (e != edges[0]); if (BLI_array_count(edges2) != len) goto err; /*we didn't use all edges in forming the boundary loop*/ /*ok, edges are in correct order, now ensure they are going in the correct direction*/ v1found = reverse = 0; for (i=0; ivdata, &target_mesh->vdata, source_vertex->head.data, &target_vertex->head.data); } static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, BMEdge *source_edge, BMEdge *target_edge) { CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->head.data, &target_edge->head.data); } static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop) { CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->head.data, &target_loop->head.data); } static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, BMFace *source_face, BMFace *target_face) { CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->head.data, &target_face->head.data); target_face->mat_nr = source_face->mat_nr; } /*Todo: Special handling for hide flags?*/ void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, void *source, void *target) { BMHeader *sheader = source, *theader = target; if(sheader->type != theader->type) return; /*First we copy select*/ if(BM_Selected(source_mesh, source)) BM_Select(target_mesh, target, 1); /*Now we copy flags*/ theader->flag = sheader->flag; /*Copy specific attributes*/ if(theader->type == BM_VERT) bm_copy_vert_attributes(source_mesh, target_mesh, (BMVert*)source, (BMVert*)target); else if(theader->type == BM_EDGE) bm_copy_edge_attributes(source_mesh, target_mesh, (BMEdge*)source, (BMEdge*)target); else if(theader->type == BM_LOOP) bm_copy_loop_attributes(source_mesh, target_mesh, (BMLoop*)source, (BMLoop*)target); else if(theader->type == BM_FACE) bm_copy_face_attributes(source_mesh, target_mesh, (BMFace*)source, (BMFace*)target); } BMesh *BM_Copy_Mesh(BMesh *bmold) { BMesh *bm; BMVert *v, *v2, **vtable = NULL; BLI_array_declare(vtable); BMEdge *e, *e2, **edges = NULL, **etable = NULL; BLI_array_declare(edges); BLI_array_declare(etable); BMLoop *l, *l2, **loops = NULL; BLI_array_declare(loops); BMFace *f, *f2, **ftable = NULL; BLI_array_declare(ftable); BMEditSelection *ese; BMIter iter, liter; int allocsize[4] = {512,512,2048,512}, numTex, numCol; int i, j; /*allocate a bmesh*/ bm = BM_Make_Mesh(allocsize); CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); /*needed later*/ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); v = BMIter_New(&iter, bmold, BM_VERTS_OF_MESH, NULL); for (i=0; v; v=BMIter_Step(&iter), i++) { v2 = BM_Make_Vert(bm, v->co, NULL); BM_Copy_Attributes(bmold, bm, v, v2); BLI_array_growone(vtable); VECCOPY(v2->no, v->no); vtable[BLI_array_count(vtable)-1] = v2; BMINDEX_SET(v, i); BMINDEX_SET(v2, i); } e = BMIter_New(&iter, bmold, BM_EDGES_OF_MESH, NULL); for (i=0; e; e=BMIter_Step(&iter), i++) { e2 = BM_Make_Edge(bm, vtable[BMINDEX_GET(e->v1)], vtable[BMINDEX_GET(e->v2)], e, 0); BM_Copy_Attributes(bmold, bm, e, e2); BLI_array_growone(etable); etable[BLI_array_count(etable)-1] = e2; BMINDEX_SET(e, i); BMINDEX_SET(e2, i); } f = BMIter_New(&iter, bmold, BM_FACES_OF_MESH, NULL); for (i=0; f; f=BMIter_Step(&iter), i++) { BLI_array_empty(loops); BLI_array_empty(edges); l = BMIter_New(&liter, bmold, BM_LOOPS_OF_FACE, f); for (j=0; jlen; j++, l = BMIter_Step(&liter)) { BLI_array_growone(loops); BLI_array_growone(edges); loops[j] = l; edges[j] = etable[BMINDEX_GET(l->e)]; } v = vtable[BMINDEX_GET(loops[0]->v)]; v2 = vtable[BMINDEX_GET(loops[1]->v)]; if (!bmesh_verts_in_edge(v, v2, edges[0])) { v = vtable[BMINDEX_GET(loops[BLI_array_count(loops)-1]->v)]; v2 = vtable[BMINDEX_GET(loops[0]->v)]; } f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0); BMINDEX_SET(f, i); BLI_array_growone(ftable); ftable[i] = f2; BM_Copy_Attributes(bmold, bm, f, f2); VECCOPY(f2->no, f->no); l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f2); for (j=0; jlen; j++, l = BMIter_Step(&liter)) { BM_Copy_Attributes(bmold, bm, loops[j], l); } if (f == bmold->act_face) bm->act_face = f2; } /*copy over edit selection history*/ for (ese=bmold->selected.first; ese; ese=ese->next) { void *ele; if (ese->type == BM_VERT) ele = vtable[BMINDEX_GET(ese->data)]; else if (ese->type == BM_EDGE) ele = etable[BMINDEX_GET(ese->data)]; else if (ese->type == BM_FACE) { ele = ftable[BMINDEX_GET(ese->data)]; } BM_store_selection(bm, ele); } BLI_array_free(etable); BLI_array_free(vtable); BLI_array_free(ftable); BLI_array_free(loops); BLI_array_free(edges); return bm; } /* BM FLAGS TO ME FLAGS Returns the flags stored in element, which much be either a BMVert, BMEdge, or BMFace, converted to mesh flags. */ int BMFlags_To_MEFlags(void *element) { BMHeader *h = element; int f = 0; if (h->flag & BM_PINNED) f |= ME_PIN; if (h->flag & BM_HIDDEN) f |= ME_HIDE; if (h->type == BM_FACE) { if (h->flag & BM_SELECT) f |= ME_FACE_SEL; if (h->flag & BM_SMOOTH) f |= ME_SMOOTH; } else if (h->type == BM_EDGE) { if (h->flag & BM_SELECT) f |= BM_SELECT; if (h->flag & BM_SEAM) f |= ME_SEAM; if (h->flag & BM_SHARP) f |= ME_SHARP; if (BM_Wire_Edge(NULL, element)) f |= ME_LOOSEEDGE; f |= ME_EDGEDRAW; } else if (h->type == BM_VERT) { if (h->flag & BM_SELECT) f |= BM_SELECT; } return f; } /* BM FLAGS TO ME FLAGS Returns the flags stored in element, which much be either a MVert, MEdge, or MPoly, converted to mesh flags. type must be either BM_VERT, BM_EDGE, or BM_FACE. */ int MEFlags_To_BMFlags(int flag, int type) { int f = 0; if (flag & ME_PIN) f |= BM_PINNED; if (type == BM_FACE) { if (flag & ME_FACE_SEL) f |= BM_SELECT; if (flag & ME_SMOOTH) f |= BM_SMOOTH; if (flag & ME_HIDE) f |= BM_HIDDEN; } else if (type == BM_EDGE) { if (flag & SELECT) f |= BM_SELECT; if (flag & ME_SEAM) f |= BM_SEAM; if (flag & ME_SHARP) f |= BM_SHARP; if (flag & ME_HIDE) f |= BM_HIDDEN; } else if (type == BM_VERT) { if (flag & SELECT) f |= BM_SELECT; if (flag & ME_HIDE) f |= BM_HIDDEN; } return f; }