f58c2d6c0cbc05b56370d2b4d332e1c27da21fee
[blender.git] / source / blender / bmesh / intern / bmesh_operators.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BLI_memarena.h"
4 #include "BLI_mempool.h"
5
6 #include "BKE_utildefines.h"
7
8 #include "bmesh.h"
9 #include "bmesh_private.h"
10
11 #include <string.h>
12
13 /*forward declarations*/
14 static void alloc_flag_layer(BMesh *bm);
15 static void free_flag_layer(BMesh *bm);
16 static void clear_flag_layer(BMesh *bm);
17
18 typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op);
19
20 /*operator slot type information - size of one element of the type given.*/
21 const int BMOP_OPSLOT_TYPEINFO[BMOP_OPSLOT_TYPES] = {
22         sizeof(int),
23         sizeof(float),
24         sizeof(void*),
25         0, /* unused */
26         0, /* unused */
27         0, /* unused */
28         sizeof(float)*3,
29         sizeof(int),    /* int buffer */
30         sizeof(float),  /* float buffer */
31         sizeof(void*)   /* pointer buffer */
32 };
33
34 /*
35  * BMESH OPSTACK PUSH
36  *
37  * Pushes the opstack down one level 
38  * and allocates a new flag layer if
39  * appropriate.
40  *
41 */
42
43 void BMO_push(BMesh *bm, BMOperator *op)
44 {
45         bm->stackdepth++;
46
47         /*add flag layer, if appropriate*/
48         if (bm->stackdepth > 1)
49                 alloc_flag_layer(bm);
50         else
51                 clear_flag_layer(bm);
52 }
53
54 /*
55  * BMESH OPSTACK POP
56  *
57  * Pops the opstack one level  
58  * and frees a flag layer if appropriate
59  * TODO: investigate NOT freeing flag
60  * layers.
61  *
62 */
63 void BMO_pop(BMesh *bm)
64 {
65         bm->stackdepth--;
66         if(bm->stackdepth > 1)
67                 free_flag_layer(bm);
68 }
69
70 /*
71  * BMESH OPSTACK INIT OP
72  *
73  * Initializes an operator structure  
74  * to a certain type
75  *
76 */
77
78 void BMO_Init_Op(BMOperator *op, int opcode)
79 {
80         int i;
81
82         memset(op, 0, sizeof(BMOperator));
83         op->type = opcode;
84         
85         /*initialize the operator slot types*/
86         for(i = 0; i < opdefines[opcode]->totslot; i++) {
87                 op->slots[i].slottype = opdefines[opcode]->slottypes[i];
88                 op->slots[i].index = i;
89         }
90
91         /*callback*/
92         op->exec = opdefines[opcode]->exec;
93
94         /*memarena, used for operator's slot buffers*/
95         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
96         BLI_memarena_use_calloc (op->arena);
97 }
98
99 /*
100  *      BMESH OPSTACK EXEC OP
101  *
102  *  Executes a passed in operator. This handles
103  *  the allocation and freeing of temporary flag
104  *  layers and starting/stopping the modelling
105  *  loop. Can be called from other operators
106  *  exec callbacks as well.
107  * 
108 */
109
110 void BMO_Exec_Op(BMesh *bm, BMOperator *op)
111 {
112         
113         BMO_push(bm, op);
114
115         if(bm->stackdepth == 1)
116                 bmesh_begin_edit(bm);
117         op->exec(bm, op);
118         
119         if(bm->stackdepth == 1)
120                 bmesh_end_edit(bm,0);
121         
122         BMO_pop(bm);    
123 }
124
125 /*
126  *  BMESH OPSTACK FINISH OP
127  *
128  *  Does housekeeping chores related to finishing
129  *  up an operator.
130  *
131 */
132
133 void BMO_Finish_Op(BMesh *bm, BMOperator *op)
134 {
135         BLI_memarena_free(op->arena);
136 }
137
138 /*
139  * BMESH OPSTACK GET SLOT
140  *
141  * Returns a pointer to the slot of  
142  * type 'slotcode'
143  *
144 */
145
146 BMOpSlot *BMO_GetSlot(BMOperator *op, int slotcode)
147 {
148         return &(op->slots[slotcode]);
149 }
150
151 /*
152  * BMESH OPSTACK COPY SLOT
153  *
154  * Copies data from one slot to another 
155  *
156 */
157
158 void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, int src, int dst)
159 {
160         BMOpSlot *source_slot = &source_op->slots[src];
161         BMOpSlot *dest_slot = &dest_op->slots[dst];
162
163         if(source_slot == dest_slot)
164                 return;
165
166         if(source_slot->slottype != dest_slot->slottype)
167                 return;
168         
169         if(dest_slot->slottype > BMOP_OPSLOT_VEC){
170                 /*do buffer copy*/
171                 dest_slot->data.buf = NULL;
172                 dest_slot->len = source_slot->len;
173                 if(dest_slot->len){
174                         dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
175                         memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
176                 }
177         } else {
178                 dest_slot->data = source_slot->data;
179         }
180 }
181
182 /*
183  * BMESH OPSTACK SET XXX
184  *
185  * Sets the value of a slot depending on it's type
186  *
187 */
188
189
190 void BMO_Set_Float(BMOperator *op, int slotcode, float f)
191 {
192         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_FLT) )
193                 return;
194         op->slots[slotcode].data.f = f;
195 }
196
197 void BMO_Set_Int(BMOperator *op, int slotcode, int i)
198 {
199         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_INT) )
200                 return;
201         op->slots[slotcode].data.i = i;
202
203 }
204
205
206 void BMO_Set_PntBuf(BMOperator *op, int slotcode, void *p, int len)
207 {
208         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_PNT_BUF) )
209                 return;
210
211         op->slots[slotcode].data.p = p;
212         op->slots[slotcode].len = len;
213 }
214
215 void BMO_Set_FltBuf(BMOperator *op, int slotcode, float *p, int len)
216 {
217         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_FLT_BUF) )
218                 return;
219
220         op->slots[slotcode].data.p = p;
221         op->slots[slotcode].len = len;
222 }
223
224 void BMO_Set_Pnt(BMOperator *op, int slotcode, void *p)
225 {
226         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_PNT) )
227                 return;
228         op->slots[slotcode].data.p = p;
229 }
230 void BMO_Set_Vec(BMOperator *op, int slotcode, float *vec)
231 {
232         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_VEC) )
233                 return;
234
235         VECCOPY(op->slots[slotcode].data.vec, vec);
236 }
237
238 /*
239  * BMO_SETFLAG
240  *
241  * Sets a flag for a certain element
242  *
243 */
244 void BMO_SetFlag(BMesh *bm, void *element, int flag)
245 {
246         BMHeader *head = element;
247         head->flags[bm->stackdepth-1].mask |= flag;
248 }
249
250 /*
251  * BMO_CLEARFLAG
252  *
253  * Clears a specific flag from a given element
254  *
255 */
256
257 void BMO_ClearFlag(BMesh *bm, void *element, int flag)
258 {
259         BMHeader *head = element;
260         head->flags[bm->stackdepth-1].mask &= ~flag;
261 }
262
263 /*
264  * BMO_TESTFLAG
265  *
266  * Tests whether or not a flag is set for a specific element
267  *
268  *
269 */
270
271 int BMO_TestFlag(BMesh *bm, void *element, int flag)
272 {
273         BMHeader *head = element;
274         if(head->flags[bm->stackdepth-1].mask & flag)
275                 return 1;
276         return 0;
277 }
278
279 /*
280  * BMO_COUNTFLAG
281  *
282  * Counts the number of elements of a certain type that
283  * have a specific flag set.
284  *
285 */
286
287 int BMO_CountFlag(BMesh *bm, int flag, int type)
288 {
289         BMIter elements;
290         BMHeader *e;
291         int count = 0;
292
293         if(type & BM_VERT){
294                 for(e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)){
295                         if(BMO_TestFlag(bm, e, flag))
296                                 count++;
297                 }
298         }
299         if(type & BM_EDGE){
300                 for(e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)){
301                         if(BMO_TestFlag(bm, e, flag))
302                                 count++;
303                 }
304         }
305         if(type & BM_FACE){
306                 for(e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)){
307                         if(BMO_TestFlag(bm, e, flag))
308                                 count++;
309                 }
310         }
311
312         return count;   
313 }
314
315 static void *alloc_slot_buffer(BMOperator *op, int slotcode, int len){
316
317         /*check if its actually a buffer*/
318         if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) )
319                 return NULL;
320         
321         op->slots[slotcode].len = len;
322         if(len)
323                 op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * len);
324         return op->slots[slotcode].data.buf;
325 }
326
327 /*
328  *
329  * BMO_HEADERFLAG_TO_SLOT
330  *
331  * Copies elements of a certain type, which have a certain header flag set 
332  * into an output slot for an operator.
333  *
334 */
335
336 void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
337 {
338         BMIter elements;
339         BMHeader *e;
340         BMOpSlot *output = BMO_GetSlot(op, slotcode);
341         int totelement=0, i=0;
342         
343         totelement = BM_CountFlag(bm, type, BM_SELECT);
344
345         if(totelement){
346                 alloc_slot_buffer(op, slotcode, totelement);
347
348                 if (type & BM_VERT) {
349                         for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
350                                 if(e->flag & flag) {
351                                         ((BMHeader**)output->data.p)[i] = e;
352                                         i++;
353                                 }
354                         }
355                 }
356
357                 if (type & BM_EDGE) {
358                         for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
359                                 if(e->flag & flag){
360                                         ((BMHeader**)output->data.p)[i] = e;
361                                         i++;
362                                 }
363                         }
364                 }
365
366                 if (type & BM_FACE) {
367                         for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
368                                 if(e->flag & flag){
369                                         ((BMHeader**)output->data.p)[i] = e;
370                                         i++;
371                                 }
372                         }
373                 }
374         }
375 }
376
377 /*
378  *
379  * BMO_FLAG_TO_SLOT
380  *
381  * Copies elements of a certain type, which have a certain flag set 
382  * into an output slot for an operator.
383  *
384 */
385 void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
386 {
387         BMIter elements;
388         BMHeader *e;
389         BMOpSlot *output = BMO_GetSlot(op, slotcode);
390         int totelement = BMO_CountFlag(bm, flag, type), i=0;
391
392         if(totelement){
393                 alloc_slot_buffer(op, slotcode, totelement);
394
395                 if (type & BM_VERT) {
396                         for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
397                                 if(BMO_TestFlag(bm, e, flag)){
398                                         ((BMHeader**)output->data.p)[i] = e;
399                                         i++;
400                                 }
401                         }
402                 }
403
404                 if (type & BM_EDGE) {
405                         for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
406                                 if(BMO_TestFlag(bm, e, flag)){
407                                         ((BMHeader**)output->data.p)[i] = e;
408                                         i++;
409                                 }
410                         }
411                 }
412
413                 if (type & BM_FACE) {
414                         for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
415                                 if(BMO_TestFlag(bm, e, flag)){
416                                         ((BMHeader**)output->data.p)[i] = e;
417                                         i++;
418                                 }
419                         }
420                 }
421         }
422 }
423
424 /*
425  *
426  * BMO_FLAG_BUFFER
427  *
428  * Flags elements in a slots buffer
429  *
430 */
431
432 void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, int slotcode, int flag)
433 {
434         BMOpSlot *slot = BMO_GetSlot(op, slotcode);
435         BMHeader **data =  slot->data.p;
436         int i;
437         
438         for(i = 0; i < slot->len; i++)
439                 BMO_SetFlag(bm, data[i], flag);
440 }
441
442
443 /*
444  *
445  *      ALLOC/FREE FLAG LAYER
446  *
447  *  Used by operator stack to free/allocate 
448  *  private flag data. This is allocated
449  *  using a mempool so the allocation/frees
450  *  should be quite fast.
451  *
452  *  TODO:
453  *      Investigate not freeing flag layers until
454  *  all operators have been executed. This would
455  *  save a lot of realloc potentially.
456  *
457 */
458
459 static void alloc_flag_layer(BMesh *bm)
460 {
461         BMVert *v;
462         BMEdge *e;
463         BMFace *f;
464
465         BMIter verts;
466         BMIter edges;
467         BMIter faces;
468         BLI_mempool *oldpool = bm->flagpool;            /*old flag pool*/
469         void *oldflags;
470         
471         /*allocate new flag pool*/
472         bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*(bm->totflags+1), 512, 512 );
473         
474         /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/
475         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
476                 oldflags = v->head.flags;
477                 v->head.flags = BLI_mempool_calloc(bm->flagpool);
478                 memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*dont know if this memcpy usage is correct*/
479         }
480         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
481                 oldflags = e->head.flags;
482                 e->head.flags = BLI_mempool_calloc(bm->flagpool);
483                 memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
484         }
485         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
486                 oldflags = f->head.flags;
487                 f->head.flags = BLI_mempool_calloc(bm->flagpool);
488                 memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
489         }
490         bm->totflags++;
491         BLI_mempool_destroy(oldpool);
492 }
493
494 static void free_flag_layer(BMesh *bm)
495 {
496         BMVert *v;
497         BMEdge *e;
498         BMFace *f;
499
500         BMIter verts;
501         BMIter edges;
502         BMIter faces;
503         BLI_mempool *oldpool = bm->flagpool;
504         void *oldflags;
505         
506         /*de-increment the totflags first...*/
507         bm->totflags--;
508         /*allocate new flag pool*/
509         bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512);
510         
511         /*now go through and memcpy all the flags*/
512         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
513                 oldflags = v->head.flags;
514                 v->head.flags = BLI_mempool_alloc(bm->flagpool);
515                 memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);  /*correct?*/
516         }
517         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
518                 oldflags = e->head.flags;
519                 e->head.flags = BLI_mempool_alloc(bm->flagpool);
520                 memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
521         }
522         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
523                 oldflags = f->head.flags;
524                 f->head.flags = BLI_mempool_alloc(bm->flagpool);
525                 memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
526         }
527
528         BLI_mempool_destroy(oldpool);
529 }
530
531 static void clear_flag_layer(BMesh *bm)
532 {
533         BMVert *v;
534         BMEdge *e;
535         BMFace *f;
536         
537         BMIter verts;
538         BMIter edges;
539         BMIter faces;
540         
541         /*now go through and memcpy all the flags*/
542         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
543                 memset(v->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
544         }
545         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
546                 memset(e->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
547         }
548         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
549                 memset(f->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
550         }
551 }