d302a85ec7289566a8e8bd6a68fbdefece77c4b9
[blender.git] / source / blender / bmesh / intern / bmesh_construct.c
1 /**
2  * bmesh_construct.c    August 2008
3  *
4  *      BM construction functions.
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * about this.  
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2007 Blender Foundation.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): Geoffrey Bantle.
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  */
32
33 #include "MEM_guardedalloc.h"
34 #include "BKE_customdata.h" 
35
36 #include "bmesh.h"
37 #include "bmesh_private.h"
38
39 /*prototypes*/
40 static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh,
41                                     BMLoop *source_loop, BMLoop *target_loop);
42
43 /*
44  * BM_CONSTRUCT.C
45  *
46  * This file contains functions for making and destroying
47  * individual elements like verts, edges and faces.
48  *
49 */
50
51 /*
52  * BMESH MAKE VERT
53  *
54  * Creates a new vertex and returns a pointer
55  * to it. If a pointer to an example vertex is
56  * passed in, it's custom data and properties
57  * will be copied to the new vertex.
58  *
59 */
60
61 BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example)
62 {
63         BMVert *v = NULL;
64         v = bmesh_mv(bm, co);
65         if(example)
66                 CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data);
67         return v;
68 }
69
70 /*
71  * BMESH MAKE EDGE
72  *
73  * Creates a new edge betweeen two vertices and returns a
74  * pointer to it. If 'nodouble' equals 1, then a check is
75  * is done to make sure that an edge between those two vertices
76  * does not already exist. If it does, that edge is returned instead
77  * of creating a new one.
78  *
79  * If a new edge is created, and a pointer to an example edge is
80  * provided, it's custom data and properties will be copied to the
81  * new edge.
82  *
83 */
84
85 BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble)
86 {
87         BMEdge *e = NULL;
88         
89         if(nodouble) /*test if edge already exists.*/
90                 e = bmesh_disk_existedge(v1, v2);
91
92         if(!e){
93                 e = bmesh_me(bm, v1, v2);
94
95                 if(example)
96                         CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->data, &e->data);
97         }
98         
99         return e;
100         
101 }
102
103 /*
104  * BMESH MAKE QUADTRIANGLE
105  *
106  * Creates a new quad or triangle from
107  * a list of 3 or 4 vertices. If nodouble
108  * equals 1, then a check is done to see
109  * if a face with these vertices already
110  * exists and returns it instead. If a pointer
111  * to an example face is provided, it's custom
112  * data and properties will be copied to the new
113  * face.
114  *
115  * Note that the winding of the face is determined
116  * by the order of the vertices in the vertex array
117  *
118 */
119
120 /*remove the edge array bits from this. Its not really needed?*/
121 BMFace *BM_Make_Quadtriangle(BMesh *bm, BMVert **verts, BMEdge **edges, int len, BMFace *example, int nodouble)
122 {
123         BMEdge *edar[4];
124         BMFace *f = NULL;
125         int overlap = 0;
126
127         edar[0] = edar[1] = edar[2] = edar[3] = NULL;
128         
129         if(edges){
130                 edar[0] = edges[0];
131                 edar[1] = edges[1];
132                 edar[2] = edges[2];
133                 if(len == 4) edar[3] = edges[3];
134         }else{
135                 edar[0] = bmesh_disk_existedge(verts[0],verts[1]);
136                 edar[1] = bmesh_disk_existedge(verts[1],verts[2]);
137                 if(len == 4){
138                         edar[2] = bmesh_disk_existedge(verts[2],verts[3]);
139                         edar[3] = bmesh_disk_existedge(verts[3],verts[0]);
140
141                 }else{
142                         edar[2] = bmesh_disk_existedge(verts[2],verts[0]);
143                 }
144         }
145         
146         if(nodouble){
147                 /*check if face exists or overlaps*/
148                 if(len == 4){
149                         overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
150                 }else{
151                         overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
152                 }
153         }
154
155         /*make new face*/
156         if((!f) && (!overlap)){
157                 if(!edar[0]) edar[0] = bmesh_me(bm, verts[0], verts[1]);
158                 if(!edar[1]) edar[1] = bmesh_me(bm, verts[1], verts[2]);
159                 if(len == 4){
160                         if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[3]);
161                         if(!edar[3]) edar[3] = bmesh_me(bm, verts[3], verts[0]); 
162                 } else {
163                         if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[0]);
164                 }
165         
166                 if(len == 4) f = bmesh_mf(bm, verts[0], verts[1], edar, 4);
167                 else f = bmesh_mf(bm, verts[0], verts[1], edar, 3);
168         
169                 if(example)
170                         CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data);
171
172         }
173
174         return f;
175 }
176
177
178 /*copies face data from shared adjacent faces*/
179 void BM_Face_CopyShared(BMesh *bm, BMFace *f) {
180         BMIter iter;
181         BMLoop *l, *l2;
182
183         if (!f) return;
184
185         l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
186         for (; l; l=BMIter_Step(&iter)) {
187                 l2 = l->radial.next->data;
188                 
189                 if (l2 && l2 != l) {
190                         if (l2->v == l->v) {
191                                 bm_copy_loop_attributes(bm, bm, l2, l);
192                         } else {
193                                 l2 = (BMLoop*) l2->head.next;
194                                 bm_copy_loop_attributes(bm, bm, l2, l);
195                         }
196                 }
197         }
198 }
199
200 /*
201  * BMESH MAKE NGON
202  *
203  * Attempts to make a new Ngon from a list of edges.
204  * If nodouble equals one, a check for overlaps or existing
205  * 
206  * 
207  *
208 */
209 #define VERT_BUF_SIZE 100
210 BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
211 {
212         BMVert *vert_buf[VERT_BUF_SIZE];
213         BMVert **verts = vert_buf;
214         BMFace *f = NULL;
215         int overlap = 0, i;
216
217         if(nodouble){
218                 if(len > VERT_BUF_SIZE)
219                         verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array");
220                 for(i = 0; i < len; i++){
221                         if(!BMO_TestFlag(bm, edges[i]->v1, BM_EDGEVERT)){
222                                 BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT);
223                                 verts[i] = edges[i]->v1;
224                         } else if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) {
225                                 BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT);
226                                 verts[i] = edges[i]->v2;
227                         }
228                 }
229                 
230                 overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
231                 
232                 /*clear flags*/
233                 for(i = 0; i < len; i++){
234                         BMO_ClearFlag(bm, edges[i]->v1, BM_EDGEVERT);
235                         BMO_ClearFlag(bm, edges[i]->v2, BM_EDGEVERT);
236                 }
237                 
238                 if(len > VERT_BUF_SIZE)
239                         MEM_freeN(verts);
240         }
241
242         if((!f) && (!overlap)) {
243                 f = bmesh_mf(bm, v1, v2, edges, len);
244         }
245
246         return f;
247 }
248
249
250 /*bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */
251
252
253 /*
254  * REMOVE TAGGED XXX
255  *
256  * Called by operators to remove elements that they have marked for
257  * removal.
258  *
259 */
260
261 void BM_remove_tagged_faces(BMesh *bm, int flag)
262 {
263         BMHeader *current, *next;
264
265         current = bm->polys.first;
266         while(current){
267                 next = current->next;
268                 if(BMO_TestFlag(bm, current, flag)) bmesh_kf(bm, (BMFace*)current);
269                 current = next;
270         }
271 }
272 void BM_remove_tagged_edges(BMesh *bm, int flag)
273 {
274         BMHeader *current, *next;
275         
276         current = bm->edges.first;
277         
278         while(current){
279                 next = current->next;
280                 if(BMO_TestFlag(bm, current, flag)) bmesh_ke(bm, (BMEdge*)current);
281                 current = next;
282         }
283 }
284
285 void BM_remove_tagged_verts(BMesh *bm, int flag)
286 {
287         BMHeader *current, *next;
288
289         current = bm->verts.first;
290
291         while(current){
292                 next = current->next;
293                 if(BMO_TestFlag(bm, current, flag)) bmesh_kv(bm,(BMVert*)current);
294                 current = next;
295         }
296 }
297
298 static void bm_copy_vert_attributes(BMesh *source_mesh, BMesh *target_mesh, BMVert *source_vertex, BMVert *target_vertex)
299 {
300         CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data);        
301         target_vertex->bweight = source_vertex->bweight;
302 }
303
304 static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, BMEdge *source_edge, BMEdge *target_edge)
305 {
306         CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data);
307         target_edge->crease = source_edge->crease;
308         target_edge->bweight = source_edge->bweight;
309 }
310
311 static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop)
312 {
313         CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data);
314 }
315
316 static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, BMFace *source_face, BMFace *target_face)
317 {
318         CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data);    
319         target_face->mat_nr = source_face->mat_nr;
320 }
321
322 /*Todo: Special handling for hide flags?*/
323
324 void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, void *source, void *target)
325 {
326         BMHeader *sheader = source, *theader = target;
327         
328         if(sheader->type != theader->type)
329                 return;
330
331         /*First we copy select*/
332         if(BM_Is_Selected(source_mesh, source)) BM_Select(target_mesh, target, 1);
333         
334         /*Now we copy flags*/
335         theader->flag = sheader->flag;
336         
337         /*Copy specific attributes*/
338         if(theader->type == BM_VERT)
339                 bm_copy_vert_attributes(source_mesh, target_mesh, (BMVert*)source, (BMVert*)target);
340         else if(theader->type == BM_EDGE)
341                 bm_copy_edge_attributes(source_mesh, target_mesh, (BMEdge*)source, (BMEdge*)target);
342         else if(theader->type == BM_LOOP)
343                 bm_copy_loop_attributes(source_mesh, target_mesh, (BMLoop*)source, (BMLoop*)target);
344         else if(theader->type == BM_FACE)
345                 bm_copy_face_attributes(source_mesh, target_mesh, (BMFace*)source, (BMFace*)target);
346 }