PageRenderTime 67ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

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