PageRenderTime 78ms CodeModel.GetById 12ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 1ms

/blender-2.63a/source/blender/bmesh/intern/bmesh_operators.c

#
C | 1588 lines | 1092 code | 290 blank | 206 comment | 231 complexity | 58180ba8edeb357d18dc81668b1bdcb3 MD5 | raw file
   1/*
   2 * ***** BEGIN GPL LICENSE BLOCK *****
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version 2
   7 * of the License, or (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software Foundation,
  16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17 *
  18 * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
  19 *
  20 * ***** END GPL LICENSE BLOCK *****
  21 */
  22
  23/** \file blender/bmesh/intern/bmesh_operators.c
  24 *  \ingroup bmesh
  25 *
  26 * BMesh operator access.
  27 */
  28
  29#include "MEM_guardedalloc.h"
  30
  31#include "BLI_utildefines.h"
  32#include "BLI_string.h"
  33#include "BLI_math.h"
  34#include "BLI_memarena.h"
  35#include "BLI_mempool.h"
  36#include "BLI_listbase.h"
  37#include "BLI_array.h"
  38
  39#include "bmesh.h"
  40#include "intern/bmesh_private.h"
  41
  42/* forward declarations */
  43static void bmo_flag_layer_alloc(BMesh *bm);
  44static void bmo_flag_layer_free(BMesh *bm);
  45static void bmo_flag_layer_clear(BMesh *bm);
  46static int bmo_name_to_slotcode(BMOpDefine *def, const char *name);
  47static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name);
  48static int bmo_opname_to_opcode(const char *opname);
  49
  50static const char *bmo_error_messages[] = {
  51	NULL,
  52	"Self intersection error",
  53	"Could not dissolve vert",
  54	"Could not connect vertices",
  55	"Could not traverse mesh",
  56	"Could not dissolve faces",
  57	"Could not dissolve vertices",
  58	"Tessellation error",
  59	"Can not deal with non-manifold geometry",
  60	"Invalid selection",
  61	"Internal mesh error",
  62};
  63
  64
  65/* operator slot type information - size of one element of the type given. */
  66const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
  67	0,                      /*  0: BMO_OP_SLOT_SENTINEL */
  68	sizeof(int),            /*  1: BMO_OP_SLOT_BOOL */ 
  69	sizeof(int),            /*  2: BMO_OP_SLOT_INT */ 
  70	sizeof(float),          /*  3: BMO_OP_SLOT_FLT */ 
  71	sizeof(void *),         /*  4: BMO_OP_SLOT_PNT */ 
  72	sizeof(void *),         /*  5: BMO_OP_SLOT_PNT */
  73	0,                      /*  6: unused */
  74	0,                      /*  7: unused */
  75	sizeof(float) * 3,      /*  8: BMO_OP_SLOT_VEC */
  76	sizeof(void *),	        /*  9: BMO_OP_SLOT_ELEMENT_BUF */
  77	sizeof(BMOElemMapping)  /* 10: BMO_OP_SLOT_MAPPING */
  78};
  79
  80/* Dummy slot so there is something to return when slot name lookup fails */
  81static BMOpSlot BMOpEmptySlot = {0};
  82
  83void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
  84{
  85	op->flag |= op_flag;
  86}
  87
  88void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
  89{
  90	op->flag &= ~op_flag;
  91}
  92
  93/**
  94 * \brief BMESH OPSTACK PUSH
  95 *
  96 * Pushes the opstack down one level and allocates a new flag layer if appropriate.
  97 */
  98void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
  99{
 100	bm->stackdepth++;
 101
 102	/* add flag layer, if appropriate */
 103	if (bm->stackdepth > 1)
 104		bmo_flag_layer_alloc(bm);
 105	else
 106		bmo_flag_layer_clear(bm);
 107}
 108
 109/**
 110 * \brief BMESH OPSTACK POP
 111 *
 112 * Pops the opstack one level and frees a flag layer if appropriate
 113 *
 114 * BMESH_TODO: investigate NOT freeing flag layers.
 115 */
 116void BMO_pop(BMesh *bm)
 117{
 118	if (bm->stackdepth > 1)
 119		bmo_flag_layer_free(bm);
 120
 121	bm->stackdepth--;
 122}
 123
 124/**
 125 * \brief BMESH OPSTACK INIT OP
 126 *
 127 * Initializes an operator structure to a certain type
 128 */
 129void BMO_op_init(BMesh *bm, BMOperator *op, const char *opname)
 130{
 131	int i, opcode = bmo_opname_to_opcode(opname);
 132
 133#ifdef DEBUG
 134	BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
 135#else
 136	(void)bm;
 137#endif
 138
 139	if (opcode == -1) {
 140		opcode = 0; /* error!, already printed, have a better way to handle this? */
 141	}
 142
 143	memset(op, 0, sizeof(BMOperator));
 144	op->type = opcode;
 145	op->flag = opdefines[opcode]->flag;
 146	
 147	/* initialize the operator slot types */
 148	for (i = 0; opdefines[opcode]->slottypes[i].type; i++) {
 149		op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
 150		op->slots[i].index = i;
 151	}
 152
 153	/* callback */
 154	op->exec = opdefines[opcode]->exec;
 155
 156	/* memarena, used for operator's slot buffers */
 157	op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
 158	BLI_memarena_use_calloc(op->arena);
 159}
 160
 161/**
 162 * \brief BMESH OPSTACK EXEC OP
 163 *
 164 * Executes a passed in operator.
 165 *
 166 * This handles the allocation and freeing of temporary flag
 167 * layers and starting/stopping the modeling loop.
 168 * Can be called from other operators exec callbacks as well.
 169 */
 170void BMO_op_exec(BMesh *bm, BMOperator *op)
 171{
 172	
 173	BMO_push(bm, op);
 174
 175	if (bm->stackdepth == 2)
 176		bmesh_edit_begin(bm, op->flag);
 177	op->exec(bm, op);
 178	
 179	if (bm->stackdepth == 2)
 180		bmesh_edit_end(bm, op->flag);
 181	
 182	BMO_pop(bm);
 183}
 184
 185/**
 186 * \brief BMESH OPSTACK FINISH OP
 187 *
 188 * Does housekeeping chores related to finishing up an operator.
 189 */
 190void BMO_op_finish(BMesh *bm, BMOperator *op)
 191{
 192	BMOpSlot *slot;
 193	int i;
 194
 195	for (i = 0; opdefines[op->type]->slottypes[i].type; i++) {
 196		slot = &op->slots[i];
 197		if (slot->slottype == BMO_OP_SLOT_MAPPING) {
 198			if (slot->data.ghash)
 199				BLI_ghash_free(slot->data.ghash, NULL, NULL);
 200		}
 201	}
 202
 203	BLI_memarena_free(op->arena);
 204
 205#ifdef DEBUG
 206	BM_ELEM_INDEX_VALIDATE(bm, "post bmo", opdefines[op->type]->name);
 207#else
 208	(void)bm;
 209#endif
 210}
 211
 212/**
 213 * \brief BMESH OPSTACK HAS SLOT
 214 *
 215 * \return Success if the slot if found.
 216 */
 217int BMO_slot_exists(BMOperator *op, const char *slotname)
 218{
 219	int slotcode = bmo_name_to_slotcode(opdefines[op->type], slotname);
 220	return (slotcode >= 0);
 221}
 222
 223/**
 224 * \brief BMESH OPSTACK GET SLOT
 225 *
 226 * Returns a pointer to the slot of type 'slotcode'
 227 */
 228BMOpSlot *BMO_slot_get(BMOperator *op, const char *slotname)
 229{
 230	int slotcode = bmo_name_to_slotcode_check(opdefines[op->type], slotname);
 231
 232	if (slotcode < 0) {
 233		return &BMOpEmptySlot;
 234	}
 235
 236	return &(op->slots[slotcode]);
 237}
 238
 239/**
 240 * \brief BMESH OPSTACK COPY SLOT
 241 *
 242 * Copies data from one slot to another.
 243 */
 244void BMO_slot_copy(BMOperator *source_op, BMOperator *dest_op, const char *src, const char *dst)
 245{
 246	BMOpSlot *source_slot = BMO_slot_get(source_op, src);
 247	BMOpSlot *dest_slot = BMO_slot_get(dest_op, dst);
 248
 249	if (source_slot == dest_slot)
 250		return;
 251
 252	if (source_slot->slottype != dest_slot->slottype) {
 253		/* possibly assert here? */
 254		return;
 255	}
 256
 257	if (dest_slot->slottype  == BMO_OP_SLOT_ELEMENT_BUF) {
 258		/* do buffer copy */
 259		dest_slot->data.buf = NULL;
 260		dest_slot->len = source_slot->len;
 261		if (dest_slot->len) {
 262			const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len;
 263			dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, slot_alloc_size);
 264			memcpy(dest_slot->data.buf, source_slot->data.buf, slot_alloc_size);
 265		}
 266	}
 267	else if (dest_slot->slottype  == BMO_OP_SLOT_MAPPING) {
 268		GHashIterator it;
 269		BMOElemMapping *srcmap, *dstmap;
 270
 271		/* sanity check */
 272		if (!source_slot->data.ghash) {
 273			return;
 274		}
 275
 276		if (!dest_slot->data.ghash) {
 277			dest_slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh operator 2");
 278		}
 279
 280		BLI_ghashIterator_init(&it, source_slot->data.ghash);
 281		for ( ; (srcmap = BLI_ghashIterator_getValue(&it));
 282			  BLI_ghashIterator_step(&it))
 283		{
 284			dstmap = BLI_memarena_alloc(dest_op->arena, sizeof(*dstmap) + srcmap->len);
 285
 286			dstmap->element = srcmap->element;
 287			dstmap->len = srcmap->len;
 288			memcpy(dstmap + 1, srcmap + 1, srcmap->len);
 289
 290			BLI_ghash_insert(dest_slot->data.ghash, dstmap->element, dstmap);
 291		}
 292	}
 293	else {
 294		dest_slot->data = source_slot->data;
 295	}
 296}
 297
 298/*
 299 * BMESH OPSTACK SET XXX
 300 *
 301 * Sets the value of a slot depending on it's type
 302 */
 303
 304void BMO_slot_float_set(BMOperator *op, const char *slotname, const float f)
 305{
 306	BMOpSlot *slot = BMO_slot_get(op, slotname);
 307	BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
 308	if (!(slot->slottype == BMO_OP_SLOT_FLT))
 309		return;
 310
 311	slot->data.f = f;
 312}
 313
 314void BMO_slot_int_set(BMOperator *op, const char *slotname, const int i)
 315{
 316	BMOpSlot *slot = BMO_slot_get(op, slotname);
 317	BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
 318	if (!(slot->slottype == BMO_OP_SLOT_INT))
 319		return;
 320
 321	slot->data.i = i;
 322}
 323
 324void BMO_slot_bool_set(BMOperator *op, const char *slotname, const int i)
 325{
 326	BMOpSlot *slot = BMO_slot_get(op, slotname);
 327	BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
 328	if (!(slot->slottype == BMO_OP_SLOT_BOOL))
 329		return;
 330
 331	slot->data.i = i;
 332}
 333
 334/* only supports square mats */
 335void BMO_slot_mat_set(BMOperator *op, const char *slotname, const float *mat, int size)
 336{
 337	BMOpSlot *slot = BMO_slot_get(op, slotname);
 338	BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
 339	if (!(slot->slottype == BMO_OP_SLOT_MAT))
 340		return;
 341
 342	slot->len = 4;
 343	slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float) * 4 * 4);
 344	
 345	if (size == 4) {
 346		memcpy(slot->data.p, mat, sizeof(float) * 4 * 4);
 347	}
 348	else if (size == 3) {
 349		copy_m4_m3(slot->data.p, (float (*)[3])mat);
 350	}
 351	else {
 352		fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
 353
 354		memset(slot->data.p, 0, sizeof(float) * 4 * 4);
 355	}
 356}
 357
 358void BMO_slot_mat4_get(BMOperator *op, const char *slotname, float r_mat[4][4])
 359{
 360	BMOpSlot *slot = BMO_slot_get(op, slotname);
 361	BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
 362	if (!(slot->slottype == BMO_OP_SLOT_MAT))
 363		return;
 364
 365	copy_m4_m4(r_mat, (float (*)[4])slot->data.p);
 366}
 367
 368void BMO_slot_mat3_set(BMOperator *op, const char *slotname, float r_mat[3][3])
 369{
 370	BMOpSlot *slot = BMO_slot_get(op, slotname);
 371	BLI_assert(slot->slottype == BMO_OP_SLOT_MAT);
 372	if (!(slot->slottype == BMO_OP_SLOT_MAT))
 373		return;
 374
 375	copy_m3_m4(r_mat, slot->data.p);
 376}
 377
 378void BMO_slot_ptr_set(BMOperator *op, const char *slotname, void *p)
 379{
 380	BMOpSlot *slot = BMO_slot_get(op, slotname);
 381	BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
 382	if (!(slot->slottype == BMO_OP_SLOT_PNT))
 383		return;
 384
 385	slot->data.p = p;
 386}
 387
 388void BMO_slot_vec_set(BMOperator *op, const char *slotname, const float vec[3])
 389{
 390	BMOpSlot *slot = BMO_slot_get(op, slotname);
 391	BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
 392	if (!(slot->slottype == BMO_OP_SLOT_VEC))
 393		return;
 394
 395	copy_v3_v3(slot->data.vec, vec);
 396}
 397
 398
 399float BMO_slot_float_get(BMOperator *op, const char *slotname)
 400{
 401	BMOpSlot *slot = BMO_slot_get(op, slotname);
 402	BLI_assert(slot->slottype == BMO_OP_SLOT_FLT);
 403	if (!(slot->slottype == BMO_OP_SLOT_FLT))
 404		return 0.0f;
 405
 406	return slot->data.f;
 407}
 408
 409int BMO_slot_int_get(BMOperator *op, const char *slotname)
 410{
 411	BMOpSlot *slot = BMO_slot_get(op, slotname);
 412	BLI_assert(slot->slottype == BMO_OP_SLOT_INT);
 413	if (!(slot->slottype == BMO_OP_SLOT_INT))
 414		return 0;
 415
 416	return slot->data.i;
 417}
 418
 419int BMO_slot_bool_get(BMOperator *op, const char *slotname)
 420{
 421	BMOpSlot *slot = BMO_slot_get(op, slotname);
 422	BLI_assert(slot->slottype == BMO_OP_SLOT_BOOL);
 423	if (!(slot->slottype == BMO_OP_SLOT_BOOL))
 424		return 0;
 425
 426	return slot->data.i;
 427}
 428
 429
 430void *BMO_slot_ptr_get(BMOperator *op, const char *slotname)
 431{
 432	BMOpSlot *slot = BMO_slot_get(op, slotname);
 433	BLI_assert(slot->slottype == BMO_OP_SLOT_PNT);
 434	if (!(slot->slottype == BMO_OP_SLOT_PNT))
 435		return NULL;
 436
 437	return slot->data.p;
 438}
 439
 440void BMO_slot_vec_get(BMOperator *op, const char *slotname, float r_vec[3])
 441{
 442	BMOpSlot *slot = BMO_slot_get(op, slotname);
 443	BLI_assert(slot->slottype == BMO_OP_SLOT_VEC);
 444	if (!(slot->slottype == BMO_OP_SLOT_VEC))
 445		return;
 446
 447	copy_v3_v3(r_vec, slot->data.vec);
 448}
 449
 450/*
 451 * BMO_COUNTFLAG
 452 *
 453 * Counts the number of elements of a certain type that have a
 454 * specific flag enabled (or disabled if test_for_enabled is false).
 455 *
 456 */
 457
 458static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
 459                               const short test_for_enabled)
 460{
 461	const char iter_types[3] = {BM_VERTS_OF_MESH,
 462	                            BM_EDGES_OF_MESH,
 463	                            BM_FACES_OF_MESH};
 464
 465	const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
 466
 467	BMIter iter;
 468	int count = 0;
 469	BMElemF *ele_f;
 470	int i;
 471
 472	BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
 473
 474	for (i = 0; i < 3; i++) {
 475		if (htype & flag_types[i]) {
 476			BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) {
 477				if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled)
 478					count++;
 479			}
 480		}
 481	}
 482
 483	return count;
 484}
 485
 486
 487int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
 488{
 489	return bmo_mesh_flag_count(bm, htype, oflag, TRUE);
 490}
 491
 492int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
 493{
 494	return bmo_mesh_flag_count(bm, htype, oflag, FALSE);
 495}
 496
 497void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag)
 498{
 499	const char iter_types[3] = {BM_VERTS_OF_MESH,
 500	                            BM_EDGES_OF_MESH,
 501	                            BM_FACES_OF_MESH};
 502
 503	const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
 504
 505	BMIter iter;
 506	BMElemF *ele;
 507	int i;
 508
 509	for (i = 0; i < 3; i++) {
 510		if (htype & flag_types[i]) {
 511			BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
 512				BMO_elem_flag_disable(bm, ele, oflag);
 513			}
 514		}
 515	}
 516}
 517
 518int BMO_slot_buffer_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
 519{
 520	BMOpSlot *slot = BMO_slot_get(op, slotname);
 521	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 522	
 523	/* check if its actually a buffer */
 524	if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
 525		return 0;
 526
 527	return slot->len;
 528}
 529
 530int BMO_slot_map_count(BMesh *UNUSED(bm), BMOperator *op, const char *slotname)
 531{
 532	BMOpSlot *slot = BMO_slot_get(op, slotname);
 533	BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
 534	
 535	/* check if its actually a buffer */
 536	if (!(slot->slottype == BMO_OP_SLOT_MAPPING))
 537		return 0;
 538
 539	return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0;
 540}
 541
 542/* inserts a key/value mapping into a mapping slot.  note that it copies the
 543 * value, it doesn't store a reference to it. */
 544
 545void BMO_slot_map_insert(BMesh *UNUSED(bm), BMOperator *op, const char *slotname,
 546                         void *element, void *data, int len)
 547{
 548	BMOElemMapping *mapping;
 549	BMOpSlot *slot = BMO_slot_get(op, slotname);
 550	BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
 551
 552	mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
 553
 554	mapping->element = (BMHeader *) element;
 555	mapping->len = len;
 556	memcpy(mapping + 1, data, len);
 557
 558	if (!slot->data.ghash) {
 559		slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh slot map hash");
 560	}
 561
 562	BLI_ghash_insert(slot->data.ghash, element, mapping);
 563}
 564
 565#if 0
 566void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slotcode, int totadd)
 567{
 568	BMOpSlot *slot = &op->slots[slotcode];
 569	void *tmp;
 570	ssize_t allocsize;
 571	
 572	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 573
 574	/* check if its actually a buffer */
 575	if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
 576		return NULL;
 577
 578	if (slot->flag & BMOS_DYNAMIC_ARRAY) {
 579		if (slot->len >= slot->size) {
 580			slot->size = (slot->size + 1 + totadd) * 2;
 581
 582			allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size;
 583
 584			tmp = slot->data.buf;
 585			slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
 586			memcpy(slot->data.buf, tmp, allocsize);
 587			MEM_freeN(tmp);
 588		}
 589
 590		slot->len += totadd;
 591	}
 592	else {
 593		slot->flag |= BMOS_DYNAMIC_ARRAY;
 594		slot->len += totadd;
 595		slot->size = slot->len + 2;
 596
 597		allocsize = BMO_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len;
 598
 599		tmp = slot->data.buf;
 600		slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
 601		memcpy(slot->data.buf, tmp, allocsize);
 602	}
 603
 604	return slot->data.buf;
 605}
 606#endif
 607
 608void BMO_slot_map_to_flag(BMesh *bm, BMOperator *op, const char *slotname,
 609                          const char htype, const short oflag)
 610{
 611	GHashIterator it;
 612	BMOpSlot *slot = BMO_slot_get(op, slotname);
 613	BMElemF *ele_f;
 614
 615	BLI_assert(slot->slottype == BMO_OP_SLOT_MAPPING);
 616
 617	/* sanity check */
 618	if (!slot->data.ghash) return;
 619
 620	BLI_ghashIterator_init(&it, slot->data.ghash);
 621	for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) {
 622		if (ele_f->head.htype & htype) {
 623			BMO_elem_flag_enable(bm, ele_f, oflag);
 624		}
 625	}
 626}
 627
 628static void *bmo_slot_buffer_alloc(BMOperator *op, const char *slotname, int len)
 629{
 630	BMOpSlot *slot = BMO_slot_get(op, slotname);
 631	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 632
 633	/* check if its actually a buffer */
 634	if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
 635		return NULL;
 636	
 637	slot->len = len;
 638	if (len)
 639		slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slottype] * len);
 640	return slot->data.buf;
 641}
 642
 643/**
 644 * \brief BMO_ALL_TO_SLOT
 645 *
 646 * Copies all elements of a certain type into an operator slot.
 647 */
 648static void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, const char *slotname, const char htype)
 649{
 650	BMOpSlot *output = BMO_slot_get(op, slotname);
 651	int totelement = 0, i = 0;
 652	
 653	if (htype & BM_VERT) totelement += bm->totvert;
 654	if (htype & BM_EDGE) totelement += bm->totedge;
 655	if (htype & BM_FACE) totelement += bm->totface;
 656
 657	if (totelement) {
 658		BMIter iter;
 659		BMHeader *ele;
 660
 661		bmo_slot_buffer_alloc(op, slotname, totelement);
 662
 663		/* TODO - collapse these loops into one */
 664
 665		if (htype & BM_VERT) {
 666			BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
 667				((BMHeader **)output->data.p)[i] = ele;
 668				i++;
 669			}
 670		}
 671
 672		if (htype & BM_EDGE) {
 673			BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
 674				((BMHeader **)output->data.p)[i] = ele;
 675				i++;
 676			}
 677		}
 678
 679		if (htype & BM_FACE) {
 680			BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
 681				((BMHeader **)output->data.p)[i] = ele;
 682				i++;
 683			}
 684		}
 685	}
 686}
 687
 688/**
 689 * \brief BMO_HEADERFLAG_TO_SLOT
 690 *
 691 * Copies elements of a certain type, which have a certain header flag
 692 * enabled/disabled into a slot for an operator.
 693 */
 694static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, const char *slotname,
 695                                       const char htype, const char hflag,
 696                                       const short test_for_enabled)
 697{
 698	BMOpSlot *output = BMO_slot_get(op, slotname);
 699	int totelement = 0, i = 0;
 700
 701	BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
 702
 703	if (test_for_enabled)
 704		totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, TRUE);
 705	else
 706		totelement = BM_mesh_elem_hflag_count_disabled(bm, htype, hflag, TRUE);
 707
 708	if (totelement) {
 709		BMIter iter;
 710		BMElem *ele;
 711
 712		bmo_slot_buffer_alloc(op, slotname, totelement);
 713
 714		/* TODO - collapse these loops into one */
 715
 716		if (htype & BM_VERT) {
 717			BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
 718				if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
 719				    BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
 720				{
 721					((BMElem **)output->data.p)[i] = ele;
 722					i++;
 723				}
 724			}
 725		}
 726
 727		if (htype & BM_EDGE) {
 728			BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
 729				if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
 730				    BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
 731				{
 732					((BMElem **)output->data.p)[i] = ele;
 733					i++;
 734				}
 735			}
 736		}
 737
 738		if (htype & BM_FACE) {
 739			BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
 740				if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN) &&
 741				    BM_elem_flag_test_bool(ele, hflag) == test_for_enabled)
 742				{
 743					((BMElem **)output->data.p)[i] = ele;
 744					i++;
 745				}
 746			}
 747		}
 748	}
 749	else {
 750		output->len = 0;
 751	}
 752}
 753
 754void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
 755                                        const char htype, const char hflag)
 756{
 757	bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, TRUE);
 758}
 759
 760void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op, const char *slotname,
 761                                         const char htype, const char hflag)
 762{
 763	bmo_slot_buffer_from_hflag(bm, op, slotname, htype, hflag, FALSE);
 764}
 765
 766/**
 767 * Copies the values from another slot to the end of the output slot.
 768 */
 769void BMO_slot_buffer_append(BMOperator *output_op, const char *output_slot_name,
 770                            BMOperator *other_op, const char *other_slot_name)
 771{
 772	BMOpSlot *output_slot = BMO_slot_get(output_op, output_slot_name);
 773	BMOpSlot *other_slot = BMO_slot_get(other_op, other_slot_name);
 774
 775	BLI_assert(output_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF &&
 776	           other_slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 777
 778	if (output_slot->len == 0) {
 779		/* output slot is empty, copy rather than append */
 780		BMO_slot_copy(other_op, output_op, other_slot_name, output_slot_name);
 781	}
 782	else if (other_slot->len != 0) {
 783		int elem_size = BMO_OPSLOT_TYPEINFO[output_slot->slottype];
 784		int alloc_size = elem_size * (output_slot->len + other_slot->len);
 785		/* allocate new buffer */
 786		void *buf = BLI_memarena_alloc(output_op->arena, alloc_size);
 787
 788		/* copy slot data */
 789		memcpy(buf, output_slot->data.buf, elem_size * output_slot->len);
 790		memcpy(((char *)buf) + elem_size * output_slot->len, other_slot->data.buf, elem_size * other_slot->len);
 791
 792		output_slot->data.buf = buf;
 793		output_slot->len += other_slot->len;
 794	}
 795}
 796
 797/**
 798 * \brief BMO_FLAG_TO_SLOT
 799 *
 800 * Copies elements of a certain type, which have a certain flag set
 801 * into an output slot for an operator.
 802 */
 803static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op, const char *slotname,
 804                                      const char htype, const short oflag,
 805                                      const short test_for_enabled)
 806{
 807	BMOpSlot *slot = BMO_slot_get(op, slotname);
 808	int totelement, i = 0;
 809
 810	BLI_assert(ELEM(TRUE, FALSE, test_for_enabled));
 811
 812	if (test_for_enabled)
 813		totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
 814	else
 815		totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
 816
 817	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 818
 819	if (totelement) {
 820		BMIter iter;
 821		BMHeader *ele;
 822		BMHeader **ele_array;
 823
 824		bmo_slot_buffer_alloc(op, slotname, totelement);
 825
 826		ele_array = (BMHeader **)slot->data.p;
 827
 828		/* TODO - collapse these loops into one */
 829
 830		if (htype & BM_VERT) {
 831			BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
 832				if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
 833					ele_array[i] = ele;
 834					i++;
 835				}
 836			}
 837		}
 838
 839		if (htype & BM_EDGE) {
 840			BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
 841				if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
 842					ele_array[i] = ele;
 843					i++;
 844				}
 845			}
 846		}
 847
 848		if (htype & BM_FACE) {
 849			BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
 850				if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) {
 851					ele_array[i] = ele;
 852					i++;
 853				}
 854			}
 855		}
 856	}
 857	else {
 858		slot->len = 0;
 859	}
 860}
 861
 862void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
 863                                       const char htype, const short oflag)
 864{
 865	bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, TRUE);
 866}
 867
 868void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op, const char *slotname,
 869                                        const char htype, const short oflag)
 870{
 871	bmo_slot_buffer_from_flag(bm, op, slotname, htype, oflag, FALSE);
 872}
 873
 874/**
 875 * \brief BMO_FLAG_BUFFER
 876 *
 877 * Header Flags elements in a slots buffer, automatically
 878 * using the selection API where appropriate.
 879 */
 880void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOperator *op, const char *slotname,
 881                                  const char htype, const char hflag, const char do_flush)
 882{
 883	BMOpSlot *slot = BMO_slot_get(op, slotname);
 884	BMElem **data =  slot->data.p;
 885	int i;
 886	const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
 887	const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
 888
 889	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 890
 891	for (i = 0; i < slot->len; i++, data++) {
 892		if (!(htype & (*data)->head.htype))
 893			continue;
 894
 895		if (do_flush_select) {
 896			BM_elem_select_set(bm, *data, TRUE);
 897		}
 898
 899		if (do_flush_hide) {
 900			BM_elem_hide_set(bm, *data, FALSE);
 901		}
 902
 903		BM_elem_flag_enable(*data, hflag);
 904	}
 905}
 906
 907/**
 908 * \brief BMO_FLAG_BUFFER
 909 *
 910 * Removes flags from elements in a slots buffer, automatically
 911 * using the selection API where appropriate.
 912 */
 913void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOperator *op, const char *slotname,
 914                                   const char htype, const char hflag, const char do_flush)
 915{
 916	BMOpSlot *slot = BMO_slot_get(op, slotname);
 917	BMElem **data =  slot->data.p;
 918	int i;
 919	const char do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
 920	const char do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
 921
 922	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 923
 924	for (i = 0; i < slot->len; i++, data++) {
 925		if (!(htype & (*data)->head.htype))
 926			continue;
 927
 928		if (do_flush_select) {
 929			BM_elem_select_set(bm, *data, FALSE);
 930		}
 931
 932		if (do_flush_hide) {
 933			BM_elem_hide_set(bm, *data, FALSE);
 934		}
 935
 936		BM_elem_flag_disable(*data, hflag);
 937	}
 938}
 939
 940int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag)
 941{
 942	int count = 0;
 943
 944	if (v->e) {
 945		BMEdge *curedge;
 946		const int len = bmesh_disk_count(v);
 947		int i;
 948		
 949		for (i = 0, curedge = v->e; i < len; i++) {
 950			if (BMO_elem_flag_test(bm, curedge, oflag))
 951				count++;
 952			curedge = bmesh_disk_edge_next(curedge, v);
 953		}
 954	}
 955
 956	return count;
 957}
 958
 959/**
 960 * \brief BMO_FLAG_BUFFER
 961 *
 962 * Flags elements in a slots buffer
 963 */
 964void BMO_slot_buffer_flag_enable(BMesh *bm, BMOperator *op, const char *slotname,
 965                                 const char htype, const short oflag)
 966{
 967	BMOpSlot *slot = BMO_slot_get(op, slotname);
 968	BMHeader **data =  slot->data.p;
 969	int i;
 970
 971	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 972
 973	for (i = 0; i < slot->len; i++) {
 974		if (!(htype & data[i]->htype))
 975			continue;
 976
 977		BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
 978	}
 979}
 980
 981/**
 982 * \brief BMO_FLAG_BUFFER
 983 *
 984 * Removes flags from elements in a slots buffer
 985 */
 986void BMO_slot_buffer_flag_disable(BMesh *bm, BMOperator *op, const char *slotname,
 987                                  const char htype, const short oflag)
 988{
 989	BMOpSlot *slot = BMO_slot_get(op, slotname);
 990	BMHeader **data =  slot->data.p;
 991	int i;
 992
 993	BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
 994
 995	for (i = 0; i < slot->len; i++) {
 996		if (!(htype & data[i]->htype))
 997			continue;
 998
 999		BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1000	}
1001}
1002
1003
1004/**
1005 * \brief ALLOC/FREE FLAG LAYER
1006 *
1007 * Used by operator stack to free/allocate
1008 * private flag data. This is allocated
1009 * using a mempool so the allocation/frees
1010 * should be quite fast.
1011 *
1012 * BMESH_TODO:
1013 * Investigate not freeing flag layers until
1014 * all operators have been executed. This would
1015 * save a lot of realloc potentially.
1016 */
1017static void bmo_flag_layer_alloc(BMesh *bm)
1018{
1019	BMElemF *ele;
1020	/* set the index values since we are looping over all data anyway,
1021	 * may save time later on */
1022	int i;
1023
1024	BMIter iter;
1025	BLI_mempool *oldpool = bm->toolflagpool; 		/* old flag pool */
1026	BLI_mempool *newpool;
1027	void *oldflags;
1028
1029	/* store memcpy size for reuse */
1030	const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1031	
1032	bm->totflags++;
1033
1034	/* allocate new flag poo */
1035	bm->toolflagpool = newpool = BLI_mempool_create(sizeof(BMFlagLayer) * bm->totflags, 512, 512, 0);
1036	
1037	/* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1038	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1039		oldflags = ele->oflags;
1040		ele->oflags = BLI_mempool_calloc(newpool);
1041		memcpy(ele->oflags, oldflags, old_totflags_size);
1042		BM_elem_index_set(ele, i); /* set_inline */
1043	}
1044	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1045		oldflags = ele->oflags;
1046		ele->oflags = BLI_mempool_calloc(newpool);
1047		memcpy(ele->oflags, oldflags, old_totflags_size);
1048		BM_elem_index_set(ele, i); /* set_inline */
1049	}
1050	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1051		oldflags = ele->oflags;
1052		ele->oflags = BLI_mempool_calloc(newpool);
1053		memcpy(ele->oflags, oldflags, old_totflags_size);
1054		BM_elem_index_set(ele, i); /* set_inline */
1055	}
1056
1057	bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1058
1059	BLI_mempool_destroy(oldpool);
1060}
1061
1062static void bmo_flag_layer_free(BMesh *bm)
1063{
1064	BMElemF *ele;
1065	/* set the index values since we are looping over all data anyway,
1066	 * may save time later on */
1067	int i;
1068
1069	BMIter iter;
1070	BLI_mempool *oldpool = bm->toolflagpool;
1071	BLI_mempool *newpool;
1072	void *oldflags;
1073	
1074	/* store memcpy size for reuse */
1075	const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1076
1077	/* de-increment the totflags first.. */
1078	bm->totflags--;
1079	/* allocate new flag poo */
1080	bm->toolflagpool = newpool = BLI_mempool_create(new_totflags_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
1081	
1082	/* now go through and memcpy all the flag */
1083	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1084		oldflags = ele->oflags;
1085		ele->oflags = BLI_mempool_calloc(newpool);
1086		memcpy(ele->oflags, oldflags, new_totflags_size);
1087		BM_elem_index_set(ele, i); /* set_inline */
1088	}
1089	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1090		oldflags = ele->oflags;
1091		ele->oflags = BLI_mempool_calloc(newpool);
1092		memcpy(ele->oflags, oldflags, new_totflags_size);
1093		BM_elem_index_set(ele, i); /* set_inline */
1094	}
1095	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1096		oldflags = ele->oflags;
1097		ele->oflags = BLI_mempool_calloc(newpool);
1098		memcpy(ele->oflags, oldflags, new_totflags_size);
1099		BM_elem_index_set(ele, i); /* set_inline */
1100	}
1101
1102	bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1103
1104	BLI_mempool_destroy(oldpool);
1105}
1106
1107static void bmo_flag_layer_clear(BMesh *bm)
1108{
1109	BMElemF *ele;
1110	/* set the index values since we are looping over all data anyway,
1111	 * may save time later on */
1112	int i;
1113
1114	BMIter iter;
1115	const int totflags_offset = bm->totflags - 1;
1116
1117	/* now go through and memcpy all the flag */
1118	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1119		memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1120		BM_elem_index_set(ele, i); /* set_inline */
1121	}
1122	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1123		memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1124		BM_elem_index_set(ele, i); /* set_inline */
1125	}
1126	BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1127		memset(ele->oflags + totflags_offset, 0, sizeof(BMFlagLayer));
1128		BM_elem_index_set(ele, i); /* set_inline */
1129	}
1130
1131	bm->elem_index_dirty &= ~(BM_VERT|BM_EDGE|BM_FACE);
1132}
1133
1134void *BMO_slot_buffer_elem_first(BMOperator *op, const char *slotname)
1135{
1136	BMOpSlot *slot = BMO_slot_get(op, slotname);
1137	
1138	if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF)
1139		return NULL;
1140
1141	return slot->data.buf ? *(void **)slot->data.buf : NULL;
1142}
1143
1144/**
1145 * \brief New Iterator
1146 *
1147 * \param restrictmask restricts the iteration to certain element types
1148 * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1149 * over an element buffer (not a mapping). */
1150void *BMO_iter_new(BMOIter *iter, BMesh *UNUSED(bm), BMOperator *op,
1151                   const char *slotname, const char restrictmask)
1152{
1153	BMOpSlot *slot = BMO_slot_get(op, slotname);
1154
1155	memset(iter, 0, sizeof(BMOIter));
1156
1157	iter->slot = slot;
1158	iter->cur = 0;
1159	iter->restrictmask = restrictmask;
1160
1161	if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1162		if (iter->slot->data.ghash) {
1163			BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1164		}
1165		else {
1166			return NULL;
1167		}
1168	}
1169
1170	return BMO_iter_step(iter);
1171}
1172
1173void *BMO_iter_step(BMOIter *iter)
1174{
1175	if (iter->slot->slottype == BMO_OP_SLOT_ELEMENT_BUF) {
1176		BMHeader *h;
1177
1178		if (iter->cur >= iter->slot->len) {
1179			return NULL;
1180		}
1181
1182		h = ((void **)iter->slot->data.buf)[iter->cur++];
1183		while (!(iter->restrictmask & h->htype)) {
1184			if (iter->cur >= iter->slot->len) {
1185				return NULL;
1186			}
1187
1188			h = ((void **)iter->slot->data.buf)[iter->cur++];
1189		}
1190
1191		return h;
1192	}
1193	else if (iter->slot->slottype == BMO_OP_SLOT_MAPPING) {
1194		BMOElemMapping *map;
1195		void *ret = BLI_ghashIterator_getKey(&iter->giter);
1196		map = BLI_ghashIterator_getValue(&iter->giter);
1197		
1198		iter->val = map + 1;
1199
1200		BLI_ghashIterator_step(&iter->giter);
1201
1202		return ret;
1203	}
1204
1205	return NULL;
1206}
1207
1208/* used for iterating over mapping */
1209void *BMO_iter_map_value(BMOIter *iter)
1210{
1211	return iter->val;
1212}
1213
1214void *BMO_iter_map_value_p(BMOIter *iter)
1215{
1216	return *((void **)iter->val);
1217}
1218
1219float BMO_iter_map_value_f(BMOIter *iter)
1220{
1221	return *((float *)iter->val);
1222}
1223
1224/* error syste */
1225typedef struct BMOpError {
1226	struct BMOpError *next, *prev;
1227	int errorcode;
1228	BMOperator *op;
1229	const char *msg;
1230} BMOpError;
1231
1232void BMO_error_clear(BMesh *bm)
1233{
1234	while (BMO_error_pop(bm, NULL, NULL));
1235}
1236
1237void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1238{
1239	BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1240	
1241	err->errorcode = errcode;
1242	if (!msg) msg = bmo_error_messages[errcode];
1243	err->msg = msg;
1244	err->op = owner;
1245	
1246	BLI_addhead(&bm->errorstack, err);
1247}
1248
1249int BMO_error_occurred(BMesh *bm)
1250{
1251	return bm->errorstack.first != NULL;
1252}
1253
1254/* returns error code or 0 if no erro */
1255int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1256{
1257	BMOpError *err = bm->errorstack.first;
1258	if (!err) {
1259		return 0;
1260	}
1261
1262	if (msg) *msg = err->msg;
1263	if (op) *op = err->op;
1264	
1265	return err->errorcode;
1266}
1267
1268int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1269{
1270	int errorcode = BMO_error_get(bm, msg, op);
1271	
1272	if (errorcode) {
1273		BMOpError *err = bm->errorstack.first;
1274		
1275		BLI_remlink(&bm->errorstack, bm->errorstack.first);
1276		MEM_freeN(err);
1277	}
1278
1279	return errorcode;
1280}
1281
1282
1283#define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1284
1285static int bmo_name_to_slotcode(BMOpDefine *def, const char *name)
1286{
1287	int i;
1288
1289	for (i = 0; def->slottypes[i].type; i++) {
1290		if (!strncmp(name, def->slottypes[i].name, MAX_SLOTNAME)) {
1291			return i;
1292		}
1293	}
1294
1295	return -1;
1296}
1297
1298static int bmo_name_to_slotcode_check(BMOpDefine *def, const char *name)
1299{
1300	int i = bmo_name_to_slotcode(def, name);
1301	if (i < 0) {
1302		fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, name);
1303	}
1304
1305	return i;
1306}
1307
1308static int bmo_opname_to_opcode(const char *opname)
1309{
1310	int i;
1311
1312	for (i = 0; i < bmesh_total_ops; i++) {
1313		if (!strcmp(opname, opdefines[i]->name)) {
1314			return i;
1315		}
1316	}
1317
1318	fprintf(stderr, "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname);
1319	return -1;
1320}
1321
1322/* Example:
1323 * BMO_op_callf(bm, "del %i %hv", DEL_ONLYFACES, BM_ELEM_SELECT);
1324 *
1325 *  i - int
1326 *  b - boolean (same as int but 1/0 only)
1327 *  f - float
1328 *  hv - header flagged verts (hflag)
1329 *  he - header flagged edges (hflag)
1330 *  hf - header flagged faces (hflag)
1331 *  fv - flagged verts (oflag)
1332 *  fe - flagged edges (oflag)
1333 *  ff - flagged faces (oflag)
1334 */
1335
1336int BMO_op_vinitf(BMesh *bm, BMOperator *op, const char *_fmt, va_list vlist)
1337{
1338	BMOpDefine *def;
1339	char *opname, *ofmt, *fmt;
1340	char slotname[64] = {0};
1341	int i /*, n = strlen(fmt) */, stop /*, slotcode = -1 */, type, state;
1342	char htype;
1343	int noslot = 0;
1344
1345
1346	/* basic useful info to help find where bmop formatting strings fail */
1347	const char *err_reason = "Unknown";
1348	int lineno = -1;
1349
1350#define GOTO_ERROR(reason)   \
1351	{                        \
1352		err_reason = reason; \
1353		lineno = __LINE__;   \
1354		goto error;          \
1355	} (void)0
1356
1357	/* we muck around in here, so dup i */
1358	fmt = ofmt = BLI_strdup(_fmt);
1359	
1360	/* find operator name */
1361	i = strcspn(fmt, " ");
1362
1363	opname = fmt;
1364	if (!opname[i]) noslot = 1;
1365	opname[i] = '\0';
1366
1367	fmt += i + (noslot ? 0 : 1);
1368	
1369	i = bmo_opname_to_opcode(opname);
1370
1371	if (i == -1) {
1372		MEM_freeN(ofmt);
1373		return FALSE;
1374	}
1375
1376	BMO_op_init(bm, op, opname);
1377	def = opdefines[i];
1378	
1379	i = 0;
1380	state = 1; /* 0: not inside slotcode name, 1: inside slotcode name */
1381
1382	while (*fmt) {
1383		if (state) {
1384			/* jump past leading whitespac */
1385			i = strspn(fmt, " ");
1386			fmt += i;
1387			
1388			/* ignore trailing whitespac */
1389			if (!fmt[i])
1390				break;
1391
1392			/* find end of slot name, only "slot=%f", can be used */
1393			i = strcspn(fmt, "=");
1394			if (!fmt[i]) {
1395				GOTO_ERROR("could not match end of slot name");
1396			}
1397
1398			fmt[i] = 0;
1399
1400			if (bmo_name_to_slotcode_check(def, fmt) < 0) {
1401				GOTO_ERROR("name to slot code check failed");
1402			}
1403			
1404			BLI_strncpy(slotname, fmt, sizeof(slotname));
1405			
1406			state = 0;
1407			fmt += i;
1408		}
1409		else {
1410			switch (*fmt) {
1411				case ' ':
1412				case '=':
1413				case '%':
1414					break;
1415				case 'm': {
1416					int size, c;
1417
1418					c = NEXT_CHAR(fmt);
1419					fmt++;
1420
1421					if      (c == '3') size = 3;
1422					else if (c == '4') size = 4;
1423					else GOTO_ERROR("matrix size was not 3 or 4");
1424
1425					BMO_slot_mat_set(op, slotname, va_arg(vlist, void *), size);
1426					state = 1;
1427					break;
1428				}
1429				case 'v': {
1430					BMO_slot_vec_set(op, slotname, va_arg(vlist, float *));
1431					state = 1;
1432					break;
1433				}
1434				case 'e': {
1435					BMHeader *ele = va_arg(vlist, void *);
1436					BMOpSlot *slot = BMO_slot_get(op, slotname);
1437
1438					slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4);
1439					slot->len = 1;
1440					*((void **)slot->data.buf) = ele;
1441
1442					state = 1;
1443					break;
1444				}
1445				case 's': {
1446					BMOperator *op2 = va_arg(vlist, void *);
1447					const char *slotname2 = va_arg(vlist, char *);
1448
1449					BMO_slot_copy(op2, op, slotname2, slotname);
1450					state = 1;
1451					break;
1452				}
1453				case 'i':
1454					BMO_slot_int_set(op, slotname, va_arg(vlist, int));
1455					state = 1;
1456					break;
1457				case 'b':
1458					BMO_slot_bool_set(op, slotname, va_arg(vlist, int));
1459					state = 1;
1460					break;
1461				case 'p':
1462					BMO_slot_ptr_set(op, slotname, va_arg(vlist, void *));
1463					state = 1;
1464					break;
1465				case 'f':
1466				case 'F':
1467				case 'h':
1468				case 'H':
1469				case 'a':
1470					type = *fmt;
1471
1472					if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1473						BMO_slot_float_set(op, slotname, va_arg(vlist, double));
1474					}
1475					else {
1476						htype = 0;
1477						stop = 0;
1478						while (1) {
1479							switch (NEXT_CHAR(fmt)) {
1480								case 'f': htype |= BM_FACE; break;
1481								case 'e': htype |= BM_EDGE; break;
1482								case 'v': htype |= BM_VERT; break;
1483								default:
1484									stop = 1;
1485									break;
1486							}
1487							if (stop) {
1488								break;
1489							}
1490
1491							fmt++;
1492						}
1493
1494						if (type == 'h') {
1495							BMO_slot_buffer_from_enabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1496						}
1497						else if (type == 'H') {
1498							BMO_slot_buffer_from_disabled_hflag(bm, op, slotname, htype, va_arg(vlist, int));
1499						}
1500						else if (type == 'a') {
1501							BMO_slot_buffer_from_all(bm, op, slotname, htype);
1502						}
1503						else if (type == 'f') {
1504							BMO_slot_buffer_from_enabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1505						}
1506						else if (type == 'F') {
1507							BMO_slot_buffer_from_disabled_flag(bm, op, slotname, htype, va_arg(vlist, int));
1508						}
1509					}
1510
1511					state = 1;
1512					break;
1513				default:
1514					fprintf(stderr,
1515					        "%s: unrecognized bmop format char: %c, %d in '%s'\n",
1516					        __func__, *fmt, (int)(fmt - ofmt), ofmt);
1517					break;
1518			}
1519		}
1520		fmt++;
1521	}
1522
1523	MEM_freeN(ofmt);
1524	return TRUE;
1525error:
1526
1527	/* non urgent todo - explain exactly what is failing */
1528	fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1529
1530	fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1531	fprintf(stderr, "         ");
1532	{
1533		int pos = (int)(fmt - ofmt);
1534		int i;
1535		for (i = 0; i < pos; i++) {
1536			fprintf(stderr, " ");
1537		}
1538		fprintf(stderr, "^\n");
1539	}
1540
1541	fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1542
1543	fprintf(stderr, "reason: %s\n", err_reason);
1544
1545
1546	MEM_freeN(ofmt);
1547
1548	BMO_op_finish(bm, op);
1549	return FALSE;
1550
1551#undef GOTO_ERROR
1552
1553}
1554
1555
1556int BMO_op_initf(BMesh *bm, BMOperator *op, const char *fmt, ...)
1557{
1558	va_list list;
1559
1560	va_start(list, fmt);
1561	if (!BMO_op_vinitf(bm, op, fmt, list)) {
1562		printf("%s: failed\n", __func__);
1563		va_end(list);
1564		return FALSE;
1565	}
1566	va_end(list);
1567
1568	return TRUE;
1569}
1570
1571int BMO_op_callf(BMesh *bm, const char *fmt, ...)
1572{
1573	va_list list;
1574	BMOperator op;
1575
1576	va_start(list, fmt);
1577	if (!BMO_op_vinitf(bm, &op, fmt, list)) {
1578		printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
1579		va_end(list);
1580		return FALSE;
1581	}
1582
1583	BMO_op_exec(bm, &op);
1584	BMO_op_finish(bm, &op);
1585
1586	va_end(list);
1587	return TRUE;
1588}