Added a new slot type, that maps geometric elements to
[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 /*mappings map elements to data, which
21   follows the mapping struct in memory.*/
22 typedef struct element_mapping {
23         BMHeader *element;
24         int len;
25 } element_mapping;
26
27
28 /*operator slot type information - size of one element of the type given.*/
29 const int BMOP_OPSLOT_TYPEINFO[] = {
30         sizeof(int),
31         sizeof(float),
32         sizeof(void*),
33         0, /* unused */
34         0, /* unused */
35         0, /* unused */
36         sizeof(void*),  /* pointer buffer */
37         sizeof(element_mapping)
38 };
39
40 /*
41  * BMESH OPSTACK PUSH
42  *
43  * Pushes the opstack down one level 
44  * and allocates a new flag layer if
45  * appropriate.
46  *
47 */
48
49 void BMO_push(BMesh *bm, BMOperator *op)
50 {
51         bm->stackdepth++;
52
53         /*add flag layer, if appropriate*/
54         if (bm->stackdepth > 1)
55                 alloc_flag_layer(bm);
56         else
57                 clear_flag_layer(bm);
58 }
59
60 /*
61  * BMESH OPSTACK POP
62  *
63  * Pops the opstack one level  
64  * and frees a flag layer if appropriate
65  * TODO: investigate NOT freeing flag
66  * layers.
67  *
68 */
69 void BMO_pop(BMesh *bm)
70 {
71         bm->stackdepth--;
72         if(bm->stackdepth > 1)
73                 free_flag_layer(bm);
74 }
75
76 /*
77  * BMESH OPSTACK INIT OP
78  *
79  * Initializes an operator structure  
80  * to a certain type
81  *
82 */
83
84 void BMO_Init_Op(BMOperator *op, int opcode)
85 {
86         int i;
87
88         memset(op, 0, sizeof(BMOperator));
89         op->type = opcode;
90         
91         /*initialize the operator slot types*/
92         for(i = 0; i < opdefines[opcode]->totslot; i++) {
93                 op->slots[i].slottype = opdefines[opcode]->slottypes[i];
94                 op->slots[i].index = i;
95         }
96
97         /*callback*/
98         op->exec = opdefines[opcode]->exec;
99
100         /*memarena, used for operator's slot buffers*/
101         op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
102         BLI_memarena_use_calloc (op->arena);
103 }
104
105 /*
106  *      BMESH OPSTACK EXEC OP
107  *
108  *  Executes a passed in operator. This handles
109  *  the allocation and freeing of temporary flag
110  *  layers and starting/stopping the modelling
111  *  loop. Can be called from other operators
112  *  exec callbacks as well.
113  * 
114 */
115
116 void BMO_Exec_Op(BMesh *bm, BMOperator *op)
117 {
118         
119         BMO_push(bm, op);
120
121         if(bm->stackdepth == 1)
122                 bmesh_begin_edit(bm);
123         op->exec(bm, op);
124         
125         if(bm->stackdepth == 1)
126                 bmesh_end_edit(bm,0);
127         
128         BMO_pop(bm);    
129 }
130
131 /*
132  *  BMESH OPSTACK FINISH OP
133  *
134  *  Does housekeeping chores related to finishing
135  *  up an operator.
136  *
137 */
138
139 void BMO_Finish_Op(BMesh *bm, BMOperator *op)
140 {
141         BMOpSlot *slot;
142         int i;
143
144         for (i=0; i<opdefines[op->type]->totslot; i++) {
145                 slot = &op->slots[i];
146                 if (slot->slottype == BMOP_OPSLOT_MAPPING) {
147                         if (slot->data.ghash) 
148                                 BLI_ghash_free(slot->data.ghash, NULL, NULL);
149                 }
150         }
151
152         BLI_memarena_free(op->arena);
153 }
154
155 /*
156  * BMESH OPSTACK GET SLOT
157  *
158  * Returns a pointer to the slot of  
159  * type 'slotcode'
160  *
161 */
162
163 BMOpSlot *BMO_GetSlot(BMOperator *op, int slotcode)
164 {
165         return &(op->slots[slotcode]);
166 }
167
168 /*
169  * BMESH OPSTACK COPY SLOT
170  *
171  * Copies data from one slot to another 
172  *
173 */
174
175 void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, int src, int dst)
176 {
177         BMOpSlot *source_slot = &source_op->slots[src];
178         BMOpSlot *dest_slot = &dest_op->slots[dst];
179
180         if(source_slot == dest_slot)
181                 return;
182
183         if(source_slot->slottype != dest_slot->slottype)
184                 return;
185         
186         if(dest_slot->slottype > BMOP_OPSLOT_VEC){
187                 /*do buffer copy*/
188                 dest_slot->data.buf = NULL;
189                 dest_slot->len = source_slot->len;
190                 if(dest_slot->len){
191                         dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
192                         memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
193                 }
194         } else {
195                 dest_slot->data = source_slot->data;
196         }
197 }
198
199 /*
200  * BMESH OPSTACK SET XXX
201  *
202  * Sets the value of a slot depending on it's type
203  *
204 */
205
206
207 void BMO_Set_Float(BMOperator *op, int slotcode, float f)
208 {
209         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_FLT) )
210                 return;
211         op->slots[slotcode].data.f = f;
212 }
213
214 void BMO_Set_Int(BMOperator *op, int slotcode, int i)
215 {
216         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_INT) )
217                 return;
218         op->slots[slotcode].data.i = i;
219
220 }
221
222
223 void BMO_Set_Pnt(BMOperator *op, int slotcode, void *p)
224 {
225         if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_PNT) )
226                 return;
227         op->slots[slotcode].data.p = p;
228 }
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 int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, int slotcode)
316 {
317         BMOpSlot *slot = &op->slots[slotcode];
318         
319         /*check if its actually a buffer*/
320         if( !(slot->slottype > BMOP_OPSLOT_VEC) )
321                 return 0;
322
323         return slot->len;
324 }
325
326 #if 0
327 void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd) {
328         BMOpSlot *slot = &op->slots[slotcode];
329         void *tmp;
330         
331         /*check if its actually a buffer*/
332         if( !(slot->slottype > BMOP_OPSLOT_VEC) )
333                 return NULL;
334
335         if (slot->flag & BMOS_DYNAMIC_ARRAY) {
336                 if (slot->len >= slot->size) {
337                         slot->size = (slot->size+1+totadd)*2;
338
339                         tmp = slot->data.buf;
340                         slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->size, "opslot dynamic array");
341                         memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->size);
342                         MEM_freeN(tmp);
343                 }
344
345                 slot->len += totadd;
346         } else {
347                 slot->flag |= BMOS_DYNAMIC_ARRAY;
348                 slot->len += totadd;
349                 slot->size = slot->len+2;
350                 tmp = slot->data.buf;
351                 slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->len, "opslot dynamic array");
352                 memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->len);
353         }
354
355         return slot->data.buf;
356 }
357 #endif
358
359 void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, int slotcode, 
360                         void *element, void *data, int len) {
361         element_mapping *mapping;
362         BMOpSlot *slot = &op->slots[slotcode];
363
364         /*sanity check*/
365         if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
366         
367         mapping = BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
368
369         mapping->element = element;
370         mapping->len = len;
371         memcpy(mapping+1, data, len);
372
373         if (!slot->data.ghash) {
374                 slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, 
375                                                      BLI_ghashutil_ptrcmp);
376         }
377         
378         BLI_ghash_insert(slot->data.ghash, element, mapping);
379 }
380
381 void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, 
382                          int slotcode, int flag)
383 {
384         GHashIterator it;
385         BMOpSlot *slot = &op->slots[slotcode];
386         BMHeader *ele;
387
388         /*sanity check*/
389         if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
390         if (!slot->data.ghash) return;
391
392         BLI_ghashIterator_init(&it, slot->data.ghash);
393         for (;ele=BLI_ghashIterator_getKey(&it);BLI_ghashIterator_step(&it)) {
394                 BMO_SetFlag(bm, ele, flag);
395         }
396 }
397
398 void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, int slotcode, 
399                         void *element, float val)
400 {
401         BMO_Insert_Mapping(bm, op, slotcode, element, &val, sizeof(float));
402 }
403
404 void *BMO_Get_MapData(BMesh *bm, BMOperator *op, int slotcode,
405                       void *element)
406 {
407         element_mapping *mapping;
408         BMOpSlot *slot = &op->slots[slotcode];
409
410         /*sanity check*/
411         if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL;
412         if (!slot->data.ghash) return NULL;
413
414         mapping = BLI_ghash_lookup(slot->data.ghash, element);
415         
416         return mapping + 1;
417 }
418
419 float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, int slotcode,
420                        void *element)
421 {
422         float *val = BMO_Get_MapData(bm, op, slotcode, element);
423         if (val) return *val;
424
425         return 0.0f;
426 }
427
428 static void *alloc_slot_buffer(BMOperator *op, int slotcode, int len){
429
430         /*check if its actually a buffer*/
431         if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) )
432                 return NULL;
433         
434         op->slots[slotcode].len = len;
435         if(len)
436                 op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * len);
437         return op->slots[slotcode].data.buf;
438 }
439
440 /*
441  *
442  * BMO_HEADERFLAG_TO_SLOT
443  *
444  * Copies elements of a certain type, which have a certain header flag set 
445  * into an output slot for an operator.
446  *
447 */
448
449 void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
450 {
451         BMIter elements;
452         BMHeader *e;
453         BMOpSlot *output = BMO_GetSlot(op, slotcode);
454         int totelement=0, i=0;
455         
456         totelement = BM_CountFlag(bm, type, BM_SELECT);
457
458         if(totelement){
459                 alloc_slot_buffer(op, slotcode, totelement);
460
461                 if (type & BM_VERT) {
462                         for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
463                                 if(e->flag & flag) {
464                                         ((BMHeader**)output->data.p)[i] = e;
465                                         i++;
466                                 }
467                         }
468                 }
469
470                 if (type & BM_EDGE) {
471                         for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
472                                 if(e->flag & flag){
473                                         ((BMHeader**)output->data.p)[i] = e;
474                                         i++;
475                                 }
476                         }
477                 }
478
479                 if (type & BM_FACE) {
480                         for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
481                                 if(e->flag & flag){
482                                         ((BMHeader**)output->data.p)[i] = e;
483                                         i++;
484                                 }
485                         }
486                 }
487         }
488 }
489
490 /*
491  *
492  * BMO_FLAG_TO_SLOT
493  *
494  * Copies elements of a certain type, which have a certain flag set 
495  * into an output slot for an operator.
496  *
497 */
498 void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
499 {
500         BMIter elements;
501         BMHeader *e;
502         BMOpSlot *output = BMO_GetSlot(op, slotcode);
503         int totelement = BMO_CountFlag(bm, flag, type), i=0;
504
505         if(totelement){
506                 alloc_slot_buffer(op, slotcode, totelement);
507
508                 if (type & BM_VERT) {
509                         for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
510                                 if(BMO_TestFlag(bm, e, flag)){
511                                         ((BMHeader**)output->data.p)[i] = e;
512                                         i++;
513                                 }
514                         }
515                 }
516
517                 if (type & BM_EDGE) {
518                         for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
519                                 if(BMO_TestFlag(bm, e, flag)){
520                                         ((BMHeader**)output->data.p)[i] = e;
521                                         i++;
522                                 }
523                         }
524                 }
525
526                 if (type & BM_FACE) {
527                         for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
528                                 if(BMO_TestFlag(bm, e, flag)){
529                                         ((BMHeader**)output->data.p)[i] = e;
530                                         i++;
531                                 }
532                         }
533                 }
534         }
535 }
536
537 /*
538  *
539  * BMO_FLAG_BUFFER
540  *
541  * Flags elements in a slots buffer
542  *
543 */
544
545 void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, int slotcode, int flag)
546 {
547         BMOpSlot *slot = BMO_GetSlot(op, slotcode);
548         BMHeader **data =  slot->data.p;
549         int i;
550         
551         for(i = 0; i < slot->len; i++)
552                 BMO_SetFlag(bm, data[i], flag);
553 }
554
555
556 /*
557  *
558  *      ALLOC/FREE FLAG LAYER
559  *
560  *  Used by operator stack to free/allocate 
561  *  private flag data. This is allocated
562  *  using a mempool so the allocation/frees
563  *  should be quite fast.
564  *
565  *  TODO:
566  *      Investigate not freeing flag layers until
567  *  all operators have been executed. This would
568  *  save a lot of realloc potentially.
569  *
570 */
571
572 static void alloc_flag_layer(BMesh *bm)
573 {
574         BMVert *v;
575         BMEdge *e;
576         BMFace *f;
577
578         BMIter verts;
579         BMIter edges;
580         BMIter faces;
581         BLI_mempool *oldpool = bm->flagpool;            /*old flag pool*/
582         void *oldflags;
583         
584         /*allocate new flag pool*/
585         bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*(bm->totflags+1), 512, 512 );
586         
587         /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/
588         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
589                 oldflags = v->head.flags;
590                 v->head.flags = BLI_mempool_calloc(bm->flagpool);
591                 memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*dont know if this memcpy usage is correct*/
592         }
593         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
594                 oldflags = e->head.flags;
595                 e->head.flags = BLI_mempool_calloc(bm->flagpool);
596                 memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
597         }
598         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
599                 oldflags = f->head.flags;
600                 f->head.flags = BLI_mempool_calloc(bm->flagpool);
601                 memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
602         }
603         bm->totflags++;
604         BLI_mempool_destroy(oldpool);
605 }
606
607 static void free_flag_layer(BMesh *bm)
608 {
609         BMVert *v;
610         BMEdge *e;
611         BMFace *f;
612
613         BMIter verts;
614         BMIter edges;
615         BMIter faces;
616         BLI_mempool *oldpool = bm->flagpool;
617         void *oldflags;
618         
619         /*de-increment the totflags first...*/
620         bm->totflags--;
621         /*allocate new flag pool*/
622         bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512);
623         
624         /*now go through and memcpy all the flags*/
625         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
626                 oldflags = v->head.flags;
627                 v->head.flags = BLI_mempool_alloc(bm->flagpool);
628                 memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);  /*correct?*/
629         }
630         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
631                 oldflags = e->head.flags;
632                 e->head.flags = BLI_mempool_alloc(bm->flagpool);
633                 memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
634         }
635         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
636                 oldflags = f->head.flags;
637                 f->head.flags = BLI_mempool_alloc(bm->flagpool);
638                 memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
639         }
640
641         BLI_mempool_destroy(oldpool);
642 }
643
644 static void clear_flag_layer(BMesh *bm)
645 {
646         BMVert *v;
647         BMEdge *e;
648         BMFace *f;
649         
650         BMIter verts;
651         BMIter edges;
652         BMIter faces;
653         
654         /*now go through and memcpy all the flags*/
655         for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
656                 memset(v->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
657         }
658         for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
659                 memset(e->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
660         }
661         for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
662                 memset(f->head.flags, 0, sizeof(BMFlagLayer)*bm->totflags);
663         }
664 }